summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
authorTofu Linden <tofu.linden@lindenlab.com>2010-08-24 19:22:00 +0100
committerTofu Linden <tofu.linden@lindenlab.com>2010-08-24 19:22:00 +0100
commite416840f85dc4a367894036b9fe483f17d959c54 (patch)
treee12956cbe7a0082bbaaa545cb80d9e86b13f88e8 /indra/llui
parent98cc2365034a93c69704daa69efb389799cc9627 (diff)
Backed out changeset c3d41f18ce2b
back-out the back-out for this branch. yay.
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llaccordionctrl.h2
-rw-r--r--indra/llui/llaccordionctrltab.cpp3
-rw-r--r--indra/llui/llaccordionctrltab.h2
-rw-r--r--indra/llui/llbutton.cpp12
-rw-r--r--indra/llui/llbutton.h1
-rw-r--r--indra/llui/llcallbackmap.h3
-rw-r--r--indra/llui/lldockablefloater.cpp17
-rw-r--r--indra/llui/lldockablefloater.h7
-rw-r--r--indra/llui/lldraghandle.cpp2
-rw-r--r--indra/llui/llflatlistview.cpp28
-rw-r--r--indra/llui/llflatlistview.h1
-rw-r--r--indra/llui/llfloater.cpp14
-rw-r--r--indra/llui/llfloater.h3
-rw-r--r--indra/llui/lllocalcliprect.cpp48
-rw-r--r--indra/llui/lllocalcliprect.h26
-rw-r--r--indra/llui/llmenugl.cpp6
-rw-r--r--indra/llui/llpanel.cpp66
-rw-r--r--indra/llui/llpanel.h4
-rw-r--r--indra/llui/llscrolllistctrl.cpp8
-rw-r--r--indra/llui/llscrolllistctrl.h4
-rw-r--r--indra/llui/llsliderctrl.cpp4
-rw-r--r--indra/llui/llstyle.cpp12
-rw-r--r--indra/llui/llstyle.h37
-rw-r--r--indra/llui/lltextbase.cpp121
-rw-r--r--indra/llui/lltextbase.h29
-rw-r--r--indra/llui/lltextbox.cpp11
-rw-r--r--indra/llui/lltextbox.h2
-rw-r--r--indra/llui/lltexteditor.cpp10
-rw-r--r--indra/llui/lltextvalidate.cpp18
-rw-r--r--indra/llui/lltextvalidate.h1
-rw-r--r--indra/llui/lltooltip.cpp2
-rw-r--r--indra/llui/llui.cpp400
-rw-r--r--indra/llui/llui.h2
-rw-r--r--indra/llui/lluictrl.cpp1
-rw-r--r--indra/llui/lluictrl.h4
-rw-r--r--indra/llui/llurlentry.cpp19
-rw-r--r--indra/llui/llurlentry.h5
-rw-r--r--indra/llui/llurlmatch.cpp6
-rw-r--r--indra/llui/llurlmatch.h6
-rw-r--r--indra/llui/llurlregistry.cpp6
-rw-r--r--indra/llui/llview.cpp62
-rw-r--r--indra/llui/llview.h7
42 files changed, 620 insertions, 402 deletions
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index e2de4b9d3b..1fe64c472e 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -133,7 +133,7 @@ public:
*/
const LLAccordionCtrlTab* getExpandedTab() const;
- const LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; }
+ LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; }
bool getFitParent() const {return mFitParent;}
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 4e0537f592..b7da5f4a1b 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -353,6 +353,7 @@ LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p)
,mPaddingBottom(p.padding_bottom)
,mCanOpenClose(true)
,mFitPanel(p.fit_panel)
+ ,mSelectionEnabled(p.selection_enabled)
,mContainerPanel(NULL)
,mScrollbar(NULL)
{
@@ -824,7 +825,7 @@ void LLAccordionCtrlTab::showAndFocusHeader()
{
LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
header->setFocus(true);
- header->setSelected(true);
+ header->setSelected(mSelectionEnabled);
LLRect screen_rc;
LLRect selected_rc = header->getRect();
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index 8ae91ad651..d6ac8cbc8f 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -236,6 +236,8 @@ private:
bool mStoredOpenCloseState;
bool mWasStateStored;
+ bool mSelectionEnabled;
+
LLScrollbar* mScrollbar;
LLView* mContainerPanel;
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index ac5651e4b6..f0f34ebd4f 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -114,6 +114,7 @@ LLButton::LLButton(const LLButton::Params& p)
mFlashing( FALSE ),
mCurGlowStrength(0.f),
mNeedsHighlight(FALSE),
+ mMouseOver(false),
mUnselectedLabel(p.label()),
mSelectedLabel(p.label_selected()),
mGLFont(p.font),
@@ -498,7 +499,11 @@ void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
LLUICtrl::onMouseEnter(x, y, mask);
if (isInEnabledChain())
+ {
mNeedsHighlight = TRUE;
+ }
+
+ mMouseOver = true;
}
void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
@@ -506,6 +511,7 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
LLUICtrl::onMouseLeave(x, y, mask);
mNeedsHighlight = FALSE;
+ mMouseOver = true;
}
void LLButton::setHighlight(bool b)
@@ -559,14 +565,10 @@ void LLButton::draw()
}
// Unselected image assignments
- S32 local_mouse_x;
- S32 local_mouse_y;
- LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
-
bool enabled = isInEnabledChain();
bool pressed = pressed_by_keyboard
- || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y))
+ || (hasMouseCapture() && mMouseOver)
|| mForcePressedState;
bool selected = getToggleState();
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 2d5fefa78c..d87ceb7c42 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -350,6 +350,7 @@ private:
BOOL mCommitOnReturn;
BOOL mFadeWhenDisabled;
bool mForcePressedState;
+ bool mMouseOver;
LLFrameTimer mFlashingTimer;
};
diff --git a/indra/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h
index eb8b423b29..0a10877c09 100644
--- a/indra/llui/llcallbackmap.h
+++ b/indra/llui/llcallbackmap.h
@@ -29,12 +29,13 @@
#include <map>
#include <string>
+#include <boost/function.hpp>
class LLCallbackMap
{
public:
// callback definition.
- typedef void* (*callback_t)(void* data);
+ typedef boost::function<void* (void* data)> callback_t;
typedef std::map<std::string, LLCallbackMap> map_t;
typedef map_t::iterator map_iter_t;
diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp
index bf55239f1b..ca2dc644a4 100644
--- a/indra/llui/lldockablefloater.cpp
+++ b/indra/llui/lldockablefloater.cpp
@@ -43,12 +43,13 @@ void LLDockableFloater::init(LLDockableFloater* thiz)
thiz->setCanClose(TRUE);
thiz->setCanDock(true);
thiz->setCanMinimize(TRUE);
+ thiz->setOverlapsScreenChannel(false);
+ thiz->mForceDocking = false;
}
LLDockableFloater::LLDockableFloater(LLDockControl* dockControl,
const LLSD& key, const Params& params) :
LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true)
- , mOverlapsScreenChannel(false)
{
init(this);
mUseTongue = true;
@@ -75,6 +76,12 @@ LLDockableFloater::~LLDockableFloater()
BOOL LLDockableFloater::postBuild()
{
+ // Remember we should force docking when the floater is opened for the first time
+ if (mIsDockedStateForcedCallback != NULL && mIsDockedStateForcedCallback())
+ {
+ mForceDocking = true;
+ }
+
mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png");
LLFloater::setDocked(true);
return LLView::postBuild();
@@ -128,6 +135,14 @@ void LLDockableFloater::resetInstance()
void LLDockableFloater::setVisible(BOOL visible)
{
+ // Force docking if requested
+ if (visible && mForceDocking)
+ {
+ setCanDock(true);
+ setDocked(true);
+ mForceDocking = false;
+ }
+
if(visible && isDocked())
{
resetInstance();
diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h
index 86dcf670b1..8deb6c1159 100644
--- a/indra/llui/lldockablefloater.h
+++ b/indra/llui/lldockablefloater.h
@@ -124,6 +124,10 @@ protected:
void setDockControl(LLDockControl* dockControl);
const LLUIImagePtr& getDockTongue();
+ // Checks if docking should be forced.
+ // It may be useful e.g. if floater created in mouselook mode (see EXT-5609)
+ boost::function<BOOL ()> mIsDockedStateForcedCallback;
+
private:
std::auto_ptr<LLDockControl> mDockControl;
LLUIImagePtr mDockTongue;
@@ -137,6 +141,9 @@ private:
bool mUseTongue;
bool mOverlapsScreenChannel;
+
+ // Force docking when the floater is being shown for the first time.
+ bool mForceDocking;
};
#endif /* LL_DOCKABLEFLOATER_H */
diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp
index 9ad7c01bd5..42e6c3c786 100644
--- a/indra/llui/lldraghandle.cpp
+++ b/indra/llui/lldraghandle.cpp
@@ -107,7 +107,7 @@ void LLDragHandleTop::setTitle(const std::string& title)
params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
params.font_shadow(LLFontGL::DROP_SHADOW_SOFT);
params.use_ellipses = true;
- params.allow_html = false; //cancel URL replacement in floater title
+ params.parse_urls = false; //cancel URL replacement in floater title
mTitleBox = LLUICtrlFactory::create<LLTextBox> (params);
addChild( mTitleBox );
}
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index b28399a36b..c57c02f4b1 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -607,8 +607,14 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
return;
}
- if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection();
+ //no need to do additional commit on selection reset
+ if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true);
+
+ //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it
+ if (mask & MASK_CONTROL)
selectItemPair(item_pair, select_item);
+ else
+ selectItemPair(item_pair, true);
}
void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask)
@@ -660,6 +666,14 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask)
}
break;
}
+ case KEY_ESCAPE:
+ {
+ if (mask == MASK_NONE)
+ {
+ setFocus(FALSE); // pass focus to the game area (EXT-8357)
+ }
+ break;
+ }
default:
break;
}
@@ -775,6 +789,18 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select)
return true;
}
+void LLFlatListView::scrollToShowFirstSelectedItem()
+{
+ if (!mSelectedItemPairs.size()) return;
+
+ LLRect selected_rc = mSelectedItemPairs.front()->first->getRect();
+
+ if (selected_rc.isValid())
+ {
+ scrollToShowRect(selected_rc);
+ }
+}
+
LLRect LLFlatListView::getLastSelectedItemRect()
{
if (!mSelectedItemPairs.size())
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index afd0176d98..0515853698 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -292,6 +292,7 @@ public:
bool updateValue(const LLSD& old_value, const LLSD& new_value);
+ void scrollToShowFirstSelectedItem();
void selectFirstItem ();
void selectLastItem ();
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 3cfb2c5d4a..e1203971ea 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2279,6 +2279,7 @@ void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
S32 floater_header_size = default_params.header_height;
static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
LLRect snap_rect_local = getLocalSnapRect();
+ snap_rect_local.mTop += mMinimizePositionVOffset;
for(S32 col = snap_rect_local.mLeft;
col < snap_rect_local.getWidth() - minimized_width;
col += minimized_width)
@@ -2376,6 +2377,19 @@ BOOL LLFloaterView::allChildrenClosed()
return true;
}
+void LLFloaterView::shiftFloaters(S32 x_offset, S32 y_offset)
+{
+ for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
+ {
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
+
+ if (floaterp && floaterp->isMinimized())
+ {
+ floaterp->translate(x_offset, y_offset);
+ }
+ }
+}
+
void LLFloaterView::refresh()
{
// Constrain children to be entirely on the screen
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 2deae29607..5e482cbac3 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -449,6 +449,7 @@ public:
// Given a child of gFloaterView, make sure this view can fit entirely onscreen.
void adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside);
+ void setMinimizePositionVerticalOffset(S32 offset) { mMinimizePositionVOffset = offset; }
void getMinimizePosition( S32 *left, S32 *bottom);
void restoreAll(); // un-minimize all floaters
typedef std::set<LLView*> skip_list_t;
@@ -465,6 +466,7 @@ public:
// attempt to close all floaters
void closeAllChildren(bool app_quitting);
BOOL allChildrenClosed();
+ void shiftFloaters(S32 x_offset, S32 y_offset);
LLFloater* getFrontmost() const;
LLFloater* getBackmost() const;
@@ -484,6 +486,7 @@ private:
BOOL mFocusCycleMode;
S32 mSnapOffsetBottom;
S32 mSnapOffsetRight;
+ S32 mMinimizePositionVOffset;
};
//
diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp
index 1a311bb13a..6841301219 100644
--- a/indra/llui/lllocalcliprect.cpp
+++ b/indra/llui/lllocalcliprect.cpp
@@ -27,33 +27,8 @@
#include "lllocalcliprect.h"
#include "llfontgl.h"
-#include "llgl.h"
#include "llui.h"
-#include <stack>
-
-//---------------------------------------------------------------------------
-// LLScreenClipRect
-// implementation class in screen space
-//---------------------------------------------------------------------------
-class LLScreenClipRect
-{
-public:
- LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE);
- virtual ~LLScreenClipRect();
-
-private:
- static void pushClipRect(const LLRect& rect);
- static void popClipRect();
- static void updateScissorRegion();
-
-private:
- LLGLState mScissorState;
- BOOL mEnabled;
-
- static std::stack<LLRect> sClipRectStack;
-};
-
/*static*/ std::stack<LLRect> LLScreenClipRect::sClipRectStack;
@@ -64,9 +39,9 @@ LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled)
if (mEnabled)
{
pushClipRect(rect);
+ mScissorState.setEnabled(!sClipRectStack.empty());
+ updateScissorRegion();
}
- mScissorState.setEnabled(!sClipRectStack.empty());
- updateScissorRegion();
}
LLScreenClipRect::~LLScreenClipRect()
@@ -74,8 +49,8 @@ LLScreenClipRect::~LLScreenClipRect()
if (mEnabled)
{
popClipRect();
+ updateScissorRegion();
}
- updateScissorRegion();
}
//static
@@ -125,16 +100,11 @@ void LLScreenClipRect::updateScissorRegion()
// LLLocalClipRect
//---------------------------------------------------------------------------
LLLocalClipRect::LLLocalClipRect(const LLRect& rect, BOOL enabled /* = TRUE */)
-{
- LLRect screen(rect.mLeft + LLFontGL::sCurOrigin.mX,
- rect.mTop + LLFontGL::sCurOrigin.mY,
- rect.mRight + LLFontGL::sCurOrigin.mX,
- rect.mBottom + LLFontGL::sCurOrigin.mY);
- mScreenClipRect = new LLScreenClipRect(screen, enabled);
-}
+: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX,
+ rect.mTop + LLFontGL::sCurOrigin.mY,
+ rect.mRight + LLFontGL::sCurOrigin.mX,
+ rect.mBottom + LLFontGL::sCurOrigin.mY), enabled)
+{}
LLLocalClipRect::~LLLocalClipRect()
-{
- delete mScreenClipRect;
- mScreenClipRect = NULL;
-}
+{}
diff --git a/indra/llui/lllocalcliprect.h b/indra/llui/lllocalcliprect.h
index 0097958916..eeeaf2adb6 100644
--- a/indra/llui/lllocalcliprect.h
+++ b/indra/llui/lllocalcliprect.h
@@ -25,7 +25,9 @@
#ifndef LLLOCALCLIPRECT_H
#define LLLOCALCLIPRECT_H
+#include "llgl.h"
#include "llrect.h" // can't forward declare, it's templated
+#include <stack>
// Clip rendering to a specific rectangle using GL scissor
// Just create one of these on the stack:
@@ -33,15 +35,29 @@
// LLLocalClipRect(rect);
// draw();
// }
-class LLLocalClipRect
+class LLScreenClipRect
{
public:
- LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
- ~LLLocalClipRect();
+ LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE);
+ virtual ~LLScreenClipRect();
+
+private:
+ static void pushClipRect(const LLRect& rect);
+ static void popClipRect();
+ static void updateScissorRegion();
private:
- // implementation class
- class LLScreenClipRect* mScreenClipRect;
+ LLGLState mScissorState;
+ BOOL mEnabled;
+
+ static std::stack<LLRect> sClipRectStack;
+};
+
+class LLLocalClipRect : public LLScreenClipRect
+{
+public:
+ LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
+ ~LLLocalClipRect();
};
#endif
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index c533610381..3e652ea960 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -52,6 +52,7 @@
#include "llbutton.h"
#include "llfontgl.h"
#include "llresmgr.h"
+#include "lltrans.h"
#include "llui.h"
#include "llstl.h"
@@ -2266,8 +2267,9 @@ void LLMenuGL::createSpilloverBranch()
// technically, you can't tear off spillover menus, but we're passing the handle
// along just to be safe
LLMenuGL::Params p;
+ std::string label = LLTrans::getString("More");
p.name("More");
- p.label("More"); // *TODO: Translate
+ p.label(label);
p.bg_color(mBackgroundColor);
p.bg_visible(true);
p.can_tear_off(false);
@@ -2276,7 +2278,7 @@ void LLMenuGL::createSpilloverBranch()
LLMenuItemBranchGL::Params branch_params;
branch_params.name = "More";
- branch_params.label = "More"; // *TODO: Translate
+ branch_params.label = label;
branch_params.branch = mSpilloverMenu;
branch_params.font.style = "italic";
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 6fe36bbc0c..b2e08c48c5 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -655,7 +655,7 @@ void LLPanel::childSetEnabled(const std::string& id, bool enabled)
void LLPanel::childSetTentative(const std::string& id, bool tentative)
{
- LLView* child = findChild<LLView>(id);
+ LLUICtrl* child = findChild<LLUICtrl>(id);
if (child)
{
child->setTentative(tentative);
@@ -854,13 +854,16 @@ LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const
return NULL;
}
-static LLPanel *childGetVisibleTabWithHelp(LLView *parent)
+LLPanel* LLPanel::childGetVisibleTabWithHelp()
{
LLView *child;
- // look through immediate children first for an active tab with help
- for (child = parent->getFirstChild(); child; child = parent->findNextSibling(child))
+ bfs_tree_iterator_t it = beginTreeBFS();
+ // skip ourselves
+ ++it;
+ for (; it != endTreeBFS(); ++it)
{
+ child = *it;
LLPanel *curTabPanel = NULL;
// do we have a tab container?
@@ -884,36 +887,21 @@ static LLPanel *childGetVisibleTabWithHelp(LLView *parent)
}
}
- // then try a bit harder and recurse through all children
- for (child = parent->getFirstChild(); child; child = parent->findNextSibling(child))
- {
- if (child->getVisible())
- {
- LLPanel* tab = ::childGetVisibleTabWithHelp(child);
- if (tab)
- {
- return tab;
- }
- }
- }
-
// couldn't find any active tabs with a help topic string
return NULL;
}
-LLPanel *LLPanel::childGetVisibleTabWithHelp()
-{
- // find a visible tab with a help topic (to determine help context)
- return ::childGetVisibleTabWithHelp(this);
-}
-static LLPanel *childGetVisiblePanelWithHelp(LLView *parent)
+LLPanel *LLPanel::childGetVisiblePanelWithHelp()
{
LLView *child;
- // look through immediate children first for an active panel with help
- for (child = parent->getFirstChild(); child; child = parent->findNextSibling(child))
+ bfs_tree_iterator_t it = beginTreeBFS();
+ // skip ourselves
+ ++it;
+ for (; it != endTreeBFS(); ++it)
{
+ child = *it;
// do we have a panel with a help topic?
LLPanel *panel = dynamic_cast<LLPanel *>(child);
if (panel && panel->getVisible() && !panel->getHelpTopic().empty())
@@ -922,39 +910,19 @@ static LLPanel *childGetVisiblePanelWithHelp(LLView *parent)
}
}
- // then try a bit harder and recurse through all children
- for (child = parent->getFirstChild(); child; child = parent->findNextSibling(child))
- {
- if (child->getVisible())
- {
- LLPanel* panel = ::childGetVisiblePanelWithHelp(child);
- if (panel)
- {
- return panel;
- }
- }
- }
-
// couldn't find any active panels with a help topic string
return NULL;
}
-LLPanel *LLPanel::childGetVisiblePanelWithHelp()
+void LLPanel::childSetAction(const std::string& id, const commit_signal_t::slot_type& function)
{
- // find a visible tab with a help topic (to determine help context)
- return ::childGetVisiblePanelWithHelp(this);
-}
-
-void LLPanel::childSetPrevalidate(const std::string& id, bool (*func)(const LLWString &) )
-{
- LLLineEditor* child = findChild<LLLineEditor>(id);
- if (child)
+ LLButton* button = findChild<LLButton>(id);
+ if (button)
{
- child->setPrevalidate(func);
+ button->setClickedCallback(function);
}
}
-
void LLPanel::childSetAction(const std::string& id, boost::function<void(void*)> function, void* value)
{
LLButton* button = findChild<LLButton>(id);
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index ca8bb77b77..a7224648c1 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -164,6 +164,7 @@ public:
std::string getString(const std::string& name) const;
// ** Wrappers for setting child properties by name ** -TomY
+ // WARNING: These are deprecated, please use getChild<T>("name")->doStuff() idiom instead
// LLView
void childSetVisible(const std::string& name, bool visible);
@@ -227,7 +228,8 @@ public:
void childSetPrevalidate(const std::string& id, bool (*func)(const LLWString &) );
// LLButton
- void childSetAction(const std::string& id, boost::function<void(void*)> function, void* value = NULL);
+ void childSetAction(const std::string& id, boost::function<void(void*)> function, void* value);
+ void childSetAction(const std::string& id, const commit_signal_t::slot_type& function);
// LLTextBox
void childSetActionTextbox(const std::string& id, boost::function<void(void*)> function, void* value = NULL);
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 3f4ab0fbc8..84e438cfb7 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -129,6 +129,7 @@ LLScrollListCtrl::Params::Params()
search_column("search_column", 0),
sort_column("sort_column", -1),
sort_ascending("sort_ascending", true),
+ mouse_wheel_opaque("mouse_wheel_opaque", false),
commit_on_keyboard_movement("commit_on_keyboard_movement", true),
heading_height("heading_height"),
page_lines("page_lines", 0),
@@ -157,6 +158,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
: LLUICtrl(p),
mLineHeight(0),
mScrollLines(0),
+ mMouseWheelOpaque(p.mouse_wheel_opaque),
mPageLines(p.page_lines),
mMaxSelectable(0),
mAllowKeyboardMovement(TRUE),
@@ -1530,6 +1532,12 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
BOOL handled = FALSE;
// Pretend the mouse is over the scrollbar
handled = mScrollbar->handleScrollWheel( 0, 0, clicks );
+
+ if (mMouseWheelOpaque)
+ {
+ return TRUE;
+ }
+
return handled;
}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 30618866af..8a2f893ba2 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -96,7 +96,8 @@ public:
{
// behavioral flags
Optional<bool> multi_select,
- commit_on_keyboard_movement;
+ commit_on_keyboard_movement,
+ mouse_wheel_opaque;
// display flags
Optional<bool> has_border,
@@ -443,6 +444,7 @@ private:
BOOL mCommitOnSelectionChange;
BOOL mSelectionChanged;
BOOL mNeedsScroll;
+ BOOL mMouseWheelOpaque;
BOOL mCanSelect;
const BOOL mDisplayColumnHeaders;
BOOL mColumnsDirty;
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 904c458e85..d760178e35 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -229,6 +229,10 @@ void LLSliderCtrl::updateText()
std::string text = llformat(format.c_str(), displayed_value);
if( mEditor )
{
+ // Setting editor text here to "" before using actual text is here because if text which
+ // is set is the same as the one which is actually typed into lineeditor, LLLineEditor::setText()
+ // will exit at it's beginning, so text for revert on escape won't be saved. (EXT-8536)
+ mEditor->setText( LLStringUtil::null );
mEditor->setText( text );
}
else
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index 93314d7bc0..5e09cee78b 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -36,6 +36,8 @@ LLStyle::Params::Params()
: visible("visible", true),
drop_shadow("drop_shadow", LLFontGL::NO_SHADOW),
color("color", LLColor4::black),
+ readonly_color("readonly_color", LLColor4::black),
+ selected_color("selected_color", LLColor4::black),
font("font", LLFontGL::getFontMonospace()),
image("image"),
link_href("href")
@@ -43,12 +45,10 @@ LLStyle::Params::Params()
LLStyle::LLStyle(const LLStyle::Params& p)
-: mItalic(FALSE),
- mBold(FALSE),
- mUnderline(FALSE),
- mVisible(p.visible),
- mColor(p.color()),
- mReadOnlyColor(p.readonly_color()),
+: mVisible(p.visible),
+ mColor(p.color),
+ mReadOnlyColor(p.readonly_color),
+ mSelectedColor(p.selected_color),
mFont(p.font()),
mLink(p.link_href),
mDropShadow(p.drop_shadow),
diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h
index bfd0d72e85..66cd639936 100644
--- a/indra/llui/llstyle.h
+++ b/indra/llui/llstyle.h
@@ -41,7 +41,8 @@ public:
Optional<bool> visible;
Optional<LLFontGL::ShadowType> drop_shadow;
Optional<LLUIColor> color,
- readonly_color;
+ readonly_color,
+ selected_color;
Optional<const LLFontGL*> font;
Optional<LLUIImage*> image;
Optional<std::string> link_href;
@@ -49,11 +50,14 @@ public:
};
LLStyle(const Params& p = Params());
public:
- const LLColor4& getColor() const { return mColor; }
- void setColor(const LLColor4 &color) { mColor = color; }
+ const LLUIColor& getColor() const { return mColor; }
+ void setColor(const LLUIColor &color) { mColor = color; }
- const LLColor4& getReadOnlyColor() const { return mReadOnlyColor; }
- void setReadOnlyColor(const LLColor4& color) { mReadOnlyColor = color; }
+ const LLUIColor& getReadOnlyColor() const { return mReadOnlyColor; }
+ void setReadOnlyColor(const LLUIColor& color) { mReadOnlyColor = color; }
+
+ const LLUIColor& getSelectedColor() const { return mSelectedColor; }
+ void setSelectedColor(const LLUIColor& color) { mSelectedColor = color; }
BOOL isVisible() const;
void setVisible(BOOL is_visible);
@@ -73,41 +77,36 @@ public:
BOOL isImage() const { return mImagep.notNull(); }
- // inlined here to make it easier to compare to member data below. -MG
bool operator==(const LLStyle &rhs) const
{
return
mVisible == rhs.mVisible
&& mColor == rhs.mColor
&& mReadOnlyColor == rhs.mReadOnlyColor
+ && mSelectedColor == rhs.mSelectedColor
&& mFont == rhs.mFont
&& mLink == rhs.mLink
&& mImagep == rhs.mImagep
- && mItalic == rhs.mItalic
- && mBold == rhs.mBold
- && mUnderline == rhs.mUnderline
&& mDropShadow == rhs.mDropShadow;
}
bool operator!=(const LLStyle& rhs) const { return !(*this == rhs); }
public:
- BOOL mItalic;
- BOOL mBold;
- BOOL mUnderline;
LLFontGL::ShadowType mDropShadow;
protected:
~LLStyle() { }
private:
- BOOL mVisible;
- LLUIColor mColor;
- LLUIColor mReadOnlyColor;
- std::string mFontName;
- const LLFontGL* mFont; // cached for performance
- std::string mLink;
- LLUIImagePtr mImagep;
+ BOOL mVisible;
+ LLUIColor mColor;
+ LLUIColor mReadOnlyColor;
+ LLUIColor mSelectedColor;
+ std::string mFontName;
+ const LLFontGL* mFont;
+ std::string mLink;
+ LLUIImagePtr mImagep;
};
typedef LLPointer<LLStyle> LLStyleSP;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 60c313b6ce..8d91aa2284 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -149,6 +149,8 @@ LLTextBase::Params::Params()
bg_readonly_color("bg_readonly_color"),
bg_writeable_color("bg_writeable_color"),
bg_focus_color("bg_focus_color"),
+ text_selected_color("text_selected_color"),
+ bg_selected_color("bg_selected_color"),
allow_scroll("allow_scroll", true),
plain_text("plain_text",false),
track_end("track_end", false),
@@ -161,11 +163,12 @@ LLTextBase::Params::Params()
font_shadow("font_shadow"),
wrap("wrap"),
use_ellipses("use_ellipses", false),
- allow_html("allow_html", false),
+ parse_urls("parse_urls", false),
parse_highlights("parse_highlights", false)
{
addSynonym(track_end, "track_bottom");
addSynonym(wrap, "word_wrap");
+ addSynonym(parse_urls, "allow_html");
}
@@ -184,6 +187,8 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mWriteableBgColor(p.bg_writeable_color),
mReadOnlyBgColor(p.bg_readonly_color),
mFocusBgColor(p.bg_focus_color),
+ mTextSelectedColor(p.text_selected_color),
+ mSelectedBGColor(p.bg_selected_color),
mReflowIndex(S32_MAX),
mCursorPos( 0 ),
mScrollNeeded(FALSE),
@@ -203,7 +208,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mPlainText ( p.plain_text ),
mWordWrap(p.wrap),
mUseEllipses( p.use_ellipses ),
- mParseHTML(p.allow_html),
+ mParseHTML(p.parse_urls),
mParseHighlights(p.parse_highlights),
mBGVisible(p.bg_visible),
mScroller(NULL),
@@ -263,9 +268,6 @@ void LLTextBase::initFromParams(const LLTextBase::Params& p)
{
mReadOnly = p.read_only;
}
-
- // HACK: text editors always need to be enabled so that we can scroll
- LLView::setEnabled(true);
}
bool LLTextBase::truncate()
@@ -295,11 +297,14 @@ bool LLTextBase::truncate()
const LLStyle::Params& LLTextBase::getDefaultStyleParams()
{
+ //FIXME: convert mDefaultStyle to a flyweight http://www.boost.org/doc/libs/1_40_0/libs/flyweight/doc/index.html
+ //and eliminate color member values
if (mStyleDirty)
{
mDefaultStyle
- .color(LLUIColor(&mFgColor))
+ .color(LLUIColor(&mFgColor)) // pass linked color instead of copy of mFGColor
.readonly_color(LLUIColor(&mReadOnlyFgColor))
+ .selected_color(LLUIColor(&mTextSelectedColor))
.font(mDefaultFont)
.drop_shadow(mFontShadow);
mStyleDirty = false;
@@ -397,7 +402,7 @@ void LLTextBase::drawSelectionBackground()
// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- const LLColor4& color = mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get();
+ const LLColor4& color = mSelectedBGColor;
F32 alpha = hasFocus() ? 0.7f : 0.3f;
alpha *= getDrawContext().mAlpha;
LLColor4 selection_color(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], alpha);
@@ -437,7 +442,6 @@ void LLTextBase::drawCursor()
}
else
{
- //segmentp = mSegments.back();
return;
}
@@ -471,21 +475,8 @@ void LLTextBase::drawCursor()
{
LLColor4 text_color;
const LLFontGL* fontp;
- if (segmentp)
- {
text_color = segmentp->getColor();
fontp = segmentp->getStyle()->getFont();
- }
- else if (mReadOnly)
- {
- text_color = mReadOnlyFgColor.get();
- fontp = mDefaultFont;
- }
- else
- {
- text_color = mFgColor.get();
- fontp = mDefaultFont;
- }
fontp->render(text, mCursorPos, cursor_rect,
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
LLFontGL::LEFT, mVAlign,
@@ -1015,21 +1006,26 @@ void LLTextBase::draw()
if (mBGVisible)
{
// clip background rect against extents, if we support scrolling
- LLLocalClipRect clip(doc_rect, mScroller != NULL);
-
+ LLRect bg_rect = mVisibleTextRect;
+ if (mScroller)
+ {
+ bg_rect.intersectWith(doc_rect);
+ }
LLColor4 bg_color = mReadOnly
? mReadOnlyBgColor.get()
: hasFocus()
? mFocusBgColor.get()
: mWriteableBgColor.get();
- gl_rect_2d(mVisibleTextRect, bg_color, TRUE);
+ gl_rect_2d(doc_rect, bg_color, TRUE);
}
// draw document view
LLUICtrl::draw();
{
- // only clip if we support scrolling (mScroller != NULL)
+ // only clip if we support scrolling...
+ // since convention is that text boxes never vertically truncate their contents
+ // regardless of rect bounds
LLLocalClipRect clip(doc_rect, mScroller != NULL);
drawSelectionBackground();
drawText();
@@ -1493,23 +1489,32 @@ void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg
LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
{
+ static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();
+
if (index > getLength()) { return mSegments.end(); }
// when there are no segments, we return the end iterator, which must be checked by caller
if (mSegments.size() <= 1) { return mSegments.begin(); }
- segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index));
+ //FIXME: avoid operator new somehow (without running into refcount problems)
+ index_segment->setStart(index);
+ index_segment->setEnd(index);
+ segment_set_t::iterator it = mSegments.upper_bound(index_segment);
return it;
}
LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 index) const
{
+ static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();
+
if (index > getLength()) { return mSegments.end(); }
// when there are no segments, we return the end iterator, which must be checked by caller
if (mSegments.size() <= 1) { return mSegments.begin(); }
- LLTextBase::segment_set_t::const_iterator it = mSegments.upper_bound(new LLIndexSegment(index));
+ index_segment->setStart(index);
+ index_segment->setEnd(index);
+ LLTextBase::segment_set_t::const_iterator it = mSegments.upper_bound(index_segment);
return it;
}
@@ -1645,7 +1650,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
}
else
{
- appendAndHighlightText(match.getLabel(), part, link_params);
+ appendAndHighlightText(match.getLabel(), part, link_params, match.underlineOnHoverOnly());
// set the tooltip for the Url label
if (! match.getTooltip().empty())
@@ -1728,7 +1733,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)
+void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only)
{
// Save old state
S32 selection_start = mSelectionStart;
@@ -1759,7 +1764,17 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
S32 cur_length = getLength();
LLStyleConstSP sp(new LLStyle(highlight_params));
- LLTextSegmentPtr segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this);
+ LLTextSegmentPtr segmentp;
+ if(underline_on_hover_only)
+ {
+ highlight_params.font.style("NORMAL");
+ LLStyleConstSP normal_sp(new LLStyle(highlight_params));
+ segmentp = new LLOnHoverChangeableTextSegment(sp, normal_sp, cur_length, cur_length + wide_text.size(), *this);
+ }
+ else
+ {
+ segmentp = new LLNormalTextSegment(sp, cur_length, cur_length + wide_text.size(), *this);
+ }
segment_vec_t segments;
segments.push_back(segmentp);
insertStringNoUndo(cur_length, wide_text, &segments);
@@ -1774,7 +1789,17 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
S32 segment_start = old_length;
S32 segment_end = old_length + wide_text.size();
LLStyleConstSP sp(new LLStyle(style_params));
+ if (underline_on_hover_only)
+ {
+ LLStyle::Params normal_style_params(style_params);
+ normal_style_params.font.style("NORMAL");
+ LLStyleConstSP normal_sp(new LLStyle(normal_style_params));
+ segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this ));
+ }
+ else
+ {
segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this ));
+ }
insertStringNoUndo(getLength(), wide_text, &segments);
}
@@ -1798,7 +1823,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)
+void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only)
{
if (new_text.empty()) return;
@@ -1810,7 +1835,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);
+ appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only);
}
appendLineBreakSegment(style_params);
start = pos+1;
@@ -1818,7 +1843,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);
+ appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only);
}
@@ -2272,6 +2297,7 @@ void LLTextBase::updateRects()
// allow horizontal scrolling?
// if so, use entire width of text contents
// otherwise, stop at width of mVisibleTextRect
+ //FIXME: consider use of getWordWrap() instead
doc_rect.mRight = mScroller
? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight)
: mVisibleTextRect.getWidth();
@@ -2481,7 +2507,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
font->render(text, start,
rect,
- LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ),
+ mStyle->getSelectedColor().get(),
LLFontGL::LEFT, mEditor.mVAlign,
LLFontGL::NORMAL,
LLFontGL::NO_SHADOW,
@@ -2678,6 +2704,33 @@ void LLNormalTextSegment::dump() const
llendl;
}
+//
+// LLOnHoverChangeableTextSegment
+//
+
+LLOnHoverChangeableTextSegment::LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor ):
+ LLNormalTextSegment(normal_style, start, end, editor),
+ mHoveredStyle(style),
+ mNormalStyle(normal_style){}
+
+/*virtual*/
+F32 LLOnHoverChangeableTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
+{
+ F32 result = LLNormalTextSegment::draw(start, end, selection_start, selection_end, draw_rect);
+ if (end == mEnd - mStart)
+ {
+ mStyle = mNormalStyle;
+ }
+ return result;
+}
+
+/*virtual*/
+BOOL LLOnHoverChangeableTextSegment::handleHover(S32 x, S32 y, MASK mask)
+{
+ mStyle = mHoveredStyle;
+ return LLNormalTextSegment::handleHover(x, y, mask);
+}
+
//
// LLInlineViewSegment
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 86ab8f357d..e5dfecad54 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -139,10 +139,25 @@ protected:
boost::signals2::connection mImageLoadedConnection;
};
+// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)
+class LLOnHoverChangeableTextSegment : public LLNormalTextSegment
+{
+public:
+ LLOnHoverChangeableTextSegment( LLStyleConstSP style, LLStyleConstSP normal_style, S32 start, S32 end, LLTextBase& editor );
+ /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+ /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
+protected:
+ // Style used for text when mouse pointer is over segment
+ LLStyleConstSP mHoveredStyle;
+ // Style used for text when mouse pointer is outside segment
+ LLStyleConstSP mNormalStyle;
+
+};
+
class LLIndexSegment : public LLTextSegment
{
public:
- LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {}
+ LLIndexSegment() : LLTextSegment(0, 0) {}
};
class LLInlineViewSegment : public LLTextSegment
@@ -235,7 +250,9 @@ public:
text_readonly_color,
bg_readonly_color,
bg_writeable_color,
- bg_focus_color;
+ bg_focus_color,
+ text_selected_color,
+ bg_selected_color;
Optional<bool> bg_visible,
border_visible,
@@ -245,7 +262,7 @@ public:
plain_text,
wrap,
use_ellipses,
- allow_html,
+ parse_urls,
parse_highlights,
clip_partial;
@@ -435,7 +452,7 @@ protected:
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);
+ void appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& stylep, bool underline_on_hover_only = false);
// manage segments
@@ -478,7 +495,7 @@ protected:
void replaceUrlLabel(const std::string &url, const std::string &label);
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);
+ void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false);
protected:
@@ -501,6 +518,8 @@ protected:
LLUIColor mWriteableBgColor;
LLUIColor mReadOnlyBgColor;
LLUIColor mFocusBgColor;
+ LLUIColor mTextSelectedColor;
+ LLUIColor mSelectedBGColor;
// cursor
S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 3e2422c88b..6a905b7ec0 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -113,6 +113,17 @@ BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
return handled;
}
+void LLTextBox::setEnabled(BOOL enabled)
+{
+ // just treat enabled as read-only flag
+ bool read_only = !enabled;
+ if (read_only != mReadOnly)
+ {
+ LLTextBase::setReadOnly(read_only);
+ updateSegments();
+ }
+}
+
void LLTextBox::setText(const LLStringExplicit& text , const LLStyle::Params& input_params )
{
// does string argument insertion
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index 4634dd0ff2..071e18c638 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -52,6 +52,8 @@ public:
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
+ /*virtual*/ void setEnabled(BOOL enabled);
+
/*virtual*/ void setText( const LLStringExplicit& text, const LLStyle::Params& input_params = LLStyle::Params() );
void setRightAlign() { mHAlign = LLFontGL::RIGHT; }
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index e09df60704..94bf716e7d 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -283,6 +283,9 @@ void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
{
LLTextBase::initFromParams(p);
+ // HACK: text editors always need to be enabled so that we can scroll
+ LLView::setEnabled(true);
+
if (p.commit_on_focus_lost.isProvided())
{
mCommitOnFocusLost = p.commit_on_focus_lost;
@@ -452,8 +455,13 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const
const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const
{
+ static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment;
+
+ index_segment->setStart(mCursorPos);
+ index_segment->setEnd(mCursorPos);
+
// find segment index at character to left of cursor (or rightmost edge of selection)
- segment_set_t::const_iterator it = mSegments.lower_bound(new LLIndexSegment(mCursorPos));
+ segment_set_t::const_iterator it = mSegments.lower_bound(index_segment);
if (it != mSegments.end())
{
diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp
index d7260369ec..4b9faa0560 100644
--- a/indra/llui/lltextvalidate.cpp
+++ b/indra/llui/lltextvalidate.cpp
@@ -44,6 +44,7 @@ namespace LLTextValidate
declare("alpha_num_space", validateAlphaNumSpace);
declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe);
declare("ascii_printable_no_space", validateASCIIPrintableNoSpace);
+ declare("ascii_with_newline", validateASCIIWithNewLine);
}
// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
@@ -293,4 +294,21 @@ namespace LLTextValidate
}
return rv;
}
+
+ // Used for multiline text stored on the server.
+ // Example is landmark description in Places SP.
+ bool validateASCIIWithNewLine(const LLWString &str)
+ {
+ bool rv = TRUE;
+ S32 len = str.length();
+ while(len--)
+ {
+ if (str[len] < 0x20 && str[len] != 0xA || str[len] > 0x7f)
+ {
+ rv = FALSE;
+ break;
+ }
+ }
+ return rv;
+ }
}
diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h
index 1b61eca051..84644be30c 100644
--- a/indra/llui/lltextvalidate.h
+++ b/indra/llui/lltextvalidate.h
@@ -51,6 +51,7 @@ namespace LLTextValidate
bool validateASCIIPrintableNoPipe(const LLWString &str);
bool validateASCIIPrintableNoSpace(const LLWString &str);
bool validateASCII(const LLWString &str);
+ bool validateASCIIWithNewLine(const LLWString &str);
}
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index 8ab4a119e5..b02d3122fe 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -180,7 +180,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
params.font = p.font;
params.use_ellipses = true;
params.wrap = p.wrap;
- params.allow_html = false; // disallow hyperlinks in tooltips, as they want to spawn their own explanatory tooltips
+ params.parse_urls = false; // disallow hyperlinks in tooltips, as they want to spawn their own explanatory tooltips
mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
addChild(mTextBox);
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 03223b45f7..d33d8e3178 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -460,7 +460,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
}
-void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect, const LLRectf& scale_rect)
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect)
{
stop_glerror();
@@ -470,36 +470,53 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
return;
}
+ // add in offset of current image to current ui translation
+ const LLVector3 ui_scale = gGL.getUIScale();
+ const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale);
+
+ F32 uv_width = uv_outer_rect.getWidth();
+ F32 uv_height = uv_outer_rect.getHeight();
+
// shrink scaling region to be proportional to clipped image region
- LLRectf scale_rect_uv(
- uv_rect.mLeft + (scale_rect.mLeft * uv_rect.getWidth()),
- uv_rect.mBottom + (scale_rect.mTop * uv_rect.getHeight()),
- uv_rect.mLeft + (scale_rect.mRight * uv_rect.getWidth()),
- uv_rect.mBottom + (scale_rect.mBottom * uv_rect.getHeight()));
-
- S32 image_natural_width = llround((F32)image->getWidth(0) * uv_rect.getWidth());
- S32 image_natural_height = llround((F32)image->getHeight(0) * uv_rect.getHeight());
-
- LLRect draw_rect(0, height, width, 0);
- LLRect draw_scale_rect(llround(scale_rect_uv.mLeft * (F32)image->getWidth(0)),
- llround(scale_rect_uv.mTop * (F32)image->getHeight(0)),
- llround(scale_rect_uv.mRight * (F32)image->getWidth(0)),
- llround(scale_rect_uv.mBottom * (F32)image->getHeight(0)));
- // scale fixed region of image to drawn region
- draw_scale_rect.mRight += width - image_natural_width;
- draw_scale_rect.mTop += height - image_natural_height;
-
- S32 border_shrink_width = llmax(0, draw_scale_rect.mLeft - draw_scale_rect.mRight);
- S32 border_shrink_height = llmax(0, draw_scale_rect.mBottom - draw_scale_rect.mTop);
-
- F32 shrink_width_ratio = scale_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - scale_rect.getWidth()));
- F32 shrink_height_ratio = scale_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - scale_rect.getHeight()));
-
- F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
- draw_scale_rect.mLeft = llround((F32)draw_scale_rect.mLeft * shrink_scale);
- draw_scale_rect.mTop = llround(lerp((F32)height, (F32)draw_scale_rect.mTop, shrink_scale));
- draw_scale_rect.mRight = llround(lerp((F32)width, (F32)draw_scale_rect.mRight, shrink_scale));
- draw_scale_rect.mBottom = llround((F32)draw_scale_rect.mBottom * shrink_scale);
+ LLRectf uv_center_rect(
+ uv_outer_rect.mLeft + (center_rect.mLeft * uv_width),
+ uv_outer_rect.mBottom + (center_rect.mTop * uv_height),
+ uv_outer_rect.mLeft + (center_rect.mRight * uv_width),
+ uv_outer_rect.mBottom + (center_rect.mBottom * uv_height));
+
+ F32 image_width = image->getWidth(0);
+ F32 image_height = image->getHeight(0);
+
+ S32 image_natural_width = llround(image_width * uv_width);
+ S32 image_natural_height = llround(image_height * uv_height);
+
+ LLRectf draw_center_rect( uv_center_rect.mLeft * image_width,
+ uv_center_rect.mTop * image_height,
+ uv_center_rect.mRight * image_width,
+ uv_center_rect.mBottom * image_height);
+
+ { // scale fixed region of image to drawn region
+ draw_center_rect.mRight += width - image_natural_width;
+ draw_center_rect.mTop += height - image_natural_height;
+
+ F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight);
+ F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop);
+
+ F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth()));
+ F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight()));
+
+ F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
+
+ draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]);
+ draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]);
+ draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]);
+ draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]);
+ }
+
+ LLRectf draw_outer_rect(ui_translation.mV[VX],
+ ui_translation.mV[VY] + height * ui_scale.mV[VY],
+ ui_translation.mV[VX] + width * ui_scale.mV[VX],
+ ui_translation.mV[VY]);
LLGLSUIDefault gls_ui;
@@ -509,136 +526,174 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
}
- gGL.pushUIMatrix();
- {
- gGL.translateUI((F32)x, (F32)y, 0.f);
+ gGL.getTexUnit(0)->bind(image);
- gGL.getTexUnit(0)->bind(image);
+ gGL.color4fv(color.mV);
+
+ const S32 NUM_VERTICES = 9 * 4; // 9 quads
+ LLVector2 uv[NUM_VERTICES];
+ LLVector3 pos[NUM_VERTICES];
- gGL.color4fv(color.mV);
-
- gGL.begin(LLRender::QUADS);
- {
- // draw bottom left
- gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
- gGL.vertex2i(0, 0);
+ S32 index = 0;
- gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mBottom);
- gGL.vertex2i(draw_scale_rect.mLeft, 0);
+ gGL.begin(LLRender::QUADS);
+ {
+ // draw bottom left
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mBottom);
- gGL.vertex2i(0, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
- // draw bottom middle
- gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mBottom);
- gGL.vertex2i(draw_scale_rect.mLeft, 0);
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mBottom);
- gGL.vertex2i(draw_scale_rect.mRight, 0);
+ // draw bottom middle
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
- // draw bottom right
- gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mBottom);
- gGL.vertex2i(draw_scale_rect.mRight, 0);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
- gGL.vertex2i(width, 0);
+ // draw bottom right
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mBottom);
- gGL.vertex2i(width, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
- // draw left
- gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mBottom);
- gGL.vertex2i(0, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+ // draw left
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mTop);
- gGL.vertex2i(0, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
- // draw middle
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+ // draw middle
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
- // draw right
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mBottom);
- gGL.vertex2i(width, draw_scale_rect.mBottom);
+ // draw right
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mTop);
- gGL.vertex2i(width, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
- // draw top left
- gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mTop);
- gGL.vertex2i(0, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+ // draw top left
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mTop);
- gGL.vertex2i(draw_scale_rect.mLeft, height);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
- gGL.vertex2i(0, height);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ index++;
- // draw top middle
- gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+ // draw top middle
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mTop);
- gGL.vertex2i(draw_scale_rect.mRight, height);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mTop);
- gGL.vertex2i(draw_scale_rect.mLeft, height);
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ index++;
- // draw top right
- gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
- gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+ uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mTop);
- gGL.vertex2i(width, draw_scale_rect.mTop);
+ // draw top right
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
- gGL.vertex2i(width, height);
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+ index++;
- gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mTop);
- gGL.vertex2i(draw_scale_rect.mRight, height);
- }
- gGL.end();
+ uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
+ pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+ index++;
+
+ gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
}
- gGL.popUIMatrix();
+ gGL.end();
if (solid_color)
{
@@ -668,25 +723,40 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
if (degrees == 0.f)
{
- gGL.pushUIMatrix();
- gGL.translateUI((F32)x, (F32)y, 0.f);
-
+ const S32 NUM_VERTICES = 4; // 9 quads
+ LLVector2 uv[NUM_VERTICES];
+ LLVector3 pos[NUM_VERTICES];
+
gGL.begin(LLRender::QUADS);
{
- gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
- gGL.vertex2i(width, height );
-
- gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
- gGL.vertex2i(0, height );
-
- gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
- gGL.vertex2i(0, 0);
-
- gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
- gGL.vertex2i(width, 0);
+ LLVector3 ui_scale = gGL.getUIScale();
+ LLVector3 ui_translation = gGL.getUITranslation();
+ ui_translation.mV[VX] += x;
+ ui_translation.mV[VY] += y;
+ ui_translation.scaleVec(ui_scale);
+ S32 index = 0;
+ S32 scaled_width = llround(width * ui_scale.mV[VX]);
+ S32 scaled_height = llround(height * ui_scale.mV[VY]);
+
+ uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
+ pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
+ pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
+ pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
+ index++;
+
+ uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
+ pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f);
+ index++;
+
+ gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
}
gGL.end();
- gGL.popUIMatrix();
}
else
{
@@ -755,25 +825,6 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
LLUI::setLineWidth(1.f);
}
-
-void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom)
-{
- gGL.color4fv( LLColor4::white.mV );
- glLogicOp( GL_XOR );
- stop_glerror();
-
- gGL.begin(LLRender::QUADS);
- gGL.vertex2i(left, top);
- gGL.vertex2i(left, bottom);
- gGL.vertex2i(right, bottom);
- gGL.vertex2i(right, top);
- gGL.end();
-
- glLogicOp( GL_COPY );
- stop_glerror();
-}
-
-
void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle)
{
if (end_angle < start_angle)
@@ -1007,42 +1058,6 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
gGL.end();
}
-// Draws spokes around a circle.
-void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color)
-{
- const F32 DELTA = F_TWO_PI / count;
- const F32 HALF_DELTA = DELTA * 0.5f;
- const F32 SIN_DELTA = sin( DELTA );
- const F32 COS_DELTA = cos( DELTA );
-
- F32 x1 = outer_radius * cos( HALF_DELTA );
- F32 y1 = outer_radius * sin( HALF_DELTA );
- F32 x2 = inner_radius * cos( HALF_DELTA );
- F32 y2 = inner_radius * sin( HALF_DELTA );
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- gGL.begin( LLRender::LINES );
- {
- while( count-- )
- {
- gGL.color4fv(outer_color.mV);
- gGL.vertex2f( x1, y1 );
- gGL.color4fv(inner_color.mV);
- gGL.vertex2f( x2, y2 );
-
- F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
- y1 = x1 * SIN_DELTA + y1 * COS_DELTA;
- x1 = x1_new;
-
- F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
- y2 = x2 * SIN_DELTA + y2 * COS_DELTA;
- x2 = x2_new;
- }
- }
- gGL.end();
-}
-
void gl_rect_2d_simple_tex( S32 width, S32 height )
{
gGL.begin( LLRender::QUADS );
@@ -1230,6 +1245,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
gGL.popUIMatrix();
}
+//FIXME: rewrite to use scissor?
void gl_segmented_rect_2d_fragment_tex(const S32 left,
const S32 top,
const S32 right,
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index afec2e9c26..fc545c85d5 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -90,7 +90,6 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac);
void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
-void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color);
void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
@@ -99,7 +98,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
-void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom);
void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f );
void gl_rect_2d_simple_tex( S32 width, S32 height );
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 294c96f8f4..3ac3bf8c41 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -95,6 +95,7 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
: LLView(p),
mTentative(FALSE),
mIsChrome(FALSE),
+ mTabStop(FALSE),
mViewModel(viewmodel),
mControlVariable(NULL),
mEnabledControlVariable(NULL),
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 71fd5034df..76dfdf754c 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -141,8 +141,6 @@ public:
// LLView interface
/*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
/*virtual*/ BOOL isCtrl() const;
- /*virtual*/ void setTentative(BOOL b);
- /*virtual*/ BOOL getTentative() const;
/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL canFocusChildren() const;
@@ -174,6 +172,8 @@ public:
void setMakeVisibleControlVariable(LLControlVariable* control);
void setMakeInvisibleControlVariable(LLControlVariable* control);
+ virtual void setTentative(BOOL b);
+ virtual BOOL getTentative() const;
virtual void setValue(const LLSD& value);
virtual LLSD getValue() const;
/// When two widgets are displaying the same data (e.g. during a skin
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index a34ede439a..5680ab8bd4 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -357,6 +357,12 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
return LLTrans::getString("TooltipAgentUrl");
}
+bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const
+{
+ std::string url = getUrl(string);
+ return LLStringUtil::endsWith(url, "/about") || LLStringUtil::endsWith(url, "/inspect");
+}
+
std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
if (!gCacheName)
@@ -724,6 +730,19 @@ std::string LLUrlEntrySLLabel::getTooltip(const std::string &string) const
return LLUrlEntryBase::getTooltip(string);
}
+bool LLUrlEntrySLLabel::underlineOnHoverOnly(const std::string &string) const
+{
+ std::string url = getUrl(string);
+ LLUrlMatch match;
+ if (LLUrlRegistry::instance().findUrl(url, match))
+ {
+ return match.underlineOnHoverOnly();
+ }
+
+ // unrecognized URL? should not happen
+ return LLUrlEntryBase::underlineOnHoverOnly(string);
+}
+
//
// LLUrlEntryWorldMap Describes secondlife:///<location> URLs
//
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index d868e01aa6..e25eaa7555 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -88,6 +88,9 @@ public:
/// is this a match for a URL that should not be hyperlinked?
bool isLinkDisabled() const { return mDisabledLink; }
+ /// Should this link text be underlined only when mouse is hovered over it?
+ virtual bool underlineOnHoverOnly(const std::string &string) const { return false; }
+
virtual LLUUID getID(const std::string &string) const { return LLUUID::null; }
protected:
@@ -167,6 +170,7 @@ public:
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
/*virtual*/ std::string getTooltip(const std::string &string) const;
/*virtual*/ LLUUID getID(const std::string &string) const;
+ /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const;
private:
void onAgentNameReceived(const LLUUID& id, const std::string& first,
const std::string& last, BOOL is_group);
@@ -269,6 +273,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;
};
///
diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp
index 4ec97091a3..e53b0c4370 100644
--- a/indra/llui/llurlmatch.cpp
+++ b/indra/llui/llurlmatch.cpp
@@ -37,7 +37,8 @@ LLUrlMatch::LLUrlMatch() :
mIcon(""),
mMenuName(""),
mLocation(""),
- mDisabledLink(false)
+ mDisabledLink(false),
+ mUnderlineOnHoverOnly(false)
{
}
@@ -45,7 +46,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
const std::string &label, const std::string &tooltip,
const std::string &icon, const LLUIColor& color,
const std::string &menu, const std::string &location,
- bool disabled_link, const LLUUID& id)
+ bool disabled_link, const LLUUID& id, bool underline_on_hover_only)
{
mStart = start;
mEnd = end;
@@ -58,4 +59,5 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
mLocation = location;
mDisabledLink = disabled_link;
mID = id;
+ mUnderlineOnHoverOnly = underline_on_hover_only;
}
diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h
index 7a4f0bc10e..d1b2112ee7 100644
--- a/indra/llui/llurlmatch.h
+++ b/indra/llui/llurlmatch.h
@@ -80,12 +80,15 @@ public:
/// is this a match for a URL that should not be hyperlinked?
bool isLinkDisabled() const { return mDisabledLink; }
+ /// Should this link text be underlined only when mouse is hovered over it?
+ bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; }
+
/// 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 &tooltip, const std::string &icon,
const LLUIColor& color, const std::string &menu,
const std::string &location, bool disabled_link
- , const LLUUID& id );
+ , const LLUUID& id, bool underline_on_hover_only = false );
const LLUUID& getID() const { return mID;}
@@ -102,6 +105,7 @@ private:
LLUUID mID;
LLUIColor mColor;
bool mDisabledLink;
+ bool mUnderlineOnHoverOnly;
};
#endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 1c103a628b..9d215cf7ef 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -178,7 +178,8 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
match_entry->getMenuName(),
match_entry->getLocation(url),
match_entry->isLinkDisabled(),
- match_entry->getID(url));
+ match_entry->getID(url),
+ match_entry->underlineOnHoverOnly(url));
return true;
}
@@ -213,7 +214,8 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
match.getMenuName(),
match.getLocation(),
match.isLinkDisabled(),
- match.getID());
+ match.getID(),
+ match.underlineOnHoverOnly());
return true;
}
return false;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 42ce7b84fe..fe5ef269a9 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -397,28 +397,40 @@ bool LLCompareByTabOrder::operator() (const LLView* const a, const LLView* const
return (a_score == b_score) ? a < b : a_score < b_score;
}
-bool LLView::trueToRoot(const boost::function<bool (const LLView*)>& predicate) const
+BOOL LLView::isInVisibleChain() const
{
- const LLView* cur_view = this;
- while(cur_view)
+ BOOL visible = TRUE;
+
+ const LLView* viewp = this;
+ while(viewp)
{
- if(!predicate(cur_view))
+ if (!viewp->getVisible())
{
- return false;
+ visible = FALSE;
+ break;
}
- cur_view = cur_view->getParent();
+ viewp = viewp->getParent();
}
- return true;
-}
-
-BOOL LLView::isInVisibleChain() const
-{
- return trueToRoot(&LLView::getVisible);
+
+ return visible;
}
BOOL LLView::isInEnabledChain() const
{
- return trueToRoot(&LLView::getEnabled);
+ BOOL enabled = TRUE;
+
+ const LLView* viewp = this;
+ while(viewp)
+ {
+ if (!viewp->getEnabled())
+ {
+ enabled = FALSE;
+ break;
+ }
+ viewp = viewp->getParent();
+ }
+
+ return enabled;
}
// virtual
@@ -428,17 +440,6 @@ BOOL LLView::canFocusChildren() const
}
//virtual
-void LLView::setTentative(BOOL b)
-{
-}
-
-//virtual
-BOOL LLView::getTentative() const
-{
- return FALSE;
-}
-
-//virtual
void LLView::setEnabled(BOOL enabled)
{
mEnabled = enabled;
@@ -2778,6 +2779,19 @@ LLView::tree_post_iterator_t LLView::endTreeDFSPost()
return tree_post_iterator_t();
}
+LLView::bfs_tree_iterator_t LLView::beginTreeBFS()
+{
+ return bfs_tree_iterator_t(this,
+ boost::bind(boost::mem_fn(&LLView::beginChild), _1),
+ boost::bind(boost::mem_fn(&LLView::endChild), _1));
+}
+
+LLView::bfs_tree_iterator_t LLView::endTreeBFS()
+{
+ // an empty iterator is an "end" iterator
+ return bfs_tree_iterator_t();
+}
+
LLView::root_to_view_iterator_t LLView::beginRootToView()
{
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index b9cecb0f84..f7175112bf 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -267,7 +267,6 @@ public:
S32 getDefaultTabGroup() const { return mDefaultTabGroup; }
S32 getLastTabGroup() { return mLastTabGroup; }
- bool trueToRoot(const boost::function<bool (const LLView*)>& predicate) const;
BOOL isInVisibleChain() const;
BOOL isInEnabledChain() const;
@@ -283,8 +282,6 @@ public:
// children, etc.
virtual void deleteAllChildren();
- virtual void setTentative(BOOL b);
- virtual BOOL getTentative() const;
void setAllChildrenEnabled(BOOL b);
virtual void setVisible(BOOL visible);
@@ -351,6 +348,10 @@ public:
tree_post_iterator_t beginTreeDFSPost();
tree_post_iterator_t endTreeDFSPost();
+ typedef LLTreeBFSIter<LLView, child_list_const_iter_t> bfs_tree_iterator_t;
+ bfs_tree_iterator_t beginTreeBFS();
+ bfs_tree_iterator_t endTreeBFS();
+
typedef LLTreeDownIter<LLView> root_to_view_iterator_t;
root_to_view_iterator_t beginRootToView();