summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt6
-rw-r--r--indra/llui/llbutton.cpp40
-rw-r--r--indra/llui/llbutton.h14
-rw-r--r--indra/llui/llconsole.cpp5
-rw-r--r--indra/llui/lldockablefloater.cpp27
-rw-r--r--indra/llui/lldockablefloater.h2
-rw-r--r--indra/llui/lldockcontrol.cpp45
-rw-r--r--indra/llui/lldockcontrol.h6
-rw-r--r--indra/llui/lldraghandle.cpp9
-rw-r--r--indra/llui/llflatlistview.cpp32
-rw-r--r--indra/llui/llflatlistview.h4
-rw-r--r--indra/llui/llfloater.cpp305
-rw-r--r--indra/llui/llfloater.h30
-rw-r--r--indra/llui/llfloaterreg.cpp38
-rw-r--r--indra/llui/llfloaterreg.h5
-rw-r--r--indra/llui/llfloaterreglistener.cpp114
-rw-r--r--indra/llui/llfloaterreglistener.h36
-rw-r--r--indra/llui/llflyoutbutton.cpp1
-rw-r--r--indra/llui/llfunctorregistry.cpp1
-rw-r--r--indra/llui/llhandle.h14
-rw-r--r--indra/llui/lliconctrl.cpp23
-rw-r--r--indra/llui/lliconctrl.h13
-rw-r--r--indra/llui/lllayoutstack.cpp30
-rw-r--r--indra/llui/lllayoutstack.h3
-rw-r--r--indra/llui/lllineeditor.cpp106
-rw-r--r--indra/llui/lllineeditor.h18
-rw-r--r--indra/llui/lllocalcliprect.cpp3
-rw-r--r--indra/llui/llmenubutton.cpp2
-rw-r--r--indra/llui/llmenugl.cpp75
-rw-r--r--indra/llui/llmenugl.h2
-rw-r--r--indra/llui/llmodaldialog.cpp15
-rw-r--r--indra/llui/llmodaldialog.h3
-rw-r--r--indra/llui/llmultifloater.cpp12
-rw-r--r--indra/llui/llnotifications.cpp4
-rw-r--r--indra/llui/llnotifications.h20
-rw-r--r--indra/llui/llnotificationslistener.cpp55
-rw-r--r--indra/llui/llnotificationslistener.h34
-rw-r--r--indra/llui/llpanel.cpp95
-rw-r--r--indra/llui/llpanel.h31
-rw-r--r--indra/llui/llradiogroup.cpp2
-rw-r--r--indra/llui/llresmgr.cpp8
-rw-r--r--indra/llui/llrngwriter.cpp3
-rw-r--r--indra/llui/llscrollbar.cpp32
-rw-r--r--indra/llui/llscrollbar.h12
-rw-r--r--indra/llui/llscrollcontainer.cpp8
-rw-r--r--indra/llui/llscrollingpanellist.cpp4
-rw-r--r--indra/llui/llscrollingpanellist.h2
-rw-r--r--indra/llui/llscrolllistcolumn.cpp15
-rw-r--r--indra/llui/llscrolllistcolumn.h15
-rw-r--r--indra/llui/llslider.cpp2
-rw-r--r--indra/llui/llsliderctrl.cpp1
-rw-r--r--indra/llui/lltabcontainer.cpp155
-rw-r--r--indra/llui/lltabcontainer.h40
-rw-r--r--indra/llui/lltextbase.cpp402
-rw-r--r--indra/llui/lltextbase.h35
-rw-r--r--indra/llui/lltextbox.cpp26
-rw-r--r--indra/llui/lltextbox.h21
-rw-r--r--indra/llui/lltexteditor.cpp94
-rw-r--r--indra/llui/lltexteditor.h6
-rw-r--r--indra/llui/lltooltip.cpp135
-rw-r--r--indra/llui/lltooltip.h14
-rw-r--r--indra/llui/llui.cpp23
-rw-r--r--indra/llui/llui.h29
-rw-r--r--indra/llui/lluicolortable.cpp25
-rw-r--r--indra/llui/lluicolortable.h23
-rw-r--r--indra/llui/lluictrl.cpp47
-rw-r--r--indra/llui/lluictrl.h24
-rw-r--r--indra/llui/lluictrlfactory.cpp45
-rw-r--r--indra/llui/lluictrlfactory.h50
-rw-r--r--indra/llui/lluiimage.cpp3
-rw-r--r--indra/llui/lluiimage.h6
-rw-r--r--indra/llui/lluistring.cpp2
-rw-r--r--indra/llui/lluistring.h6
-rw-r--r--indra/llui/llurlaction.cpp12
-rw-r--r--indra/llui/llurlaction.h3
-rw-r--r--indra/llui/llurlentry.cpp172
-rw-r--r--indra/llui/llurlentry.h14
-rw-r--r--indra/llui/llurlregistry.cpp13
-rw-r--r--indra/llui/llurlregistry.h4
-rw-r--r--indra/llui/llview.cpp73
-rw-r--r--indra/llui/llview.h23
-rw-r--r--indra/llui/tests/llurlentry_test.cpp4
82 files changed, 2011 insertions, 900 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index d9169f57f9..f0b4436df5 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -43,6 +43,7 @@ set(llui_SOURCE_FILES
llflatlistview.cpp
llfloater.cpp
llfloaterreg.cpp
+ llfloaterreglistener.cpp
llflyoutbutton.cpp
llfocusmgr.cpp
llfunctorregistry.cpp
@@ -58,6 +59,7 @@ set(llui_SOURCE_FILES
llmultislider.cpp
llmultisliderctrl.cpp
llnotifications.cpp
+ llnotificationslistener.cpp
llpanel.cpp
llprogressbar.cpp
llradiogroup.cpp
@@ -86,7 +88,6 @@ set(llui_SOURCE_FILES
lltextbox.cpp
lltexteditor.cpp
lltextparser.cpp
- lltransientfloatermgr.cpp
lltransutil.cpp
lltoggleablemenu.cpp
lltooltip.cpp
@@ -128,6 +129,7 @@ set(llui_HEADER_FILES
llflatlistview.h
llfloater.h
llfloaterreg.h
+ llfloaterreglistener.h
llflyoutbutton.h
llfocusmgr.h
llfunctorregistry.h
@@ -146,6 +148,7 @@ set(llui_HEADER_FILES
llmultisliderctrl.h
llmultislider.h
llnotifications.h
+ llnotificationslistener.h
llpanel.h
llprogressbar.h
llradiogroup.h
@@ -176,7 +179,6 @@ set(llui_HEADER_FILES
lltextparser.h
lltoggleablemenu.h
lltooltip.h
- lltransientfloatermgr.h
lltransutil.h
lluicolortable.h
lluiconstants.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index f28fca35c5..bbaf908d2e 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -95,8 +95,7 @@ LLButton::Params::Params()
is_toggle("is_toggle", false),
scale_image("scale_image", true),
hover_glow_amount("hover_glow_amount"),
- commit_on_return("commit_on_return", true),
- picture_style("picture_style", false)
+ commit_on_return("commit_on_return", true)
{
addSynonym(is_toggle, "toggle");
held_down_delay.seconds = 0.5f;
@@ -147,22 +146,15 @@ LLButton::LLButton(const LLButton::Params& p)
mHoverGlowStrength(p.hover_glow_amount),
mCommitOnReturn(p.commit_on_return),
mFadeWhenDisabled(FALSE),
- mForcePressedState(FALSE)
+ mForcePressedState(FALSE),
+ mLastDrawCharsCount(0)
{
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
- //if we aren't a picture_style button set label as name if not provided
- if (!p.picture_style.isProvided() || !p.picture_style)
+ if (!p.label_selected.isProvided())
{
- if (!p.label.isProvided())
- {
- mUnselectedLabel = p.name();
- }
- if (!p.label_selected.isProvided())
- {
- mSelectedLabel = mUnselectedLabel.getString();
- }
+ mSelectedLabel = mUnselectedLabel;
}
// Hack to make sure there is space for at least one character
@@ -485,6 +477,11 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
mNeedsHighlight = FALSE;
}
+void LLButton::setHighlight(bool b)
+{
+ mNeedsHighlight = b;
+}
+
BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
{
if (!childrenHandleHover(x, y, mask))
@@ -814,7 +811,7 @@ void LLButton::draw()
// LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value.
// Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode.
// Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars.
- mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset),
+ mLastDrawCharsCount = mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset),
label_color % alpha,
mHAlign, LLFontGL::BOTTOM,
LLFontGL::NORMAL,
@@ -1094,18 +1091,3 @@ void LLButton::resetMouseDownTimer()
mMouseDownTimer.stop();
mMouseDownTimer.reset();
}
-
-
-// *TODO: Remove this function after the initial XUI XML re-export pass.
-// static
-void LLButton::setupParamsForExport(Params& p, LLView* parent)
-{
- std::string label = p.label;
- if (label.empty())
- {
- //if our label is empty this is a picture style button
- p.picture_style = true;
- }
-
- LLUICtrl::setupParamsForExport(p, parent);
-}
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 7ca520b935..08f289092f 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -115,8 +115,7 @@ public:
// misc
Optional<bool> is_toggle,
scale_image,
- commit_on_return,
- picture_style; //if true, don't display label
+ commit_on_return;
Optional<F32> hover_glow_amount;
Optional<TimeIntervalParam> held_down_delay;
@@ -176,6 +175,7 @@ public:
BOOL getToggleState() const;
void setToggleState(BOOL b);
+ void setHighlight(bool b);
void setFlashing( BOOL b );
BOOL getFlashing() const { return mFlashing; }
@@ -210,6 +210,9 @@ public:
void setFont(const LLFontGL *font)
{ mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); }
+
+ S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; }
+
void setScaleImage(BOOL scale) { mScaleImage = scale; }
BOOL getScaleImage() const { return mScaleImage; }
@@ -238,13 +241,11 @@ public:
void setForcePressedState(BOOL b) { mForcePressedState = b; }
protected:
- const LLPointer<LLUIImage>& getImageUnselected() const { return mImageUnselected; }
- const LLPointer<LLUIImage>& getImageSelected() const { return mImageSelected; }
+ LLPointer<LLUIImage> getImageUnselected() const { return mImageUnselected; }
+ LLPointer<LLUIImage> getImageSelected() const { return mImageSelected; }
LLFrameTimer mMouseDownTimer;
- // If the label is empty, set the picture_style attribute
- static void setupParamsForExport(Params& p, LLView* parent);
private:
void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size);
void resetMouseDownTimer();
@@ -260,6 +261,7 @@ private:
S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback
F32 mHeldDownDelay; // seconds, after which held-down callbacks get called
S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called
+ S32 mLastDrawCharsCount;
LLPointer<LLUIImage> mImageOverlay;
LLFontGL::HAlign mImageOverlayAlignment;
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 285ce82d2d..e0053b4cc7 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -120,6 +120,11 @@ void LLConsole::setFontSize(S32 size_index)
{
mFont = LLFontGL::getFontSansSerifHuge();
}
+ // Make sure the font exists
+ if (mFont == NULL)
+ {
+ mFont = LLFontGL::getFontDefault();
+ }
for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
{
diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp
index 228d0e701f..f56cb2eee7 100644
--- a/indra/llui/lldockablefloater.cpp
+++ b/indra/llui/lldockablefloater.cpp
@@ -99,7 +99,7 @@ void LLDockableFloater::toggleInstance(const LLSD& sdname)
{
instance->setMinimized(FALSE);
instance->setVisible(TRUE);
- instance->setFocus(TRUE);
+ gFloaterView->bringToFront(instance);
}
}
@@ -136,11 +136,29 @@ void LLDockableFloater::setMinimized(BOOL minimize)
{
setVisible(FALSE);
}
- setCanDock(!minimize);
+
+ if (minimize)
+ {
+ setCanDock(false);
+ }
+ else if (!minimize && mDockControl.get() != NULL && mDockControl.get()->isDockVisible())
+ {
+ setCanDock(true);
+ }
LLFloater::setMinimized(minimize);
}
+LLView * LLDockableFloater::getDockWidget()
+{
+ LLView * res = NULL;
+ if (getDockControl() != NULL) {
+ res = getDockControl()->getDock();
+ }
+
+ return res;
+}
+
void LLDockableFloater::onDockHidden()
{
setCanDock(FALSE);
@@ -148,7 +166,10 @@ void LLDockableFloater::onDockHidden()
void LLDockableFloater::onDockShown()
{
- setCanDock(TRUE);
+ if (!isMinimized())
+ {
+ setCanDock(TRUE);
+ }
}
void LLDockableFloater::setDocked(bool docked, bool pop_on_undock)
diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h
index 499ce9ae8d..46491d8a29 100644
--- a/indra/llui/lldockablefloater.h
+++ b/indra/llui/lldockablefloater.h
@@ -78,6 +78,8 @@ public:
*/
/*virtual*/ void setMinimized(BOOL minimize);
+ LLView * getDockWidget();
+
virtual void onDockHidden();
virtual void onDockShown();
diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp
index cdcd823b1c..35a854267a 100644
--- a/indra/llui/lldockcontrol.cpp
+++ b/indra/llui/lldockcontrol.cpp
@@ -37,7 +37,7 @@
LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) :
- mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue)
+ mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue)
{
mDockAt = dockAt;
@@ -63,6 +63,15 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
{
repositionDockable();
}
+
+ if (mDockWidget != NULL)
+ {
+ mDockWidgetVisible = isDockVisible();
+ }
+ else
+ {
+ mDockWidgetVisible = false;
+ }
}
LLDockControl::~LLDockControl()
@@ -75,6 +84,11 @@ void LLDockControl::setDock(LLView* dockWidget)
if (mDockWidget != NULL)
{
repositionDockable();
+ mDockWidgetVisible = isDockVisible();
+ }
+ else
+ {
+ mDockWidgetVisible = false;
}
}
@@ -88,11 +102,10 @@ void LLDockControl::repositionDockable()
LLRect dockRect = mDockWidget->calcScreenRect();
LLRect rootRect;
mGetAllowedRectCallback(rootRect);
- static BOOL prev_visibility = !mDockWidget->getVisible();
// recalculate dockable position if dock position changed, dock visibility changed,
// root view rect changed or recalculation is forced
- if (mPrevDockRect != dockRect || prev_visibility != mDockWidget->getVisible()
+ if (mPrevDockRect != dockRect || mDockWidgetVisible != isDockVisible()
|| mRootRect != rootRect || mRecalculateDocablePosition)
{
// undock dockable and off() if dock not visible
@@ -125,7 +138,7 @@ void LLDockControl::repositionDockable()
mPrevDockRect = dockRect;
mRootRect = rootRect;
mRecalculateDocablePosition = false;
- prev_visibility = mDockWidget->getVisible();
+ mDockWidgetVisible = isDockVisible();
}
}
@@ -143,6 +156,8 @@ bool LLDockControl::isDockVisible()
switch (mDockAt)
{
+ case LEFT: // to keep compiler happy
+ break;
case TOP:
// check is dock inside parent rect
LLRect dockParentRect =
@@ -170,8 +185,27 @@ void LLDockControl::moveDockable()
LLRect dockableRect = mDockableFloater->calcScreenRect();
S32 x = 0;
S32 y = 0;
+ LLRect dockParentRect;
switch (mDockAt)
{
+ case LEFT:
+ x = dockRect.mLeft;
+ y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
+ // check is dockable inside root view rect
+ if (x < rootRect.mLeft)
+ {
+ x = rootRect.mLeft;
+ }
+ if (x + dockableRect.getWidth() > rootRect.mRight)
+ {
+ x = rootRect.mRight - dockableRect.getWidth();
+ }
+
+ mDockTongueX = x + dockableRect.getWidth()/2 - mDockTongue->getWidth() / 2;
+
+ mDockTongueY = dockRect.mTop;
+ break;
+
case TOP:
x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
@@ -187,8 +221,7 @@ void LLDockControl::moveDockable()
// calculate dock tongue position
- LLRect dockParentRect =
- mDockWidget->getParent()->calcScreenRect();
+ dockParentRect = mDockWidget->getParent()->calcScreenRect();
if (dockRect.getCenterX() < dockParentRect.mLeft)
{
mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h
index e8ffcac0ac..eaedb4c307 100644
--- a/indra/llui/lldockcontrol.h
+++ b/indra/llui/lldockcontrol.h
@@ -48,6 +48,7 @@ public:
enum DocAt
{
TOP
+ ,LEFT
};
public:
@@ -63,6 +64,10 @@ public:
void on();
void off();
void setDock(LLView* dockWidget);
+ LLView* getDock()
+ {
+ return mDockWidget;
+ }
void repositionDockable();
void drawToungue();
bool isDockVisible();
@@ -76,6 +81,7 @@ private:
get_allowed_rect_callback_t mGetAllowedRectCallback;
bool mEnabled;
bool mRecalculateDocablePosition;
+ bool mDockWidgetVisible;
DocAt mDockAt;
LLView* mDockWidget;
LLRect mPrevDockRect;
diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp
index 8eccd709ce..d9b98b1c28 100644
--- a/indra/llui/lldraghandle.cpp
+++ b/indra/llui/lldraghandle.cpp
@@ -49,9 +49,9 @@
#include "lluictrlfactory.h"
const S32 LEADING_PAD = 5;
-const S32 TITLE_PAD = 8;
+const S32 TITLE_HPAD = 8;
const S32 BORDER_PAD = 1;
-const S32 LEFT_PAD = BORDER_PAD + TITLE_PAD + LEADING_PAD;
+const S32 LEFT_PAD = BORDER_PAD + TITLE_HPAD + LEADING_PAD;
const S32 RIGHT_PAD = BORDER_PAD + 32; // HACK: space for close btn and minimize btn
S32 LLDragHandle::sSnapMargin = 5;
@@ -240,19 +240,20 @@ void LLDragHandleLeft::draw()
void LLDragHandleTop::reshapeTitleBox()
{
+ static LLUICachedControl<S32> title_vpad("UIFloaterTitleVPad", 0);
if( ! mTitleBox)
{
return;
}
const LLFontGL* font = LLFontGL::getFontSansSerif();
- S32 title_width = font->getWidth( mTitleBox->getText() ) + TITLE_PAD;
+ S32 title_width = font->getWidth( mTitleBox->getText() ) + TITLE_HPAD;
if (getMaxTitleWidth() > 0)
title_width = llmin(title_width, getMaxTitleWidth());
S32 title_height = llround(font->getLineHeight());
LLRect title_rect;
title_rect.setLeftTopAndSize(
LEFT_PAD,
- getRect().getHeight() - BORDER_PAD,
+ getRect().getHeight() - title_vpad,
getRect().getWidth() - LEFT_PAD - RIGHT_PAD,
title_height);
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index e9df361472..19f203b80c 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -44,6 +44,9 @@ const LLSD UNSELECTED_EVENT = LLSD().insert("selected", false);
static const std::string COMMENT_TEXTBOX = "comment_text";
+//forward declaration
+bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2);
+
LLFlatListView::Params::Params()
: item_pad("item_pad"),
allow_select("allow_select"),
@@ -89,7 +92,7 @@ bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*
//_4 is for MASK
item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
- item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
+ item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4));
rearrangeItems();
notifyParentItemsRectChanged();
@@ -134,7 +137,7 @@ bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add,
//_4 is for MASK
item_to_add->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
- item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
+ item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4));
rearrangeItems();
notifyParentItemsRectChanged();
@@ -333,6 +336,17 @@ void LLFlatListView::sort()
rearrangeItems();
}
+bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value)
+{
+ if (old_value.isUndefined() || new_value.isUndefined()) return false;
+ if (llsds_are_equal(old_value, new_value)) return false;
+
+ item_pair_t* item_pair = getItemPair(old_value);
+ if (!item_pair) return false;
+
+ item_pair->second = new_value;
+ return true;
+}
//////////////////////////////////////////////////////////////////////////
// PROTECTED STUFF
@@ -445,6 +459,20 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
selectItemPair(item_pair, select_item);
}
+void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask)
+{
+ if (!item_pair)
+ return;
+
+ // Forbid deselecting of items on right mouse button click if mMultipleSelection flag is set on,
+ // because some of derived classes may have context menu and selected items must be kept.
+ if ( !(mask & MASK_CONTROL) && mMultipleSelection && isSelected(item_pair) )
+ return;
+
+ // else got same behavior as at onItemMouseClick
+ onItemMouseClick(item_pair, mask);
+}
+
LLFlatListView::item_pair_t* LLFlatListView::getItemPair(LLPanel* item) const
{
llassert(item);
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index af5a9cfa9b..97772bc677 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -273,6 +273,8 @@ public:
void setComparator(const ItemComparator* comp) { mItemComparator = comp; }
void sort();
+ bool updateValue(const LLSD& old_value, const LLSD& new_value);
+
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
@@ -302,6 +304,8 @@ protected:
/** Manage selection on mouse events */
void onItemMouseClick(item_pair_t* item_pair, MASK mask);
+ void onItemRightMouseClick(item_pair_t* item_pair, MASK mask);
+
/**
* Updates position of items.
* It does not take into account invisible items.
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 8d2783db20..aac27e6562 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -61,6 +61,7 @@
#include "lltrans.h"
#include "llhelp.h"
#include "llmultifloater.h"
+#include "llsdutil.h"
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
@@ -132,6 +133,16 @@ LLFloater::handle_map_t LLFloater::sFloaterMap;
LLFloaterView* gFloaterView = NULL;
+/*==========================================================================*|
+// DEV-38598: The fundamental problem with this operation is that it can only
+// support a subset of LLSD values. While it's plausible to compare two arrays
+// lexicographically, what strict ordering can you impose on maps?
+// (LLFloaterTOS's current key is an LLSD map.)
+
+// Of course something like this is necessary if you want to build a std::set
+// or std::map with LLSD keys. Fortunately we're getting by with other
+// container types for now.
+
//static
bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
{
@@ -159,32 +170,11 @@ bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
else
return false; // no valid operation for Binary
}
+|*==========================================================================*/
bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
{
- if (a.type() != b.type())
- {
- //llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl;
- return false;
- }
- else if (a.isUndefined())
- return true;
- else if (a.isInteger())
- return a.asInteger() == b.asInteger();
- else if (a.isReal())
- return a.asReal() == b.asReal();
- else if (a.isString())
- return a.asString() == b.asString();
- else if (a.isUUID())
- return a.asUUID() == b.asUUID();
- else if (a.isDate())
- return a.asDate() == b.asDate();
- else if (a.isURI())
- return a.asString() == b.asString(); // compare URIs as strings
- else if (a.isBoolean())
- return a.asBoolean() == b.asBoolean();
- else
- return false; // no valid operation for Binary
+ return llsd_equals(a, b);
}
//************************************
@@ -199,11 +189,14 @@ LLFloater::Params::Params()
can_close("can_close", true),
can_drag_on_left("can_drag_on_left", false),
can_tear_off("can_tear_off", true),
+ save_dock_state("save_dock_state", false),
save_rect("save_rect", false),
save_visibility("save_visibility", false),
+ can_dock("can_dock", false),
+ header_height("header_height", 0),
+ legacy_header_height("legacy_header_height", 0),
open_callback("open_callback"),
- close_callback("close_callback"),
- can_dock("can_dock", false)
+ close_callback("close_callback")
{
visible = false;
}
@@ -229,7 +222,7 @@ void LLFloater::initClass()
static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater");
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
-: LLPanel(),
+: LLPanel(), // intentionally do not pass params here, see initFromParams
mDragHandle(NULL),
mTitle(p.title),
mShortTitle(p.short_title),
@@ -243,6 +236,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mResizable(p.can_resize),
mMinWidth(p.min_width),
mMinHeight(p.min_height),
+ mHeaderHeight(p.header_height),
+ mLegacyHeaderHeight(p.legacy_header_height),
mMinimized(FALSE),
mForeground(FALSE),
mFirstLook(TRUE),
@@ -273,11 +268,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mButtonsEnabled[i] = FALSE;
mButtons[i] = NULL;
}
- for (S32 i = 0; i < 4; i++)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
+ addDragHandle();
+ addResizeCtrls();
initFromParams(p);
@@ -290,10 +282,6 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
// Note: Floaters constructed from XML call init() twice!
void LLFloater::initFloater()
{
- addDragHandle();
-
- addResizeCtrls();
-
// Close button.
if (mCanClose)
{
@@ -333,9 +321,6 @@ void LLFloater::initFloater()
void LLFloater::addDragHandle()
{
- static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
- S32 close_box_size = mCanClose ? floater_close_box_size : 0;
-
if (!mDragHandle)
{
if (mDragOnLeft)
@@ -356,6 +341,14 @@ void LLFloater::addDragHandle()
}
addChild(mDragHandle);
}
+ layoutDragHandle();
+}
+
+void LLFloater::layoutDragHandle()
+{
+ static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+ S32 close_box_size = mCanClose ? floater_close_box_size : 0;
+
LLRect rect;
if (mDragOnLeft)
{
@@ -371,40 +364,17 @@ void LLFloater::addDragHandle()
}
void LLFloater::addResizeCtrls()
-{
- for (S32 i = 0; i < 4; i++)
- {
- if (mResizeBar[i])
- {
- removeChild(mResizeBar[i]);
- delete mResizeBar[i];
- mResizeBar[i] = NULL;
- }
- if (mResizeHandle[i])
- {
- removeChild(mResizeHandle[i]);
- delete mResizeHandle[i];
- mResizeHandle[i] = NULL;
- }
- }
- if( !mResizable )
- {
- return;
- }
-
+{
// Resize bars (sides)
- const S32 RESIZE_BAR_THICKNESS = 3;
LLResizeBar::Params p;
p.name("resizebar_left");
p.resizing_view(this);
- p.rect(LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0));
p.min_size(mMinWidth);
p.side(LLResizeBar::LEFT);
mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p);
addChild( mResizeBar[LLResizeBar::LEFT] );
p.name("resizebar_top");
- p.rect(LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS));
p.min_size(mMinHeight);
p.side(LLResizeBar::TOP);
@@ -412,15 +382,12 @@ void LLFloater::addResizeCtrls()
addChild( mResizeBar[LLResizeBar::TOP] );
p.name("resizebar_right");
- p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0));
p.min_size(mMinWidth);
- p.side(LLResizeBar::RIGHT);
-
+ p.side(LLResizeBar::RIGHT);
mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p);
addChild( mResizeBar[LLResizeBar::RIGHT] );
p.name("resizebar_bottom");
- p.rect(LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0));
p.min_size(mMinHeight);
p.side(LLResizeBar::BOTTOM);
mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p);
@@ -431,27 +398,69 @@ void LLFloater::addResizeCtrls()
// handles must not be mouse-opaque, otherwise they block hover events
// to other buttons like the close box. JC
handle_p.mouse_opaque(false);
- handle_p.rect(LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0));
handle_p.min_width(mMinWidth);
handle_p.min_height(mMinHeight);
handle_p.corner(LLResizeHandle::RIGHT_BOTTOM);
mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
addChild(mResizeHandle[0]);
- handle_p.rect(LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT));
handle_p.corner(LLResizeHandle::RIGHT_TOP);
mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
addChild(mResizeHandle[1]);
- handle_p.rect(LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ));
handle_p.corner(LLResizeHandle::LEFT_BOTTOM);
mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
addChild(mResizeHandle[2]);
- handle_p.rect(LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ));
handle_p.corner(LLResizeHandle::LEFT_TOP);
mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
addChild(mResizeHandle[3]);
+
+ layoutResizeCtrls();
+}
+
+void LLFloater::layoutResizeCtrls()
+{
+ LLRect rect;
+
+ // Resize bars (sides)
+ const S32 RESIZE_BAR_THICKNESS = 3;
+ rect = LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0);
+ mResizeBar[LLResizeBar::LEFT]->setRect(rect);
+
+ rect = LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS);
+ mResizeBar[LLResizeBar::TOP]->setRect(rect);
+
+ rect = LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0);
+ mResizeBar[LLResizeBar::RIGHT]->setRect(rect);
+
+ rect = LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0);
+ mResizeBar[LLResizeBar::BOTTOM]->setRect(rect);
+
+ // Resize handles (corners)
+ rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0);
+ mResizeHandle[0]->setRect(rect);
+
+ rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT);
+ mResizeHandle[1]->setRect(rect);
+
+ rect = LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 );
+ mResizeHandle[2]->setRect(rect);
+
+ rect = LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT );
+ mResizeHandle[3]->setRect(rect);
+}
+
+void LLFloater::enableResizeCtrls(bool enable)
+{
+ for (S32 i = 0; i < 4; ++i)
+ {
+ mResizeBar[i]->setVisible(enable);
+ mResizeBar[i]->setEnabled(enable);
+
+ mResizeHandle[i]->setVisible(enable);
+ mResizeHandle[i]->setEnabled(enable);
+ }
}
// virtual
@@ -493,6 +502,7 @@ LLFloater::~LLFloater()
storeRectControl();
setVisible(false); // We're not visible if we're destroyed
storeVisibilityControl();
+ storeDockStateControl();
}
void LLFloater::storeRectControl()
@@ -511,6 +521,15 @@ void LLFloater::storeVisibilityControl()
}
}
+void LLFloater::storeDockStateControl()
+{
+ if( !sQuitting && mDocStateControl.size() > 1 )
+ {
+ LLUI::sSettingGroups["floater"]->setBOOL( mDocStateControl, isDocked() );
+ }
+}
+
+
void LLFloater::setVisible( BOOL visible )
{
LLPanel::setVisible(visible); // calls handleVisibilityChange()
@@ -753,6 +772,12 @@ LLMultiFloater* LLFloater::getHost()
return (LLMultiFloater*)mHostHandle.get();
}
+void LLFloater::applySavedVariables()
+{
+ applyRectControl();
+ applyDockState();
+}
+
void LLFloater::applyRectControl()
{
if (mRectControl.size() > 1)
@@ -769,6 +794,16 @@ void LLFloater::applyRectControl()
}
}
+void LLFloater::applyDockState()
+{
+ if (mDocStateControl.size() > 1)
+ {
+ bool dockState = LLUI::sSettingGroups["floater"]->getBOOL(mDocStateControl);
+ setDocked(dockState);
+ }
+
+}
+
void LLFloater::applyTitle()
{
if (!mDragHandle)
@@ -919,7 +954,8 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
void LLFloater::setMinimized(BOOL minimize)
{
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
if (minimize == mMinimized) return;
@@ -1092,7 +1128,8 @@ void LLFloater::setFocus( BOOL b )
void LLFloater::setRect(const LLRect &rect)
{
LLPanel::setRect(rect);
- addDragHandle(); // re-add drag handle, sized based on rect
+ layoutDragHandle();
+ layoutResizeCtrls();
}
// virtual
@@ -1262,6 +1299,12 @@ BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons inde
return FALSE;
}
+BOOL LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ LLPanel::handleScrollWheel(x,y,clicks);
+ return TRUE;//always
+}
+
// virtual
BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
{
@@ -1380,7 +1423,10 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock)
mButtonsEnabled[BUTTON_DOCK] = !mDocked;
mButtonsEnabled[BUTTON_UNDOCK] = mDocked;
updateButtons();
+
+ storeDockStateControl();
}
+
}
// static
@@ -1393,9 +1439,9 @@ void LLFloater::onClickMinimize(LLFloater* self)
void LLFloater::onClickTearOff(LLFloater* self)
{
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
if (!self)
return;
+ S32 floater_header_size = self->mHeaderHeight;
LLMultiFloater* host_floater = self->getHost();
if (host_floater) //Tear off
{
@@ -1443,7 +1489,12 @@ void LLFloater::onClickHelp( LLFloater* self )
{
if (self && LLUI::sHelpImpl)
{
- LLUI::sHelpImpl->showTopic(self->getHelpTopic());
+ // find the current help context for this floater
+ std::string help_topic;
+ if (self->findHelpTopic(help_topic))
+ {
+ LLUI::sHelpImpl->showTopic(help_topic);
+ }
}
}
@@ -1547,26 +1598,42 @@ void LLFloater::draw()
shadow_color % alpha,
llround(shadow_offset));
- // No transparent windows in simple UI
+ LLUIImage* image = NULL;
+ LLColor4 color;
if (isBackgroundOpaque())
{
- gl_rect_2d( left, top, right, bottom, getBackgroundColor() % alpha );
+ // NOTE: image may not be set
+ image = getBackgroundImage();
+ color = getBackgroundColor();
}
else
{
- gl_rect_2d( left, top, right, bottom, getTransparentColor() % alpha );
+ image = getTransparentImage();
+ color = getTransparentColor();
}
- if(hasFocus()
- && !getIsChrome()
- && !getCurrentTitle().empty())
+ if (image)
+ {
+ // We're using images for this floater's backgrounds
+ image->draw(getLocalRect(), UI_VERTEX_COLOR % alpha);
+ }
+ else
{
- static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor");
+ // We're not using images, use old-school flat colors
+ gl_rect_2d( left, top, right, bottom, color % alpha );
+
// draw highlight on title bar to indicate focus. RDW
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- LLRect r = getRect();
- gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,
- titlebar_focus_color % alpha, 0, TRUE);
+ if(hasFocus()
+ && !getIsChrome()
+ && !getCurrentTitle().empty())
+ {
+ static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor");
+
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ LLRect r = getRect();
+ gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1,
+ titlebar_focus_color % alpha, 0, TRUE);
+ }
}
}
@@ -1616,18 +1683,6 @@ void LLFloater::draw()
drawChild(focused_child);
}
- if( isBackgroundVisible() )
- {
- // add in a border to improve spacialized visual aclarity ;)
- // use lines instead of gl_rect_2d so we can round the edges as per james' recommendation
- static LLUIColor focus_border_color = LLUIColorTable::instance().getColor("FloaterFocusBorderColor");
- static LLUIColor unfocus_border_color = LLUIColorTable::instance().getColor("FloaterUnfocusBorderColor");
- LLUI::setLineWidth(1.5f);
- LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? focus_border_color : unfocus_border_color;
- gl_rect_2d_offset_local(0, getRect().getHeight() + 1, getRect().getWidth() + 1, 0, outlineColor % alpha, -LLPANEL_BORDER_WIDTH, FALSE);
- LLUI::setLineWidth(1.f);
- }
-
// update tearoff button for torn off floaters
// when last host goes away
if (mCanTearOff && !getHost())
@@ -1676,7 +1731,7 @@ void LLFloater::setCanTearOff(BOOL can_tear_off)
void LLFloater::setCanResize(BOOL can_resize)
{
mResizable = can_resize;
- addResizeCtrls();
+ enableResizeCtrls(can_resize);
}
void LLFloater::setCanDrag(BOOL can_drag)
@@ -1777,7 +1832,6 @@ void LLFloater::buildButtons()
LLButton::Params p;
p.name(sButtonNames[i]);
p.rect(btn_rect);
- p.label("");
p.image_unselected.name(sButtonActiveImageNames[i]);
// Selected, no matter if hovered or not, is "pressed"
p.image_selected.name(sButtonPressedImageNames[i]);
@@ -1790,6 +1844,7 @@ void LLFloater::buildButtons()
p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT);
p.tool_tip(sButtonToolTips[i]);
p.scale_image(true);
+ p.chrome(true);
LLButton* buttonp = LLUICtrlFactory::create<LLButton>(p);
addChild(buttonp);
@@ -2112,7 +2167,8 @@ void LLFloaterView::focusFrontFloater()
void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
{
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
S32 col = 0;
LLRect snap_rect_local = getLocalSnapRect();
@@ -2487,6 +2543,11 @@ void LLFloater::setInstanceName(const std::string& name)
{
mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName);
}
+ if(!mDocStateControl.empty())
+ {
+ mDocStateControl = LLFloaterReg::declareDockStateControl(mInstanceName);
+ }
+
}
}
@@ -2527,6 +2588,9 @@ void LLFloater::setupParamsForExport(Params& p, LLView* parent)
void LLFloater::initFromParams(const LLFloater::Params& p)
{
+ // *NOTE: We have too many classes derived from LLFloater to retrofit them
+ // all to pass in params via constructors. So we use this method.
+
// control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
LLPanel::initFromParams(p);
@@ -2538,11 +2602,12 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
setCanMinimize(p.can_minimize);
setCanClose(p.can_close);
setCanDock(p.can_dock);
+ setCanResize(p.can_resize);
+ setResizeLimits(p.min_width, p.min_height);
mDragOnLeft = p.can_drag_on_left;
- mResizable = p.can_resize;
- mMinWidth = p.min_width;
- mMinHeight = p.min_height;
+ mHeaderHeight = p.header_height;
+ mLegacyHeaderHeight = p.legacy_header_height;
mSingleInstance = p.single_instance;
mAutoTile = p.auto_tile;
@@ -2554,6 +2619,11 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
{
mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
}
+
+ if(p.save_dock_state)
+ {
+ mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set
+ }
// open callback
if (p.open_callback.isProvided())
@@ -2598,6 +2668,23 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
LLFloater::setFloaterHost(last_host);
}
+ // HACK: When we changed the header height to 25 pixels in Viewer 2, rather
+ // than re-layout all the floaters we use this value in pixels to make the
+ // whole floater bigger and change the top-left coordinate for widgets.
+ // The goal is to eventually set mLegacyHeaderHeight to zero, which would
+ // make the top-left corner for widget layout the same as the top-left
+ // corner of the window's content area. James
+ S32 header_stretch = (mHeaderHeight - mLegacyHeaderHeight);
+ if (header_stretch > 0)
+ {
+ // Stretch the floater vertically, don't move widgets
+ LLRect rect = getRect();
+ rect.mTop += header_stretch;
+
+ // This will also update drag handle, title bar, close box, etc.
+ setRect(rect);
+ }
+
BOOL result;
{
LLFastTimer ft(POST_BUILD);
@@ -2615,6 +2702,18 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
moveResizeHandlesToFront();
+ applyDockState();
+
return true; // *TODO: Error checking
}
+bool LLFloater::isShown() const
+{
+ return ! isMinimized() && isInVisibleChain();
+}
+
+/* static */
+bool LLFloater::isShown(const LLFloater* floater)
+{
+ return floater && floater->isShown();
+}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 7a6c3f6863..95c8dd84f6 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -87,12 +87,14 @@ friend class LLMultiFloater;
public:
struct KeyCompare
{
- static bool compare(const LLSD& a, const LLSD& b);
+// static bool compare(const LLSD& a, const LLSD& b);
static bool equate(const LLSD& a, const LLSD& b);
+/*==========================================================================*|
bool operator()(const LLSD& a, const LLSD& b) const
{
return compare(a, b);
}
+|*==========================================================================*/
};
enum EFloaterButtons
@@ -122,7 +124,10 @@ public:
can_tear_off,
save_rect,
save_visibility,
+ save_dock_state,
can_dock;
+ Optional<S32> header_height,
+ legacy_header_height; // HACK see initFromXML()
Optional<CommitCallbackParam> open_callback,
close_callback;
@@ -183,7 +188,13 @@ public:
void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE);
LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); }
void removeDependentFloater(LLFloater* dependent);
- BOOL isMinimized() { return mMinimized; }
+ BOOL isMinimized() const { return mMinimized; }
+ /// isShown() differs from getVisible() in that isShown() also considers
+ /// isMinimized(). isShown() is true only if visible and not minimized.
+ bool isShown() const;
+ /// The static isShown() can accept a NULL pointer (which of course
+ /// returns false). When non-NULL, it calls the non-static isShown().
+ static bool isShown(const LLFloater* floater);
BOOL isFrontmost();
BOOL isDependent() { return !mDependeeHandle.isDead(); }
void setCanMinimize(BOOL can_minimize);
@@ -201,11 +212,15 @@ public:
bool isDragOnLeft() const{ return mDragOnLeft; }
S32 getMinWidth() const{ return mMinWidth; }
S32 getMinHeight() const{ return mMinHeight; }
+ S32 getHeaderHeight() const { return mHeaderHeight; }
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
+
+ virtual BOOL handleScrollWheel(S32 x, S32 y, S32 mask);
+
virtual void draw();
virtual void onOpen(const LLSD& key) {}
@@ -265,9 +280,14 @@ public:
protected:
void setRectControl(const std::string& rectname) { mRectControl = rectname; };
+
+ virtual void applySavedVariables();
+
void applyRectControl();
+ void applyDockState();
void storeRectControl();
void storeVisibilityControl();
+ void storeDockStateControl();
void setKey(const LLSD& key);
void setInstanceName(const std::string& name);
@@ -291,7 +311,10 @@ private:
void buildButtons();
BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons index);
void addResizeCtrls();
+ void layoutResizeCtrls();
+ void enableResizeCtrls(bool enable);
void addDragHandle();
+ void layoutDragHandle(); // repair layout
public:
// Called when floater is opened, passes mKey
@@ -305,6 +328,7 @@ public:
protected:
std::string mRectControl;
std::string mVisibilityControl;
+ std::string mDocStateControl;
LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg
LLDragHandle* mDragHandle;
@@ -329,6 +353,8 @@ private:
S32 mMinWidth;
S32 mMinHeight;
+ S32 mHeaderHeight; // height in pixels of header for title, drag bar
+ S32 mLegacyHeaderHeight;// HACK see initFloaterXML()
BOOL mMinimized;
BOOL mForeground;
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 815260dff3..03925f922c 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -36,6 +36,7 @@
#include "llfloater.h"
#include "llmultifloater.h"
+#include "llfloaterreglistener.h"
//*******************************************************
@@ -45,6 +46,8 @@ LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
std::map<std::string,std::string> LLFloaterReg::sGroupMap;
+static LLFloaterRegListener sFloaterRegListener("LLFloaterReg");
+
//*******************************************************
//static
@@ -124,14 +127,14 @@ LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
bool success = LLUICtrlFactory::getInstance()->buildFloater(res, xui_file, NULL);
if (!success)
{
- llwarns << "Failed to buid floater type: '" << name << "'." << llendl;
+ llwarns << "Failed to build floater type: '" << name << "'." << llendl;
return NULL;
}
// Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe
res->mKey = key;
res->setInstanceName(name);
- res->applyRectControl(); // Can't apply rect control until setting instance name
+ res->applySavedVariables(); // Can't apply rect and dock state until setting instance name
if (res->mAutoTile && !res->getHost() && index > 0)
{
const LLRect& cur_rect = res->getRect();
@@ -249,7 +252,7 @@ bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key)
bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
{
LLFloater* instance = findInstance(name, key);
- if (instance && !instance->isMinimized() && instance->isInVisibleChain())
+ if (LLFloater::isShown(instance))
{
// When toggling *visibility*, close the host instead of the floater when hosted
if (instance->getHost())
@@ -269,14 +272,7 @@ bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
{
LLFloater* instance = findInstance(name, key);
- if (instance && !instance->isMinimized() && instance->isInVisibleChain())
- {
- return true;
- }
- else
- {
- return false;
- }
+ return LLFloater::isShown(instance);
}
//static
@@ -368,6 +364,26 @@ std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
}
//static
+std::string LLFloaterReg::declareDockStateControl(const std::string& name)
+{
+ std::string controlname = getDockStateControlName(name);
+ LLUI::sSettingGroups["floater"]->declareBOOL(controlname, TRUE,
+ llformat("Window Docking state for %s", name.c_str()),
+ TRUE);
+ return controlname;
+
+}
+
+//static
+std::string LLFloaterReg::getDockStateControlName(const std::string& name)
+{
+ std::string res = std::string("floater_dock_") + name;
+ LLStringUtil::replaceChar( res, ' ', '_' );
+ return res;
+}
+
+
+//static
void LLFloaterReg::registerControlVariables()
{
// Iterate through alll registered instance names and register rect and visibility control variables
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 7edac43c96..634a235926 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -70,6 +70,7 @@ public:
typedef std::map<std::string, BuildData> build_map_t;
private:
+ friend class LLFloaterRegListener;
static instance_list_t sNullInstanceList;
static instance_map_t sInstanceMap;
static build_map_t sBuildMap;
@@ -120,6 +121,10 @@ public:
static std::string declareRectControl(const std::string& name);
static std::string getVisibilityControlName(const std::string& name);
static std::string declareVisibilityControl(const std::string& name);
+
+ static std::string declareDockStateControl(const std::string& name);
+ static std::string getDockStateControlName(const std::string& name);
+
static void registerControlVariables();
// Callback wrappers
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
new file mode 100644
index 0000000000..57d148b5af
--- /dev/null
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -0,0 +1,114 @@
+/**
+ * @file llfloaterreglistener.cpp
+ * @author Nat Goodspeed
+ * @date 2009-08-12
+ * @brief Implementation for llfloaterreglistener.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llfloaterreglistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llfloaterreg.h"
+#include "llfloater.h"
+#include "llbutton.h"
+
+LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
+ LLDispatchListener(pumpName, "op")
+{
+ add("getBuildMap", &LLFloaterRegListener::getBuildMap, LLSD().insert("reply", LLSD()));
+ LLSD requiredName;
+ requiredName["name"] = LLSD();
+ add("showInstance", &LLFloaterRegListener::showInstance, requiredName);
+ add("hideInstance", &LLFloaterRegListener::hideInstance, requiredName);
+ add("toggleInstance", &LLFloaterRegListener::toggleInstance, requiredName);
+ LLSD requiredNameButton;
+ requiredNameButton["name"] = LLSD();
+ requiredNameButton["button"] = LLSD();
+ add("clickButton", &LLFloaterRegListener::clickButton, requiredNameButton);
+}
+
+void LLFloaterRegListener::getBuildMap(const LLSD& event) const
+{
+ // Honor the "reqid" convention by echoing event["reqid"] in our reply packet.
+ LLReqID reqID(event);
+ LLSD reply(reqID.makeResponse());
+ // Build an LLSD map that mirrors sBuildMap. Since we have no good way to
+ // represent a C++ callable in LLSD, the only part of BuildData we can
+ // store is the filename. For each LLSD map entry, it would be more
+ // extensible to store a nested LLSD map containing a single key "file" --
+ // but we don't bother, simply storing the string filename instead.
+ for (LLFloaterReg::build_map_t::const_iterator mi(LLFloaterReg::sBuildMap.begin()),
+ mend(LLFloaterReg::sBuildMap.end());
+ mi != mend; ++mi)
+ {
+ reply[mi->first] = mi->second.mFile;
+ }
+ // Send the reply to the LLEventPump named in event["reply"].
+ LLEventPumps::instance().obtain(event["reply"]).post(reply);
+}
+
+void LLFloaterRegListener::showInstance(const LLSD& event) const
+{
+ LLFloaterReg::showInstance(event["name"], event["key"], event["focus"]);
+}
+
+void LLFloaterRegListener::hideInstance(const LLSD& event) const
+{
+ LLFloaterReg::hideInstance(event["name"], event["key"]);
+}
+
+void LLFloaterRegListener::toggleInstance(const LLSD& event) const
+{
+ LLFloaterReg::toggleInstance(event["name"], event["key"]);
+}
+
+void LLFloaterRegListener::clickButton(const LLSD& event) const
+{
+ // If the caller requests a reply, build the reply.
+ LLReqID reqID(event);
+ LLSD reply(reqID.makeResponse());
+
+ LLFloater* floater = LLFloaterReg::findInstance(event["name"], event["key"]);
+ if (! LLFloater::isShown(floater))
+ {
+ reply["type"] = "LLFloater";
+ reply["name"] = event["name"];
+ reply["key"] = event["key"];
+ reply["error"] = floater? "!isShown()" : "NULL";
+ }
+ else
+ {
+ // Here 'floater' points to an LLFloater instance with the specified
+ // name and key which isShown().
+ LLButton* button = floater->findChild<LLButton>(event["button"]);
+ if (! LLButton::isAvailable(button))
+ {
+ reply["type"] = "LLButton";
+ reply["name"] = event["button"];
+ reply["error"] = button? "!isAvailable()" : "NULL";
+ }
+ else
+ {
+ // Here 'button' points to an isAvailable() LLButton child of
+ // 'floater' with the specified button name. Pretend to click it.
+ button->onCommit();
+ // Leave reply["error"] isUndefined(): no error, i.e. success.
+ }
+ }
+
+ // Send a reply only if caller asked for a reply.
+ LLSD replyPump(event["reply"]);
+ if (replyPump.isString()) // isUndefined() if absent
+ {
+ LLEventPumps::instance().obtain(replyPump).post(reply);
+ }
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
new file mode 100644
index 0000000000..304ecd1090
--- /dev/null
+++ b/indra/llui/llfloaterreglistener.h
@@ -0,0 +1,36 @@
+/**
+ * @file llfloaterreglistener.h
+ * @author Nat Goodspeed
+ * @date 2009-08-12
+ * @brief Wrap (subset of) LLFloaterReg API with an event API
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLFLOATERREGLISTENER_H)
+#define LL_LLFLOATERREGLISTENER_H
+
+#include "lleventdispatcher.h"
+#include <string>
+
+class LLSD;
+
+/// Event API wrapper for LLFloaterReg
+class LLFloaterRegListener: public LLDispatchListener
+{
+public:
+ /// As all public LLFloaterReg methods are static, there's no point in
+ /// binding an LLFloaterReg instance.
+ LLFloaterRegListener(const std::string& pumpName);
+
+private:
+ void getBuildMap(const LLSD& event) const;
+ void showInstance(const LLSD& event) const;
+ void hideInstance(const LLSD& event) const;
+ void toggleInstance(const LLSD& event) const;
+ void clickButton(const LLSD& event) const;
+};
+
+#endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp
index 3483bac782..abb0b869eb 100644
--- a/indra/llui/llflyoutbutton.cpp
+++ b/indra/llui/llflyoutbutton.cpp
@@ -48,6 +48,7 @@ LLFlyoutButton::LLFlyoutButton(const Params& p)
// Text label button
LLButton::Params bp(p.action_button);
bp.name(p.label);
+ bp.label(p.label);
bp.rect.left(0).bottom(0).width(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH).height(getRect().getHeight());
bp.click_callback.function(boost::bind(&LLFlyoutButton::onActionButtonClick, this, _2));
bp.follows.flags(FOLLOWS_ALL);
diff --git a/indra/llui/llfunctorregistry.cpp b/indra/llui/llfunctorregistry.cpp
index 0c5b1655b1..5f9644f258 100644
--- a/indra/llui/llfunctorregistry.cpp
+++ b/indra/llui/llfunctorregistry.cpp
@@ -31,6 +31,7 @@
* $/LicenseInfo$
**/
+#include "linden_common.h"
#include "llfunctorregistry.h"
// This is a default functor always resident in the system.
diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h
index 10a7fd4544..899f6b9326 100644
--- a/indra/llui/llhandle.h
+++ b/indra/llui/llhandle.h
@@ -60,7 +60,7 @@ template <typename T>
class LLHandle
{
public:
- LLHandle() : mTombStone(sDefaultTombStone) {}
+ LLHandle() : mTombStone(getDefaultTombStone()) {}
const LLHandle<T>& operator =(const LLHandle<T>& other)
{
mTombStone = other.mTombStone;
@@ -74,7 +74,7 @@ public:
void markDead()
{
- mTombStone = sDefaultTombStone;
+ mTombStone = getDefaultTombStone();
}
T* get() const
@@ -104,13 +104,13 @@ protected:
LLPointer<LLTombStone<T> > mTombStone;
private:
- static LLPointer<LLTombStone<T> > sDefaultTombStone;
+ static LLPointer<LLTombStone<T> >& getDefaultTombStone()
+ {
+ static LLPointer<LLTombStone<T> > sDefaultTombStone = new LLTombStone<T>;
+ return sDefaultTombStone;
+ }
};
-// initialize static "empty" tombstone pointer
-template <typename T> LLPointer<LLTombStone<T> > LLHandle<T>::sDefaultTombStone = new LLTombStone<T>();
-
-
template <typename T>
class LLRootHandle : public LLHandle<T>
{
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 0330a2b374..b1bd2b89a9 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -56,7 +56,10 @@ LLIconCtrl::Params::Params()
LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
: LLUICtrl(p),
mColor(p.color()),
- mImagep(p.image)
+ mImagep(p.image),
+ mPriority(0),
+ mDrawWidth(0),
+ mDrawHeight(0)
{
if (mImagep.notNull())
{
@@ -93,12 +96,14 @@ void LLIconCtrl::setValue(const LLSD& value )
LLUICtrl::setValue(tvalue);
if (tvalue.isUUID())
{
- mImagep = LLUI::getUIImageByID(tvalue.asUUID());
+ mImagep = LLUI::getUIImageByID(tvalue.asUUID(), mPriority);
}
else
{
- mImagep = LLUI::getUIImage(tvalue.asString());
+ mImagep = LLUI::getUIImage(tvalue.asString(), mPriority);
}
+
+ setIconImageDrawSize();
}
std::string LLIconCtrl::getImageName() const
@@ -108,3 +113,15 @@ std::string LLIconCtrl::getImageName() const
else
return std::string();
}
+
+void LLIconCtrl::setIconImageDrawSize()
+{
+ if(mImagep.notNull() && mDrawWidth && mDrawHeight)
+ {
+ if(mImagep->getImage().notNull())
+ {
+ mImagep->getImage()->setKnownDrawSize(mDrawWidth, mDrawHeight) ;
+ }
+ }
+}
+
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index ff25b0d53e..66368f979b 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -60,6 +60,7 @@ public:
protected:
LLIconCtrl(const Params&);
friend class LLUICtrlFactory;
+
public:
virtual ~LLIconCtrl();
@@ -72,10 +73,20 @@ public:
std::string getImageName() const;
void setColor(const LLColor4& color) { mColor = color; }
+
+private:
+ void setIconImageDrawSize() ;
+
+protected:
+ S32 mPriority;
+
+ //the output size of the icon image if set.
+ S32 mDrawWidth ;
+ S32 mDrawHeight ;
private:
LLUIColor mColor;
- LLPointer<LLUIImage> mImagep;
+ LLPointer<LLUIImage> mImagep;
};
#endif
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 5eade72b61..bac5491943 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -229,7 +229,7 @@ static void get_attribute_bool_and_write(LLXMLNodePtr node,
LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
{
LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack>());
- LLXUIParser::instance().readXUI(node, p);
+ LLXUIParser::instance().readXUI(node, p, LLUICtrlFactory::getInstance()->getCurFileName());
// Export must happen before setupParams() mungles rectangles and before
// this item gets added to parent (otherwise screws up last_child_rect
@@ -401,6 +401,16 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
panel_container->mCollapsed = collapsed;
}
+void LLLayoutStack::updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize)
+{
+ LayoutPanel* panel = findEmbeddedPanelByName(panel_name);
+
+ if (panel)
+ {
+ panel->mAutoResize = auto_resize;
+ }
+}
+
void LLLayoutStack::updateLayout(BOOL force_resize)
{
static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);
@@ -713,6 +723,24 @@ LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) co
return NULL;
}
+LLLayoutStack::LayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) const
+{
+ LayoutPanel* result = NULL;
+
+ for (e_panel_list_t::const_iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+ {
+ LayoutPanel* p = *panel_it;
+
+ if (p->mPanel->getName() == name)
+ {
+ result = p;
+ break;
+ }
+ }
+
+ return result;
+}
+
// Compute sum of min_width or min_height of children
void LLLayoutStack::calcMinExtents()
{
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 49cbe7270f..9ded48ef6a 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -80,6 +80,7 @@ public:
void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
S32 getNumPanels() { return mPanels.size(); }
+ void updatePanelAutoResize(const std::string& panel_name, BOOL auto_resize);
protected:
LLLayoutStack(const Params&);
friend class LLUICtrlFactory;
@@ -96,7 +97,9 @@ private:
typedef std::vector<LayoutPanel*> e_panel_list_t;
e_panel_list_t mPanels;
+
LayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
+ LayoutPanel* findEmbeddedPanelByName(const std::string& name) const;
S32 mMinWidth; // calculated by calcMinExtents
S32 mMinHeight; // calculated by calcMinExtents
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 693ea5bb45..75905d0927 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -148,6 +148,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mBgImage( p.background_image ),
mBgImageDisabled( p.background_image_disabled ),
mBgImageFocused( p.background_image_focused ),
+ mHaveHistory(FALSE),
mReplaceNewlinesWithSpaces( TRUE ),
mLabel(p.label),
mCursorColor(p.cursor_color()),
@@ -164,13 +165,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mTripleClickTimer.reset();
setText(p.default_text());
- // line history support:
- // - initialize line history list
- mLineHistory.insert( mLineHistory.end(), "" );
- // - disable line history by default
- mHaveHistory = FALSE;
- // - reset current history line pointer
- mCurrentHistoryLine = 0;
+ // Initialize current history line iterator
+ mCurrentHistoryLine = mLineHistory.begin();
LLRect border_rect(getLocalRect());
// adjust for gl line drawing glitch
@@ -278,16 +274,31 @@ void LLLineEditor::updateHistory()
// reset current history line number.
// Be sure only to remember lines that are not empty and that are
// different from the last on the list.
- if( mHaveHistory && mText.length() && ( mLineHistory.empty() || getText() != mLineHistory.back() ) )
+ if( mHaveHistory && getLength() )
{
- // discard possible empty line at the end of the history
- // inserted by setText()
- if( !mLineHistory.back().length() )
+ if( !mLineHistory.empty() )
{
- mLineHistory.pop_back();
+ // When not empty, last line of history should always be blank.
+ if( mLineHistory.back().empty() )
+ {
+ // discard the empty line
+ mLineHistory.pop_back();
+ }
+ else
+ {
+ LL_WARNS("") << "Last line of history was not blank." << LL_ENDL;
+ }
+ }
+
+ // Add text to history, ignoring duplicates
+ if( mLineHistory.empty() || getText() != mLineHistory.back() )
+ {
+ mLineHistory.push_back( getText() );
}
- mLineHistory.insert( mLineHistory.end(), getText() );
- mCurrentHistoryLine = mLineHistory.size() - 1;
+
+ // Restore the blank line and set mCurrentHistoryLine to point at it
+ mLineHistory.push_back( "" );
+ mCurrentHistoryLine = mLineHistory.end() - 1;
}
}
@@ -357,11 +368,8 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
}
setCursor(llmin((S32)mText.length(), getCursor()));
- // Newly set text goes always in the last line of history.
- // Possible empty strings (as with chat line) will be deleted later.
- mLineHistory.insert( mLineHistory.end(), new_text );
// Set current history line to end of history.
- mCurrentHistoryLine = mLineHistory.size() - 1;
+ mCurrentHistoryLine = mLineHistory.end() - 1;
mPrevText = mText;
}
@@ -1254,9 +1262,9 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
case KEY_UP:
if( mHaveHistory && ( MASK_CONTROL == mask ) )
{
- if( mCurrentHistoryLine > 0 )
+ if( mCurrentHistoryLine > mLineHistory.begin() )
{
- mText.assign( mLineHistory[ --mCurrentHistoryLine ] );
+ mText.assign( *(--mCurrentHistoryLine) );
setCursor(llmin((S32)mText.length(), getCursor()));
}
else
@@ -1271,9 +1279,9 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
case KEY_DOWN:
if( mHaveHistory && ( MASK_CONTROL == mask ) )
{
- if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.size() - 1 )
+ if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.end() - 1 )
{
- mText.assign( mLineHistory[ ++mCurrentHistoryLine ] );
+ mText.assign( *(++mCurrentHistoryLine) );
setCursor(llmin((S32)mText.length(), getCursor()));
}
else
@@ -1536,18 +1544,24 @@ void LLLineEditor::drawBackground()
image = mBgImage;
}
+ F32 alpha = getDrawContext().mAlpha;
// optionally draw programmatic border
if (has_focus)
{
+ LLColor4 tmp_color = gFocusMgr.getFocusColor();
+ tmp_color.setAlpha(alpha);
image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(),
- gFocusMgr.getFocusColor(),
+ tmp_color,
gFocusMgr.getFocusFlashWidth());
}
- image->draw(getLocalRect());
+ LLColor4 tmp_color = UI_VERTEX_COLOR;
+ tmp_color.setAlpha(alpha);
+ image->draw(getLocalRect(), tmp_color);
}
void LLLineEditor::draw()
{
+ F32 alpha = getDrawContext().mAlpha;
S32 text_len = mText.length();
static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0);
static LLUICachedControl<S32> lineeditor_v_pad ("UILineEditorVPad", 0);
@@ -1600,8 +1614,10 @@ void LLLineEditor::draw()
{
text_color = mReadOnlyFgColor.get();
}
+ text_color.setAlpha(alpha);
LLColor4 label_color = mTentativeFgColor.get();
-
+ label_color.setAlpha(alpha);
+
if (hasPreeditString())
{
// Draw preedit markers. This needs to be before drawing letters.
@@ -1624,7 +1640,7 @@ void LLLineEditor::draw()
preedit_pixels_right - preedit_standout_gap - 1,
background.mBottom + preedit_standout_position - preedit_standout_thickness,
(text_color * preedit_standout_brightness
- + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(1.0f));
+ + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(alpha/*1.0f*/));
}
else
{
@@ -1633,7 +1649,7 @@ void LLLineEditor::draw()
preedit_pixels_right - preedit_marker_gap - 1,
background.mBottom + preedit_marker_position - preedit_marker_thickness,
(text_color * preedit_marker_brightness
- + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(1.0f));
+ + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(alpha/*1.0f*/));
}
}
}
@@ -1676,15 +1692,17 @@ void LLLineEditor::draw()
if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )
{
LLColor4 color = mHighlightColor;
+ color.setAlpha(alpha);
// selected middle
S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text);
width = llmin(width, mMaxHPixels - llround(rendered_pixels_right));
gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color);
+ LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );
rendered_text += mGLFont->render(
mText, mScrollHPos + rendered_text,
rendered_pixels_right, text_bottom,
- LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
+ tmp_color,
LLFontGL::LEFT, LLFontGL::BOTTOM,
0,
LLFontGL::NO_SHADOW,
@@ -1750,8 +1768,9 @@ void LLLineEditor::draw()
cursor_right, cursor_bottom, text_color);
if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
{
+ LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );
mGLFont->render(mText, getCursor(), (F32)(cursor_left + lineeditor_cursor_thickness / 2), text_bottom,
- LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
+ tmp_color,
LLFontGL::LEFT, LLFontGL::BOTTOM,
0,
LLFontGL::NO_SHADOW,
@@ -2291,14 +2310,20 @@ BOOL LLLineEditor::hasPreeditString() const
void LLLineEditor::resetPreedit()
{
- if (hasPreeditString())
+ if (hasSelection())
{
- if (hasSelection())
+ if (hasPreeditString())
{
llwarns << "Preedit and selection!" << llendl;
deselect();
}
-
+ else
+ {
+ deleteSelection();
+ }
+ }
+ if (hasPreeditString())
+ {
const S32 preedit_pos = mPreeditPositions.front();
mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos);
mText.insert(preedit_pos, mPreeditOverwrittenWString);
@@ -2500,20 +2525,3 @@ LLWString LLLineEditor::getConvertedText() const
}
return text;
}
-
-namespace LLInitParam
-{
- template<>
- bool ParamCompare<LLLinePrevalidateFunc>::equals(const LLLinePrevalidateFunc &a, const LLLinePrevalidateFunc &b)
- {
- return false;
- }
-
- template<>
- bool ParamCompare<boost::function<void (LLLineEditor *)> >::equals(
- const boost::function<void (LLLineEditor *)> &a,
- const boost::function<void (LLLineEditor *)> &b)
- {
- return false;
- }
-}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 48d68b9935..d3daa941cf 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -172,6 +172,8 @@ public:
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; }
+ const std::string& getLabel() { return mLabel.getString(); }
+
void setText(const LLStringExplicit &new_text);
const std::string& getText() const { return mText.getString(); }
@@ -286,8 +288,9 @@ protected:
// line history support:
BOOL mHaveHistory; // flag for enabled line history
- std::vector<std::string> mLineHistory; // line history storage
- U32 mCurrentHistoryLine; // currently browsed history line
+ typedef std::vector<std::string> line_history_t;
+ line_history_t mLineHistory; // line history storage
+ line_history_t::iterator mCurrentHistoryLine; // currently browsed history line
LLViewBorder* mBorder;
const LLFontGL* mGLFont;
@@ -390,15 +393,4 @@ private:
}; // end class LLLineEditor
-namespace LLInitParam
-{
- template<>
- bool ParamCompare<LLLinePrevalidateFunc>::equals(
- const LLLinePrevalidateFunc &a, const LLLinePrevalidateFunc &b);
-
- template<>
- bool ParamCompare<boost::function<void (LLLineEditor *)> >::equals(
- const boost::function<void (LLLineEditor *)> &a, const boost::function<void (LLLineEditor *)> &b);
-}
-
#endif // LL_LINEEDITOR_
diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp
index 058b6ae178..43c21e250c 100644
--- a/indra/llui/lllocalcliprect.cpp
+++ b/indra/llui/lllocalcliprect.cpp
@@ -113,6 +113,9 @@ void LLScreenClipRect::updateScissorRegion()
{
if (sClipRectStack.empty()) return;
+ // finish any deferred calls in the old clipping region
+ gGL.flush();
+
LLRect rect = sClipRectStack.top();
stop_glerror();
S32 x,y,w,h;
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index 8dbcd6e229..a657ed039a 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -85,6 +85,8 @@ void LLMenuButton::toggleMenu()
void LLMenuButton::hideMenu()
{
+ if(!mMenu)
+ return;
mMenu->setVisible(FALSE);
}
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 14bee0465c..956e843987 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -279,47 +279,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
// the current accelerator key and mask to the provided string.
void LLMenuItemGL::appendAcceleratorString( std::string& st ) const
{
- // break early if this is a silly thing to do.
- if( KEY_NONE == mAcceleratorKey )
- {
- return;
- }
-
- // Append any masks
-#ifdef LL_DARWIN
- // Standard Mac names for modifier keys in menu equivalents
- // We could use the symbol characters, but they only exist in certain fonts.
- if( mAcceleratorMask & MASK_CONTROL )
- {
- if ( mAcceleratorMask & MASK_MAC_CONTROL )
- {
- st.append( "Ctrl-" );
- }
- else
- {
- st.append( "Cmd-" ); // Symbol would be "\xE2\x8C\x98"
- }
- }
- if( mAcceleratorMask & MASK_ALT )
- st.append( "Opt-" ); // Symbol would be "\xE2\x8C\xA5"
- if( mAcceleratorMask & MASK_SHIFT )
- st.append( "Shift-" ); // Symbol would be "\xE2\x8C\xA7"
-#else
- if( mAcceleratorMask & MASK_CONTROL )
- st.append( "Ctrl-" );
- if( mAcceleratorMask & MASK_ALT )
- st.append( "Alt-" );
- if( mAcceleratorMask & MASK_SHIFT )
- st.append( "Shift-" );
-#endif
-
- std::string keystr = LLKeyboard::stringFromKey( mAcceleratorKey );
- if ((mAcceleratorMask & MASK_NORMALKEYS) &&
- (keystr[0] == '-' || keystr[0] == '='))
- {
- st.append( " " );
- }
- st.append( keystr );
+ st = LLKeyboard::stringFromAccelerator( mAcceleratorMask, mAcceleratorKey );
LL_DEBUGS("HotKeys") << "appendAcceleratorString: " << st << LL_ENDL;
}
@@ -499,12 +459,6 @@ void LLMenuItemGL::draw( void )
LLColor4 color;
- LLFontGL::ShadowType shadow_style = LLFontGL::NO_SHADOW;
- if (getEnabled() && !mDrawTextDisabled )
- {
- shadow_style = LLFontGL::DROP_SHADOW_SOFT;
- }
-
if ( getEnabled() && getHighlight() )
{
color = mHighlightForeground.get();
@@ -522,26 +476,26 @@ void LLMenuItemGL::draw( void )
if (mBriefItem)
{
mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color,
- LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style );
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL);
}
else
{
if( !mDrawBoolLabel.empty() )
{
mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
}
mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
if( !mDrawAccelLabel.empty() )
{
mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
}
if( !mDrawBranchLabel.empty() )
{
mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
- LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
+ LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
}
}
@@ -1500,12 +1454,6 @@ void LLMenuItemBranchDownGL::draw( void )
gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
}
- LLFontGL::ShadowType shadow_style = LLFontGL::NO_SHADOW;
- if (getEnabled() && !getDrawTextDisabled() )
- {
- shadow_style = LLFontGL::DROP_SHADOW_SOFT;
- }
-
LLColor4 color;
if (getHighlight())
{
@@ -1520,7 +1468,7 @@ void LLMenuItemBranchDownGL::draw( void )
color = mDisabledColor.get();
}
getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
- LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style );
+ LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL);
// underline navigation key only when keyboard navigation has been initiated
@@ -1595,8 +1543,6 @@ LLMenuScrollItem::LLMenuScrollItem(const Params& p)
}
LLButton::Params bparams;
- bparams.label("");
- bparams.label_selected("");
bparams.mouse_opaque(true);
bparams.scale_image(false);
bparams.click_callback(p.scroll_callback);
@@ -2934,8 +2880,8 @@ void hide_top_view( LLView* view )
}
-// x and y are the desired location for the popup, NOT necessarily the
-// mouse location
+// x and y are the desired location for the popup, in the spawning_view's
+// coordinate frame, NOT necessarily the mouse location
// static
void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
{
@@ -3475,7 +3421,7 @@ void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) :
LLFloater(LLSD())
{
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+ S32 floater_header_size = getHeaderHeight();
setName(menup->getName());
setTitle(menup->getLabel());
@@ -3519,7 +3465,6 @@ LLTearOffMenu::~LLTearOffMenu()
void LLTearOffMenu::draw()
{
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
mMenu->setBackgroundVisible(isBackgroundOpaque());
mMenu->needsArrange();
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 48887ec352..09d9e407c7 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -505,7 +505,7 @@ public:
void buildDrawLabels();
void createJumpKeys();
- // Show popup at a specific location.
+ // Show popup at a specific location, in the spawn_view's coordinate frame
static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y);
// Whether to drop shadow menu bar
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index f77ec5f4c7..387af05935 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -297,5 +297,16 @@ void LLModalDialog::onAppFocusGained()
}
}
-
-
+void LLModalDialog::shutdownModals()
+{
+ // This method is only for use during app shutdown. ~LLModalDialog()
+ // checks sModalStack, and if the dialog instance is still there, it
+ // crumps with "Attempt to delete dialog while still in sModalStack!" But
+ // at app shutdown, all bets are off. If the user asks to shut down the
+ // app, we shouldn't have to care WHAT's open. Put differently, if a modal
+ // dialog is so crucial that we can't let the user terminate until s/he
+ // addresses it, we should reject a termination request. The current state
+ // of affairs is that we accept it, but then produce an llerrs popup that
+ // simply makes our software look unreliable.
+ sModalStack.clear();
+}
diff --git a/indra/llui/llmodaldialog.h b/indra/llui/llmodaldialog.h
index 9d716a1880..863572fb5a 100644
--- a/indra/llui/llmodaldialog.h
+++ b/indra/llui/llmodaldialog.h
@@ -73,7 +73,8 @@ public:
static void onAppFocusGained();
static S32 activeCount() { return sModalStack.size(); }
-
+ static void shutdownModals();
+
protected:
void centerOnScreen();
diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp
index e8ce1a8d97..78738c826d 100644
--- a/indra/llui/llmultifloater.cpp
+++ b/indra/llui/llmultifloater.cpp
@@ -54,7 +54,8 @@ LLMultiFloater::LLMultiFloater(const LLSD& key, const LLFloater::Params& params)
void LLMultiFloater::buildTabContainer()
{
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
LLTabContainer::Params p;
p.name(std::string("Preview Tabs"));
@@ -131,7 +132,8 @@ BOOL LLMultiFloater::closeAllFloaters()
void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
{
static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
S32 new_height = llmax(getRect().getHeight(), content_height + floater_header_size + tabcntr_header_height);
@@ -432,6 +434,7 @@ void LLMultiFloater::onTabSelected()
void LLMultiFloater::setCanResize(BOOL can_resize)
{
LLFloater::setCanResize(can_resize);
+ if (!mTabContainer) return;
if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
{
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
@@ -455,13 +458,16 @@ BOOL LLMultiFloater::postBuild()
}
mTabContainer = getChild<LLTabContainer>("Preview Tabs");
+
+ setCanResize(mResizable);
return TRUE;
}
void LLMultiFloater::updateResizeLimits()
{
static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
- static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
// initialize minimum size constraint to the original xml values.
S32 new_min_width = mOrigMinWidth;
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 25e2475f59..ef222bad60 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -34,11 +34,13 @@
#include "llnotifications.h"
+#include "llxmlnode.h"
#include "lluictrl.h"
#include "lluictrlfactory.h"
#include "lldir.h"
#include "llsdserialize.h"
#include "lltrans.h"
+#include "llnotificationslistener.h"
#include <algorithm>
#include <boost/regex.hpp>
@@ -944,6 +946,8 @@ LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFil
mIgnoreAllNotifications(false)
{
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
+
+ mListener.reset(new LLNotificationsListener(*this));
}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 19895c3293..0d7cb74f70 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -102,7 +102,7 @@
#include "llfunctorregistry.h"
#include "llpointer.h"
#include "llinitparam.h"
-#include "llxmlnode.h"
+#include "llnotificationslistener.h"
class LLNotification;
typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
@@ -160,7 +160,7 @@ public:
LLNotificationForm();
LLNotificationForm(const LLSD& sd);
LLNotificationForm(const std::string& name,
- const LLPointer<LLXMLNode> xml_node);
+ const LLPointer<class LLXMLNode> xml_node);
LLSD asLLSD() const;
@@ -813,9 +813,19 @@ private:
LLNotificationComparator mComparator;
};
-
+// An interface class to provide a clean linker seam to the LLNotifications class.
+// Extend this interface as needed for your use of LLNotifications.
+class LLNotificationsInterface
+{
+public:
+ virtual LLNotificationPtr add(const std::string& name,
+ const LLSD& substitutions,
+ const LLSD& payload,
+ LLNotificationFunctorRegistry::ResponseFunctor functor) = 0;
+};
class LLNotifications :
+ public LLNotificationsInterface,
public LLSingleton<LLNotifications>,
public LLNotificationChannelBase
{
@@ -839,7 +849,7 @@ public:
const LLSD& substitutions,
const LLSD& payload,
const std::string& functor_name);
- LLNotificationPtr add(const std::string& name,
+ /* virtual */ LLNotificationPtr add(const std::string& name,
const LLSD& substitutions,
const LLSD& payload,
LLNotificationFunctorRegistry::ResponseFunctor functor);
@@ -918,6 +928,8 @@ private:
GlobalStringMap mGlobalStrings;
bool mIgnoreAllNotifications;
+
+ boost::scoped_ptr<LLNotificationsListener> mListener;
};
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
new file mode 100644
index 0000000000..75f4d6177d
--- /dev/null
+++ b/indra/llui/llnotificationslistener.cpp
@@ -0,0 +1,55 @@
+/**
+ * @file llnotificationslistener.cpp
+ * @author Brad Kittenbrink
+ * @date 2009-07-08
+ * @brief Implementation for llnotificationslistener.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llnotificationslistener.h"
+
+#include "llnotifications.h"
+
+LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
+ LLDispatchListener("LLNotifications", "op"),
+ mNotifications(notifications)
+{
+ add("requestAdd", &LLNotificationsListener::requestAdd);
+}
+
+void LLNotificationsListener::requestAdd(const LLSD& event_data) const
+{
+ if(event_data.has("reply"))
+ {
+ mNotifications.add(event_data["name"],
+ event_data["substitutions"],
+ event_data["payload"],
+ boost::bind(&LLNotificationsListener::NotificationResponder,
+ this,
+ event_data["reply"].asString(),
+ _1, _2
+ )
+ );
+ }
+ else
+ {
+ mNotifications.add(event_data["name"],
+ event_data["substitutions"],
+ event_data["payload"]);
+ }
+}
+
+void LLNotificationsListener::NotificationResponder(const std::string& reply_pump,
+ const LLSD& notification,
+ const LLSD& response) const
+{
+ LLSD reponse_event;
+ reponse_event["notification"] = notification;
+ reponse_event["response"] = response;
+ LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
+}
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
new file mode 100644
index 0000000000..6f71a7c781
--- /dev/null
+++ b/indra/llui/llnotificationslistener.h
@@ -0,0 +1,34 @@
+/**
+ * @file llnotificationslistener.h
+ * @author Brad Kittenbrink
+ * @date 2009-07-08
+ * @brief Wrap subset of LLNotifications API in event API for test scripts.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLNOTIFICATIONSLISTENER_H
+#define LL_LLNOTIFICATIONSLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLNotifications;
+class LLSD;
+
+class LLNotificationsListener : public LLDispatchListener
+{
+public:
+ LLNotificationsListener(LLNotifications & notifications);
+
+ void requestAdd(LLSD const & event_data) const;
+
+private:
+ void NotificationResponder(const std::string& replypump,
+ const LLSD& notification,
+ const LLSD& response) const;
+ LLNotifications & mNotifications;
+};
+
+#endif // LL_LLNOTIFICATIONSLISTENER_H
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 69ff3dddc3..07c0f3ce84 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -71,10 +71,12 @@ const LLPanel::Params& LLPanel::getDefaultParams()
LLPanel::Params::Params()
: has_border("border", false),
border(""),
- bg_opaque_color("bg_opaque_color"),
- bg_alpha_color("bg_alpha_color"),
background_visible("background_visible", false),
background_opaque("background_opaque", false),
+ bg_opaque_color("bg_opaque_color"),
+ bg_alpha_color("bg_alpha_color"),
+ bg_opaque_image("bg_opaque_image"),
+ bg_alpha_image("bg_alpha_image"),
min_width("min_width", 100),
min_height("min_height", 100),
strings("string"),
@@ -92,10 +94,12 @@ LLPanel::Params::Params()
LLPanel::LLPanel(const LLPanel::Params& p)
: LLUICtrl(p),
- mBgColorAlpha(p.bg_alpha_color()),
- mBgColorOpaque(p.bg_opaque_color()),
mBgVisible(p.background_visible),
mBgOpaque(p.background_opaque),
+ mBgOpaqueColor(p.bg_opaque_color()),
+ mBgAlphaColor(p.bg_alpha_color()),
+ mBgOpaqueImage(p.bg_opaque_image()),
+ mBgAlphaImage(p.bg_alpha_image()),
mDefaultBtn(NULL),
mBorder(NULL),
mLabel(p.label),
@@ -103,9 +107,9 @@ LLPanel::LLPanel(const LLPanel::Params& p)
mCommitCallbackRegistrar(false),
mEnableCallbackRegistrar(false),
mXMLFilename(p.filename)
+ // *NOTE: Be sure to also change LLPanel::initFromParams(). We have too
+ // many classes derived from LLPanel to retrofit them all to pass in params.
{
- setIsChrome(FALSE);
-
if (p.has_border)
{
addBorder(p.border);
@@ -178,19 +182,31 @@ void LLPanel::draw()
// draw background
if( mBgVisible )
{
- //RN: I don't see the point of this
- S32 left = 0;//LLPANEL_BORDER_WIDTH;
- S32 top = getRect().getHeight();// - LLPANEL_BORDER_WIDTH;
- S32 right = getRect().getWidth();// - LLPANEL_BORDER_WIDTH;
- S32 bottom = 0;//LLPANEL_BORDER_WIDTH;
-
+ LLRect local_rect = getLocalRect();
if (mBgOpaque )
{
- gl_rect_2d( left, top, right, bottom, mBgColorOpaque.get() % alpha);
+ // opaque, in-front look
+ if (mBgOpaqueImage.notNull())
+ {
+ mBgOpaqueImage->draw( local_rect, UI_VERTEX_COLOR % alpha );
+ }
+ else
+ {
+ // fallback to flat colors when there are no images
+ gl_rect_2d( local_rect, mBgOpaqueColor.get() % alpha);
+ }
}
else
{
- gl_rect_2d( left, top, right, bottom, mBgColorAlpha.get() % alpha);
+ // transparent, in-back look
+ if (mBgAlphaImage.notNull())
+ {
+ mBgAlphaImage->draw( local_rect, UI_VERTEX_COLOR % alpha );
+ }
+ else
+ {
+ gl_rect_2d( local_rect, mBgAlphaColor.get() % alpha );
+ }
}
}
@@ -443,7 +459,8 @@ void LLPanel::initFromParams(const LLPanel::Params& p)
setBackgroundOpaque(p.background_opaque);
setBackgroundColor(p.bg_opaque_color().get());
setTransparentColor(p.bg_alpha_color().get());
-
+ mBgOpaqueImage = p.bg_opaque_image();
+ mBgAlphaImage = p.bg_alpha_image();
}
static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup");
@@ -474,7 +491,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
{
//if we are exporting, we want to export the current xml
//not the referenced xml
- LLXUIParser::instance().readXUI(node, params);
+ LLXUIParser::instance().readXUI(node, params, xml_filename);
Params output_params(params);
setupParamsForExport(output_params, parent);
output_node->setName(node->getName()->mString);
@@ -490,14 +507,15 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu
return FALSE;
}
- LLXUIParser::instance().readXUI(referenced_xml, params);
+ LLXUIParser::instance().readXUI(referenced_xml, params, xml_filename);
// add children using dimensions from referenced xml for consistent layout
setShape(params.rect);
LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance());
}
- LLXUIParser::instance().readXUI(node, params);
+ // ask LLUICtrlFactory for filename, since xml_filename might be empty
+ LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
if (output_node)
{
@@ -810,6 +828,47 @@ LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const
return NULL;
}
+static LLPanel *childGetVisibleTabWithHelp(LLView *parent)
+{
+ LLView *child;
+
+ // look through immediate children first for an active tab with help
+ for (child = parent->getFirstChild(); child; child = parent->findNextSibling(child))
+ {
+ LLTabContainer *tab = dynamic_cast<LLTabContainer *>(child);
+ if (tab && tab->getVisible())
+ {
+ LLPanel *curTabPanel = tab->getCurrentPanel();
+ if (curTabPanel && !curTabPanel->getHelpTopic().empty())
+ {
+ return curTabPanel;
+ }
+ }
+ }
+
+ // 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);
+}
+
void LLPanel::childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWString &) )
{
LLLineEditor* child = findChild<LLLineEditor>(id);
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 0594762333..c213809d68 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -48,6 +48,7 @@ const BOOL BORDER_YES = TRUE;
const BOOL BORDER_NO = FALSE;
class LLButton;
+class LLUIImage;
/*
* General purpose concrete view base class.
@@ -72,12 +73,15 @@ public:
Optional<bool> has_border;
Optional<LLViewBorder::Params> border;
- Optional<LLUIColor> bg_opaque_color,
- bg_alpha_color;
-
Optional<bool> background_visible,
background_opaque;
+ Optional<LLUIColor> bg_opaque_color,
+ bg_alpha_color;
+ // opaque image is for "panel in foreground" look
+ Optional<LLUIImage*> bg_opaque_image,
+ bg_alpha_image;
+
Optional<S32> min_width,
min_height;
@@ -127,10 +131,12 @@ public:
BOOL hasBorder() const { return mBorder != NULL; }
void setBorderVisible( BOOL b );
- void setBackgroundColor( const LLColor4& color ) { mBgColorOpaque = color; }
- const LLColor4& getBackgroundColor() const { return mBgColorOpaque; }
- void setTransparentColor(const LLColor4& color) { mBgColorAlpha = color; }
- const LLColor4& getTransparentColor() const { return mBgColorAlpha; }
+ void setBackgroundColor( const LLColor4& color ) { mBgOpaqueColor = color; }
+ const LLColor4& getBackgroundColor() const { return mBgOpaqueColor; }
+ void setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; }
+ const LLColor4& getTransparentColor() const { return mBgAlphaColor; }
+ LLPointer<LLUIImage> getBackgroundImage() const { return mBgOpaqueImage; }
+ LLPointer<LLUIImage> getTransparentImage() const { return mBgAlphaImage; }
void setBackgroundVisible( BOOL b ) { mBgVisible = b; }
BOOL isBackgroundVisible() const { return mBgVisible; }
void setBackgroundOpaque(BOOL b) { mBgOpaque = b; }
@@ -208,6 +214,7 @@ public:
// LLTabContainer
void childShowTab(const std::string& id, const std::string& tabname, bool visible = true);
LLPanel *childGetVisibleTab(const std::string& id) const;
+ LLPanel *childGetVisibleTabWithHelp();
// LLTextBox/LLTextEditor/LLLineEditor
void childSetText(const std::string& id, const LLStringExplicit& text) { childSetValue(id, LLSD(text)); }
@@ -247,10 +254,12 @@ protected:
std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer
private:
- LLUIColor mBgColorAlpha;
- LLUIColor mBgColorOpaque;
- BOOL mBgVisible;
- BOOL mBgOpaque;
+ BOOL mBgVisible; // any background at all?
+ BOOL mBgOpaque; // use opaque color or image
+ LLUIColor mBgOpaqueColor;
+ LLUIColor mBgAlphaColor;
+ LLPointer<LLUIImage> mBgOpaqueImage; // "panel in front" look
+ LLPointer<LLUIImage> mBgAlphaImage; // "panel in back" look
LLViewBorder* mBorder;
LLButton* mDefaultBtn;
LLUIString mLabel;
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index f9f0307d17..86bd2f05ce 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -106,7 +106,7 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled)
child->setEnabled(enabled);
if (index == mSelectedIndex && enabled == FALSE)
{
- mSelectedIndex = -1;
+ setSelectedIndex(-1);
}
break;
}
diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp
index a4e23a605b..ed870d46d5 100644
--- a/indra/llui/llresmgr.cpp
+++ b/indra/llui/llresmgr.cpp
@@ -279,6 +279,14 @@ std::string LLResMgr::getMonetaryString( S32 input ) const
void LLResMgr::getIntegerString( std::string& output, S32 input ) const
{
+ // handle special case of input value being zero
+ if (input == 0)
+ {
+ output = "0";
+ return;
+ }
+
+ // *NOTE: this method does not handle negative input integers correctly
S32 fraction = 0;
std::string fraction_string;
S32 remaining_count = input;
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index cf23e3af15..7e3d4b92d3 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -108,7 +108,8 @@ void LLRNGWriter::addDefinition(const std::string& type_name, const LLInitParam:
LLXMLNodePtr old_element_node = mElementNode;
LLXMLNodePtr old_child_node = mChildrenNode;
- addDefinition(child_name, (*LLDefaultParamBlockRegistry::instance().getValue(type))());
+ //FIXME: add LLDefaultParamBlockRegistry back when working on schema generation
+ //addDefinition(child_name, (*LLDefaultParamBlockRegistry::instance().getValue(type))());
mElementNode = old_element_node;
mChildrenNode = old_child_node;
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 7db34a0608..dfd315d451 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -149,7 +149,8 @@ void LLScrollbar::setDocParams( S32 size, S32 pos )
updateThumbRect();
}
-void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
+// returns true if document position really changed
+bool LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
{
pos = llclamp(pos, 0, getDocPosMax());
if (pos != mDocPos)
@@ -166,7 +167,9 @@ void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
{
updateThumbRect();
}
+ return true;
}
+ return false;
}
void LLScrollbar::setDocSize(S32 size)
@@ -409,8 +412,8 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
BOOL LLScrollbar::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
- changeLine( clicks * mStepSize, TRUE );
- return TRUE;
+ BOOL handled = changeLine( clicks * mStepSize, TRUE );
+ return handled;
}
BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -452,6 +455,13 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask)
return handled;
}
+BOOL LLScrollbar::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ // just treat a double click as a second click
+ return handleMouseDown(x, y, mask);
+}
+
+
void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent)
{
if (width == getRect().getWidth() && height == getRect().getHeight()) return;
@@ -566,9 +576,9 @@ void LLScrollbar::draw()
} // end draw
-void LLScrollbar::changeLine( S32 delta, BOOL update_thumb )
+bool LLScrollbar::changeLine( S32 delta, BOOL update_thumb )
{
- setDocPos(mDocPos + delta, update_thumb);
+ return setDocPos(mDocPos + delta, update_thumb);
}
void LLScrollbar::setValue(const LLSD& value)
@@ -640,15 +650,3 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data )
{
changeLine( mStepSize, TRUE );
}
-
-
-namespace LLInitParam
-{
- template<>
- bool ParamCompare<boost::function<void (S32, LLScrollbar*)> >::equals(
- const boost::function<void (S32, LLScrollbar*)> &a,
- const boost::function<void (S32, LLScrollbar*)> &b)
- {
- return false;
- }
-}
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index e4c5712fb7..a9f028f9ae 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -93,6 +93,7 @@ public:
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -108,7 +109,7 @@ public:
// How many "lines" the "document" has scrolled.
// 0 <= DocPos <= DocSize - DocVisibile
- void setDocPos( S32 pos, BOOL update_thumb = TRUE );
+ bool setDocPos( S32 pos, BOOL update_thumb = TRUE );
S32 getDocPos() const { return mDocPos; }
BOOL isAtBeginning();
@@ -132,7 +133,7 @@ public:
private:
void updateThumbRect();
- void changeLine(S32 delta, BOOL update_thumb );
+ bool changeLine(S32 delta, BOOL update_thumb );
callback_t mChangeCallback;
@@ -167,11 +168,4 @@ private:
};
-namespace LLInitParam
-{
- template<>
- bool ParamCompare<boost::function<void (S32, LLScrollbar*)> >::equals(
- const boost::function<void (S32, LLScrollbar*)> &a, const boost::function<void (S32, LLScrollbar*)> &b);
-}
-
#endif // LL_SCROLLBAR_H
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 5597d494fe..5e17372fe9 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -235,6 +235,8 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
{
+ if(LLUICtrl::handleScrollWheel(x,y,clicks))
+ return TRUE;
for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
{
// Note: tries vertical and then horizontal
@@ -246,9 +248,7 @@ BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
return TRUE;
}
}
-
- // Eat scroll wheel event (to avoid scrolling nested containers?)
- return TRUE;
+ return FALSE;
}
BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,
@@ -432,7 +432,7 @@ void LLScrollContainer::draw()
LLLocalClipRect clip(LLRect(mInnerRect.mLeft,
mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height,
- visible_width,
+ mInnerRect.mRight - (show_v_scrollbar ? scrollbar_size: 0),
mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0)
));
drawChild(mScrolledView);
diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp
index 13fbe1d576..4f55c0507c 100644
--- a/indra/llui/llscrollingpanellist.cpp
+++ b/indra/llui/llscrollingpanellist.cpp
@@ -50,7 +50,7 @@ void LLScrollingPanelList::clearPanels()
reshape( 1, 1, FALSE );
}
-void LLScrollingPanelList::addPanel( LLScrollingPanel* panel )
+S32 LLScrollingPanelList::addPanel( LLScrollingPanel* panel )
{
addChildInBack( panel );
mPanelList.push_front( panel );
@@ -79,6 +79,8 @@ void LLScrollingPanelList::addPanel( LLScrollingPanel* panel )
childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom);
cur_y -= GAP_BETWEEN_PANELS;
}
+
+ return total_height;
}
void LLScrollingPanelList::removePanel(LLScrollingPanel* panel)
diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h
index 9da15822d0..3abfbcbbe7 100644
--- a/indra/llui/llscrollingpanellist.h
+++ b/indra/llui/llscrollingpanellist.h
@@ -77,7 +77,7 @@ public:
virtual void draw();
void clearPanels();
- void addPanel( LLScrollingPanel* panel );
+ S32 addPanel( LLScrollingPanel* panel );
void removePanel( LLScrollingPanel* panel );
void removePanel( U32 panel_index );
void updatePanels(BOOL allow_modify);
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index 073e14386f..ba53f84877 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -47,6 +47,21 @@ const S32 MIN_COLUMN_WIDTH = 20;
//---------------------------------------------------------------------------
// LLScrollColumnHeader
//---------------------------------------------------------------------------
+LLScrollColumnHeader::Params::Params()
+: column("column")
+{
+ name = "column_header";
+ image_unselected.name("square_btn_32x128.tga");
+ image_selected.name("square_btn_selected_32x128.tga");
+ image_disabled.name("square_btn_32x128.tga");
+ image_disabled_selected.name("square_btn_selected_32x128.tga");
+ image_overlay.name("combobox_arrow.tga");
+ image_overlay_alignment("right");
+ font_halign = LLFontGL::LEFT;
+ tab_stop(false);
+ scale_image(true);
+}
+
LLScrollColumnHeader::LLScrollColumnHeader(const LLScrollColumnHeader::Params& p)
: LLButton(p), // use combobox params to steal images
diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h
index 23318fd7c4..5aef6e8e94 100644
--- a/indra/llui/llscrolllistcolumn.h
+++ b/indra/llui/llscrolllistcolumn.h
@@ -50,20 +50,7 @@ public:
{
Mandatory<LLScrollListColumn*> column;
- Params()
- : column("column")
- {
- name = "column_header";
- image_unselected.name("square_btn_32x128.tga");
- image_selected.name("square_btn_selected_32x128.tga");
- image_disabled.name("square_btn_32x128.tga");
- image_disabled_selected.name("square_btn_selected_32x128.tga");
- image_overlay.name("combobox_arrow.tga");
- image_overlay_alignment("right");
- font_halign = LLFontGL::LEFT;
- tab_stop(false);
- scale_image(true);
- }
+ Params();
};
LLScrollColumnHeader(const Params&);
~LLScrollColumnHeader();
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index 07b6895378..f86776384a 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -43,6 +43,8 @@
#include "lluictrlfactory.h"
static LLDefaultChildRegistry::Register<LLSlider> r1("slider_bar");
+//FIXME: make this into an unregistered template so that code constructed sliders don't
+// have ambigious template lookup problem
LLSlider::Params::Params()
: track_color("track_color"),
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 3ecf629082..ed22c0a47f 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -396,4 +396,3 @@ void LLSliderCtrl::reportInvalidData()
make_ui_sound("UISndBadKeystroke");
}
-
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index b1067ad6f3..b67f753d39 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -44,6 +44,7 @@
#include "lluictrlfactory.h"
#include "llrender.h"
#include "llfloater.h"
+#include "lltrans.h"
//----------------------------------------------------------------------------
@@ -105,19 +106,26 @@ struct LLPlaceHolderPanel : public LLPanel
static LLDefaultChildRegistry::Register<LLPlaceHolderPanel> r1("placeholder");
static LLDefaultChildRegistry::Register<LLTabContainer> r2("tab_container");
+LLTabContainer::TabParams::TabParams()
+: tab_top_image_unselected("tab_top_image_unselected"),
+ tab_top_image_selected("tab_top_image_selected"),
+ tab_bottom_image_unselected("tab_bottom_image_unselected"),
+ tab_bottom_image_selected("tab_bottom_image_selected"),
+ tab_left_image_unselected("tab_left_image_unselected"),
+ tab_left_image_selected("tab_left_image_selected")
+{}
+
LLTabContainer::Params::Params()
: tab_width("tab_width"),
- tab_position("tab_position"),
tab_min_width("tab_min_width"),
tab_max_width("tab_max_width"),
+ tab_height("tab_height"),
+ tab_position("tab_position"),
hide_tabs("hide_tabs", false),
tab_padding_right("tab_padding_right"),
- tab_top_image_unselected("tab_top_image_unselected"),
- tab_top_image_selected("tab_top_image_selected"),
- tab_bottom_image_unselected("tab_bottom_image_unselected"),
- tab_bottom_image_selected("tab_bottom_image_selected"),
- tab_left_image_unselected("tab_left_image_unselected"),
- tab_left_image_selected("tab_left_image_selected")
+ first_tab("first_tab"),
+ middle_tab("middle_tab"),
+ last_tab("last_tab")
{
name(std::string("tab_container"));
mouse_opaque = false;
@@ -136,6 +144,7 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mLockedTabCount(0),
mMinTabWidth(0),
mMaxTabWidth(p.tab_max_width),
+ mTabHeight(p.tab_height),
mPrevArrowBtn(NULL),
mNextArrowBtn(NULL),
mIsVertical( p.tab_position == LEFT ),
@@ -145,12 +154,11 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mRightTabBtnOffset(p.tab_padding_right),
mTotalTabWidth(0),
mTabPosition(p.tab_position),
- mImageTopUnselected(p.tab_top_image_unselected),
- mImageTopSelected(p.tab_top_image_selected),
- mImageBottomUnselected(p.tab_bottom_image_unselected),
- mImageBottomSelected(p.tab_bottom_image_selected),
- mImageLeftUnselected(p.tab_left_image_unselected),
- mImageLeftSelected(p.tab_left_image_selected)
+ mFontHalign(p.font_halign),
+ mFont(p.font),
+ mFirstTabParams(p.first_tab),
+ mMiddleTabParams(p.middle_tab),
+ mLastTabParams(p.last_tab)
{
static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@@ -396,12 +404,6 @@ void LLTabContainer::draw()
}
}
}
- LLUI::pushMatrix();
- {
- LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
- tuple->mButton->draw();
- }
- LLUI::popMatrix();
idx++;
}
@@ -636,12 +638,6 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)
}
}
}
-
- for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
- {
- LLTabTuple* tuple = *iter;
- tuple->mButton->setVisible( FALSE );
- }
}
return handled;
}
@@ -789,6 +785,29 @@ void LLTabContainer::addTabPanel(LLPanel* panelp)
addTabPanel(TabPanelParams().panel(panelp));
}
+// function to update images
+void LLTabContainer::update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos)
+{
+ if (tuple && tuple->mButton)
+ {
+ if (pos == LLTabContainer::TOP)
+ {
+ tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_top_image_unselected));
+ tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_top_image_selected));
+ }
+ else if (pos == LLTabContainer::BOTTOM)
+ {
+ tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_bottom_image_unselected));
+ tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_bottom_image_selected));
+ }
+ else if (pos == LLTabContainer::LEFT)
+ {
+ tuple->mButton->setImageUnselected(static_cast<LLUIImage*>(params.tab_left_image_unselected));
+ tuple->mButton->setImageSelected(static_cast<LLUIImage*>(params.tab_left_image_selected));
+ }
+ }
+}
+
void LLTabContainer::addTabPanel(const TabPanelParams& panel)
{
LLPanel* child = panel.panel();
@@ -802,15 +821,12 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
static LLUICachedControl<S32> tabcntr_button_panel_overlap ("UITabCntrButtonPanelOverlap", 0);
- static LLUICachedControl<S32> tabcntr_tab_height ("UITabCntrTabHeight", 0);
static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
if (child->getParent() == this)
{
// already a child of mine
return;
}
- const LLFontGL* font =
- (mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall());
// Store the original label for possible xml export.
child->setLabel(label);
@@ -820,7 +836,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
S32 button_width = mMinTabWidth;
if (!mIsVertical)
{
- button_width = llclamp(font->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);
+ button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);
}
// Tab panel
@@ -830,14 +846,14 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
{
if( getTabPosition() == LLTabContainer::TOP )
{
- S32 tab_height = mIsVertical ? BTN_HEIGHT : tabcntr_tab_height;
+ S32 tab_height = mIsVertical ? BTN_HEIGHT : mTabHeight;
tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - tabcntr_button_panel_overlap);
tab_panel_bottom = LLPANEL_BORDER_WIDTH;
}
else
{
tab_panel_top = getRect().getHeight() - getTopBorderHeight();
- tab_panel_bottom = (tabcntr_tab_height - tabcntr_button_panel_overlap); // Run to the edge, covering up the border
+ tab_panel_bottom = (mTabHeight - tabcntr_button_panel_overlap); // Run to the edge, covering up the border
}
}
else
@@ -886,15 +902,15 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
}
else if( getTabPosition() == LLTabContainer::TOP )
{
- btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, tabcntr_tab_height );
- tab_img = mImageTopUnselected.get();
- tab_selected_img = mImageTopSelected.get();
+ btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, mTabHeight);
+ tab_img = mMiddleTabParams.tab_top_image_unselected;
+ tab_selected_img = mMiddleTabParams.tab_top_image_selected;
}
else
{
- btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, tabcntr_tab_height );
- tab_img = mImageBottomUnselected.get();
- tab_selected_img = mImageBottomSelected.get();
+ btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, mTabHeight);
+ tab_img = mMiddleTabParams.tab_bottom_image_unselected;
+ tab_selected_img = mMiddleTabParams.tab_bottom_image_selected;
}
LLTextBox* textbox = NULL;
@@ -907,11 +923,11 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
params.name(trimmed_label);
params.rect(btn_rect);
params.initial_value(trimmed_label);
- params.font(font);
+ params.font(mFont);
textbox = LLUICtrlFactory::create<LLTextBox> (params);
LLButton::Params p;
- p.name("");
+ p.name("placeholder");
btn = LLUICtrlFactory::create<LLButton>(p);
}
else
@@ -923,13 +939,14 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.rect(btn_rect);
p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
- p.font(font);
+ p.font(mFont);
p.label(trimmed_label);
- p.image_unselected(mImageLeftUnselected);
- p.image_selected(mImageLeftSelected);
+ p.image_unselected(mMiddleTabParams.tab_left_image_unselected);
+ p.image_selected(mMiddleTabParams.tab_left_image_selected);
p.scale_image(true);
- p.font_halign = LLFontGL::LEFT;
+ p.font_halign = mFontHalign;
p.tab_stop(false);
+ p.label_shadow(false);
if (indent)
{
p.pad_left(indent);
@@ -938,26 +955,22 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
}
else
{
- std::string tooltip = trimmed_label;
- tooltip += "\nAlt-Left arrow for previous tab";
- tooltip += "\nAlt-Right arrow for next tab";
-
LLButton::Params p;
p.name(std::string(child->getName()) + " tab");
p.rect(btn_rect);
p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
- p.font(font);
+ p.font(mFont);
p.label(trimmed_label);
p.visible(false);
- p.tool_tip(tooltip);
p.scale_image(true);
p.image_unselected(tab_img);
p.image_selected(tab_selected_img);
p.tab_stop(false);
+ p.label_shadow(false);
// Try to squeeze in a bit more text
p.pad_left(4);
p.pad_right(2);
- p.font_halign = LLFontGL::LEFT;
+ p.font_halign = mFontHalign;
p.follows.flags = FOLLOWS_LEFT;
p.follows.flags = FOLLOWS_LEFT;
@@ -975,13 +988,38 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM;
}
- btn = LLUICtrlFactory::create<LLButton>(p);
+++ btn = LLUICtrlFactory::create<LLButton>(p);
}
}
LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox );
insertTuple( tuple, insertion_point );
+ // if new tab was added as a first or last tab, update button image
+ // and update button image of any tab it may have affected
+ if (tuple == mTabList.front())
+ {
+ update_images(tuple, mFirstTabParams, getTabPosition());
+
+ if (mTabList.size() == 2)
+ {
+ update_images(mTabList[1], mLastTabParams, getTabPosition());
+ }
+ else if (mTabList.size() > 2)
+ {
+ update_images(mTabList[1], mMiddleTabParams, getTabPosition());
+ }
+ }
+ else if (tuple == mTabList.back())
+ {
+ update_images(tuple, mLastTabParams, getTabPosition());
+
+ if (mTabList.size() > 2)
+ {
+ update_images(mTabList[mTabList.size()-2], mMiddleTabParams, getTabPosition());
+ }
+ }
+
//Don't add button and textbox if tab buttons are invisible(EXT - 576)
if (!getTabsHidden())
{
@@ -1063,7 +1101,17 @@ void LLTabContainer::removeTabPanel(LLPanel* child)
LLTabTuple* tuple = *iter;
if( tuple->mTabPanel == child )
{
- removeChild( tuple->mButton );
+ // update tab button images if removing the first or last tab
+ if ((tuple == mTabList.front()) && (mTabList.size() > 1))
+ {
+ update_images(mTabList[1], mFirstTabParams, getTabPosition());
+ }
+ else if ((tuple == mTabList.back()) && (mTabList.size() > 2))
+ {
+ update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition());
+ }
+
+ removeChild( tuple->mButton );
delete tuple->mButton;
removeChild( tuple->mTabPanel );
@@ -1443,7 +1491,6 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L
if (!mIsVertical)
{
- const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
// remove current width from total tab strip width
mTotalTabWidth -= tuple->mButton->getRect().getWidth();
@@ -1454,7 +1501,7 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L
tuple->mPadding = image_overlay_width;
tuple->mButton->setRightHPad(6);
- tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
+ tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
tuple->mButton->getRect().getHeight());
// add back in button width to total tab strip width
mTotalTabWidth += tuple->mButton->getRect().getWidth();
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 7bbecc1abc..be9c6c7d06 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -61,22 +61,32 @@ public:
static void declareValues();
};
+ struct TabParams : public LLInitParam::Block<TabParams>
+ {
+ Optional<LLUIImage*> tab_top_image_unselected,
+ tab_top_image_selected,
+ tab_bottom_image_unselected,
+ tab_bottom_image_selected,
+ tab_left_image_unselected,
+ tab_left_image_selected;
+ TabParams();
+ };
+
struct Params
: public LLInitParam::Block<Params, LLPanel::Params>
{
Optional<TabPosition, TabPositions> tab_position;
Optional<S32> tab_width,
tab_min_width,
- tab_max_width;
+ tab_max_width,
+ tab_height;
+
Optional<bool> hide_tabs;
Optional<S32> tab_padding_right;
- Optional<LLUIImage*> tab_top_image_unselected,
- tab_top_image_selected,
- tab_bottom_image_unselected,
- tab_bottom_image_selected,
- tab_left_image_unselected,
- tab_left_image_selected;
+ Optional<TabParams> first_tab,
+ middle_tab,
+ last_tab;
Params();
};
@@ -213,6 +223,9 @@ private:
void updateMaxScrollPos();
void commitHoveredButton(S32 x, S32 y);
+ // updates tab button images given the tuple, tab position and the corresponding params
+ void update_images(LLTabTuple* tuple, TabParams params, LLTabContainer::TabPosition pos);
+
// Variables
typedef std::vector<LLTabTuple*> tuple_list_t;
@@ -246,15 +259,16 @@ private:
S32 mMaxTabWidth;
S32 mTotalTabWidth;
+ S32 mTabHeight;
LLFrameTimer mDragAndDropDelayTimer;
+
+ LLFontGL::HAlign mFontHalign;
+ const LLFontGL* mFont;
- LLPointer<LLUIImage> mImageTopUnselected;
- LLPointer<LLUIImage> mImageTopSelected;
- LLPointer<LLUIImage> mImageBottomUnselected;
- LLPointer<LLUIImage> mImageBottomSelected;
- LLPointer<LLUIImage> mImageLeftUnselected;
- LLPointer<LLUIImage> mImageLeftSelected;
+ TabParams mFirstTabParams;
+ TabParams mMiddleTabParams;
+ TabParams mLastTabParams;
};
#endif // LL_TABCONTAINER_H
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index e85bee7775..97ba691341 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -210,8 +210,6 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
scroll_params.mouse_opaque = false;
scroll_params.min_auto_scroll_rate = 200;
scroll_params.max_auto_scroll_rate = 800;
- // all text widgets only show scrollbar on demand
- scroll_params.hide_scrollbar = true;
scroll_params.border_visible = p.border_visible;
mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_params);
addChild(mScroller);
@@ -234,7 +232,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
createDefaultSegment();
- updateTextRect();
+ updateRects();
}
LLTextBase::~LLTextBase()
@@ -342,11 +340,14 @@ void LLTextBase::drawSelectionBackground()
S32 segment_line_start = segmentp->getStart() + segment_offset;
S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
+ S32 segment_width, segment_height;
+
// if selection after beginning of segment
if(selection_left >= segment_line_start)
{
S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start;
- selection_rect.mLeft += segmentp->getWidth(segment_offset, num_chars);
+ segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height);
+ selection_rect.mLeft += segment_width;
}
// if selection spans end of current segment...
@@ -354,13 +355,16 @@ void LLTextBase::drawSelectionBackground()
{
// extend selection slightly beyond end of line
// to indicate selection of newline character (use "n" character to determine width)
- selection_rect.mRight += segmentp->getWidth(segment_offset, segment_line_end - segment_line_start);
+ S32 num_chars = segment_line_end - segment_line_start;
+ segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height);
+ selection_rect.mRight += segment_width;
}
// else if selection ends on current segment...
else
{
S32 num_chars = selection_right - segment_line_start;
- selection_rect.mRight += segmentp->getWidth(segment_offset, num_chars);
+ segmentp->getDimensions(segment_offset, num_chars, segment_width, segment_height);
+ selection_rect.mRight += segment_width;
break;
}
@@ -415,9 +419,6 @@ void LLTextBase::drawCursor()
return;
}
- if (!mTextRect.contains(cursor_rect))
- return;
-
// Draw the cursor
// (Flash the cursor every half second starting a fixed time after the last keystroke)
F32 elapsed = mCursorBlinkTimer.getElapsedTimeF32();
@@ -426,7 +427,9 @@ void LLTextBase::drawCursor()
if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
{
- S32 width = llmax(CURSOR_THICKNESS, segmentp->getWidth(mCursorPos - segmentp->getStart(), 1));
+ S32 segment_width, segment_height;
+ segmentp->getDimensions(mCursorPos - segmentp->getStart(), 1, segment_width, segment_height);
+ S32 width = llmax(CURSOR_THICKNESS, segment_width);
cursor_rect.mRight = cursor_rect.mLeft + width;
}
else
@@ -532,10 +535,6 @@ void LLTextBase::drawText()
next_start = getLineStart(cur_line + 1);
line_end = next_start;
}
- if ( text[line_end-1] == '\n' )
- {
- --line_end;
- }
LLRect text_rect(line.mRect.mLeft + mTextRect.mLeft - scrolled_view_rect.mLeft,
line.mRect.mTop - scrolled_view_rect.mBottom + mTextRect.mBottom,
@@ -934,13 +933,16 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- LLUICtrl::reshape( width, height, called_from_parent );
+ if (width != getRect().getWidth() || height != getRect().getHeight())
+ {
+ LLUICtrl::reshape( width, height, called_from_parent );
- // do this first after reshape, because other things depend on
- // up-to-date mTextRect
- updateTextRect();
-
- needsReflow();
+ // do this first after reshape, because other things depend on
+ // up-to-date mTextRect
+ updateRects();
+
+ needsReflow();
+ }
}
void LLTextBase::draw()
@@ -951,17 +953,27 @@ void LLTextBase::draw()
// then update scroll position, as cursor may have moved
updateScrollFromCursor();
+ LLRect doc_rect;
+ if (mScroller)
+ {
+ mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &doc_rect, this);
+ }
+ else
+ {
+ doc_rect = getLocalRect();
+ }
+
if (mBGVisible)
{
// clip background rect against extents, if we support scrolling
- LLLocalClipRect clip(getLocalRect(), mScroller != NULL);
+ LLLocalClipRect clip(doc_rect, mScroller != NULL);
LLColor4 bg_color = mReadOnly
? mReadOnlyBgColor.get()
: hasFocus()
? mFocusBgColor.get()
: mWriteableBgColor.get();
- gl_rect_2d(mDocumentView->getRect(), bg_color, TRUE);
+ gl_rect_2d(mTextRect, bg_color, TRUE);
}
// draw document view
@@ -969,7 +981,7 @@ void LLTextBase::draw()
{
// only clip if we support scrolling (mScroller != NULL)
- LLLocalClipRect clip(mTextRect, mScroller != NULL);
+ LLLocalClipRect clip(doc_rect, mScroller != NULL);
drawSelectionBackground();
drawText();
drawCursor();
@@ -1022,13 +1034,13 @@ S32 LLTextBase::getLeftOffset(S32 width)
switch (mHAlign)
{
case LLFontGL::LEFT:
- return 0;
+ return mHPad;
case LLFontGL::HCENTER:
- return (mTextRect.getWidth() - width) / 2;
+ return mHPad + (mTextRect.getWidth() - width - mHPad) / 2;
case LLFontGL::RIGHT:
return mTextRect.getWidth() - width;
default:
- return 0;
+ return mHPad;
}
}
@@ -1036,8 +1048,6 @@ S32 LLTextBase::getLeftOffset(S32 width)
static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow");
void LLTextBase::reflow(S32 start_index)
{
- if (!mReflowNeeded) return;
-
LLFastTimer ft(FTM_TEXT_REFLOW);
updateSegments();
@@ -1066,7 +1076,7 @@ void LLTextBase::reflow(S32 start_index)
segment_set_t::iterator seg_iter = mSegments.begin();
S32 seg_offset = 0;
S32 line_start_index = 0;
- const S32 text_width = mTextRect.getWidth(); // optionally reserve room for margin
+ const S32 text_width = mTextRect.getWidth() - mHPad; // reserve room for margin
S32 remaining_pixels = text_width;
LLWString text(getWText());
S32 line_count = 0;
@@ -1089,59 +1099,44 @@ void LLTextBase::reflow(S32 start_index)
LLTextSegmentPtr segment = *seg_iter;
// track maximum height of any segment on this line
- line_height = llmax(line_height, segment->getMaxHeight());
S32 cur_index = segment->getStart() + seg_offset;
- // find run of text from this segment that we can display on one line
- S32 end_index = cur_index;
- while(end_index < segment->getEnd() && text[end_index] != '\n')
- {
- ++end_index;
- }
// ask segment how many character fit in remaining space
- S32 max_characters = end_index - cur_index;
S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, remaining_pixels) : S32_MAX,
seg_offset,
cur_index - line_start_index,
- max_characters);
-
+ S32_MAX);
- S32 segment_width = segment->getWidth(seg_offset, character_count);
+ S32 segment_width, segment_height;
+ bool force_newline = segment->getDimensions(seg_offset, character_count, segment_width, segment_height);
+ // grow line height as necessary based on reported height of this segment
+ line_height = llmax(line_height, segment_height);
remaining_pixels -= segment_width;
- S32 text_left = getLeftOffset(text_width - remaining_pixels);
seg_offset += character_count;
S32 last_segment_char_on_line = segment->getStart() + seg_offset;
+ S32 text_left = getLeftOffset(text_width - remaining_pixels);
+ LLRect line_rect(text_left,
+ cur_top,
+ text_left + (text_width - remaining_pixels),
+ cur_top - line_height);
+
// if we didn't finish the current segment...
if (last_segment_char_on_line < segment->getEnd())
{
- // set up index for next line
- // ...skip newline, we don't want to draw
- S32 next_line_count = line_count;
- if (text[last_segment_char_on_line] == '\n')
- {
- seg_offset++;
- last_segment_char_on_line++;
- next_line_count++;
- }
-
// add line info and keep going
mLineInfoList.push_back(line_info(
line_start_index,
last_segment_char_on_line,
- LLRect(text_left,
- cur_top,
- text_left + (text_width - remaining_pixels),
- cur_top - line_height),
+ line_rect,
line_count));
line_start_index = segment->getStart() + seg_offset;
cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels;
remaining_pixels = text_width;
line_height = 0;
- line_count = next_line_count;
}
// ...just consumed last segment..
else if (++segment_set_t::iterator(seg_iter) == mSegments.end())
@@ -1149,77 +1144,34 @@ void LLTextBase::reflow(S32 start_index)
mLineInfoList.push_back(line_info(
line_start_index,
last_segment_char_on_line,
- LLRect(text_left,
- cur_top,
- text_left + (text_width - remaining_pixels),
- cur_top - line_height),
+ line_rect,
line_count));
cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels;
break;
}
- // finished a segment and there are segments remaining on this line
+ // ...or finished a segment and there are segments remaining on this line
else
{
// subtract pixels used and increment segment
+ if (force_newline)
+ {
+ mLineInfoList.push_back(line_info(
+ line_start_index,
+ last_segment_char_on_line,
+ line_rect,
+ line_count));
+ line_start_index = segment->getStart() + seg_offset;
+ cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels;
+ line_height = 0;
+ remaining_pixels = text_width;
+ }
++seg_iter;
seg_offset = 0;
}
}
- if (mLineInfoList.empty())
- {
- mContentsRect = LLRect(0, mVPad, mHPad, 0);
- }
- else
- {
-
- mContentsRect = mLineInfoList.begin()->mRect;
- for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin();
- line_iter != mLineInfoList.end();
- ++line_iter)
- {
- mContentsRect.unionWith(line_iter->mRect);
- }
-
- mContentsRect.mRight += mHPad;
- mContentsRect.mTop += mVPad;
- // get around rounding errors when clipping text against rectangle
- mContentsRect.stretch(1);
- }
-
- // change mDocumentView size to accomodate reflowed text
- LLRect document_rect;
- if (mScroller)
- {
- // document is size of scroller or size of text contents, whichever is larger
- document_rect.setOriginAndSize(0, 0,
- mScroller->getContentWindowRect().getWidth(),
- llmax(mScroller->getContentWindowRect().getHeight(), mContentsRect.getHeight()));
- }
- else
- {
- // document size is just extents of reflowed text, reset to origin 0,0
- document_rect.set(0,
- getLocalRect().getHeight(),
- getLocalRect().getWidth(),
- llmin(0, getLocalRect().getHeight() - mContentsRect.getHeight()));
- }
- mDocumentView->setShape(document_rect);
-
- // after making document big enough to hold all the text, move the text to fit in the document
- if (!mLineInfoList.empty())
- {
- S32 delta_pos = mDocumentView->getRect().getHeight() - mLineInfoList.begin()->mRect.mTop - mVPad;
- // move line segments to fit new document rect
- for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)
- {
- it->mRect.translate(0, delta_pos);
- }
- mContentsRect.translate(0, delta_pos);
- }
-
// calculate visible region for diplaying text
- updateTextRect();
+ updateRects();
for (segment_set_t::iterator segment_it = mSegments.begin();
segment_it != mSegments.end();
@@ -1256,11 +1208,10 @@ void LLTextBase::reflow(S32 start_index)
//llassert_always(getLocalRectFromDocIndex(mScrollIndex).mBottom == first_char_rect.mBottom);
}
}
- }
-
- // reset desired x cursor position
- updateCursorXPos();
+ // reset desired x cursor position
+ updateCursorXPos();
+ }
}
LLRect LLTextBase::getContentsRect()
@@ -1480,6 +1431,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));
registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url));
registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
+ registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
@@ -1511,9 +1463,7 @@ void LLTextBase::setText(const LLStringExplicit &utf8str)
appendText(text, false);
- //resetDirty();
onValueChange(0, getLength());
- needsReflow();
}
//virtual
@@ -1691,8 +1641,6 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepen
insertStringNoUndo(getLength(), wide_text, &segments);
}
- needsReflow();
-
// Set the cursor and scroll position
if( selection_start != selection_end )
{
@@ -1804,7 +1752,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round
S32 segment_line_start = segmentp->getStart() + line_seg_offset;
S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd - 1) - segment_line_start;
- S32 text_width = segmentp->getWidth(line_seg_offset, segment_line_length);
+ S32 text_width, text_height;
+ segmentp->getDimensions(line_seg_offset, segment_line_length, text_width, text_height);
if (local_x < start_x + text_width // cursor to left of right edge of text
|| segmentp->getEnd() >= line_iter->mDocIndexEnd - 1) // or this segment wraps to next line
{
@@ -1812,7 +1761,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round
S32 offset;
if (!segmentp->canEdit())
{
- S32 segment_width = segmentp->getWidth(0, segmentp->getEnd() - segmentp->getStart());
+ S32 segment_width, segment_height;
+ segmentp->getDimensions(0, segmentp->getEnd() - segmentp->getStart(), segment_width, segment_height);
if (round && local_x - start_x > segment_width / 2)
{
offset = segment_line_length;
@@ -1835,27 +1785,26 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round
return pos;
}
-LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
+// returns rectangle of insertion caret
+// in document coordinate frame from given index into text
+LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
{
- LLRect local_rect;
if (mLineInfoList.empty())
{
- local_rect = mTextRect;
- local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight());
- return local_rect;
+ return LLRect();
}
+ LLRect doc_rect;
+
// clamp pos to valid values
pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1);
-
// find line that contains cursor
line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare());
- LLRect scrolled_view_rect = getVisibleDocumentRect();
- local_rect.mLeft = mTextRect.mLeft - scrolled_view_rect.mLeft + line_iter->mRect.mLeft;
- local_rect.mBottom = mTextRect.mBottom + (line_iter->mRect.mBottom - scrolled_view_rect.mBottom);
- local_rect.mTop = mTextRect.mBottom + (line_iter->mRect.mTop - scrolled_view_rect.mBottom);
+ doc_rect.mLeft = line_iter->mRect.mLeft;
+ doc_rect.mBottom = line_iter->mRect.mBottom;
+ doc_rect.mTop = line_iter->mRect.mTop;
segment_set_t::iterator line_seg_iter;
S32 line_seg_offset;
@@ -1871,14 +1820,18 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
if (line_seg_iter == cursor_seg_iter)
{
// cursor advanced to right based on difference in offset of cursor to start of line
- local_rect.mLeft += segmentp->getWidth(line_seg_offset, cursor_seg_offset - line_seg_offset);
+ S32 segment_width, segment_height;
+ segmentp->getDimensions(line_seg_offset, cursor_seg_offset - line_seg_offset, segment_width, segment_height);
+ doc_rect.mLeft += segment_width;
break;
}
else
{
// add remainder of current text segment to cursor position
- local_rect.mLeft += segmentp->getWidth(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset);
+ S32 segment_width, segment_height;
+ segmentp->getDimensions(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset, segment_width, segment_height);
+ doc_rect.mLeft += segment_width;
// offset will be 0 for all segments after the first
line_seg_offset = 0;
// go to next text segment on this line
@@ -1886,7 +1839,31 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
}
}
- local_rect.mRight = local_rect.mLeft;
+ // set rect to 0 width
+ doc_rect.mRight = doc_rect.mLeft;
+
+ return doc_rect;
+}
+
+LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
+{
+ LLRect local_rect;
+ if (mLineInfoList.empty())
+ {
+ // return default height rect in upper left
+ local_rect = mTextRect;
+ local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight());
+ return local_rect;
+ }
+
+ // get the rect in document coordinates
+ LLRect doc_rect = getDocRectFromDocIndex(pos);
+
+ // compensate for scrolled, inset view of doc
+ LLRect scrolled_view_rect = getVisibleDocumentRect();
+ local_rect = doc_rect;
+ local_rect.translate(mTextRect.mLeft - scrolled_view_rect.mLeft,
+ mTextRect.mBottom - scrolled_view_rect.mBottom);
return local_rect;
}
@@ -2058,8 +2035,44 @@ S32 LLTextBase::getEditableIndex(S32 index, bool increasing_direction)
}
}
-void LLTextBase::updateTextRect()
+void LLTextBase::updateRects()
{
+ if (mLineInfoList.empty())
+ {
+ mContentsRect = LLRect(0, mVPad, mHPad, 0);
+ }
+ else
+ {
+ mContentsRect = mLineInfoList.begin()->mRect;
+ for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin();
+ line_iter != mLineInfoList.end();
+ ++line_iter)
+ {
+ mContentsRect.unionWith(line_iter->mRect);
+ }
+
+ mContentsRect.mLeft = 0;
+ mContentsRect.mTop += mVPad;
+
+ S32 delta_pos = -mContentsRect.mBottom;
+ // move line segments to fit new document rect
+ for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)
+ {
+ it->mRect.translate(0, delta_pos);
+ }
+ mContentsRect.translate(0, delta_pos);
+ }
+
+ // update document container dimensions according to text contents
+ LLRect doc_rect = mContentsRect;
+ // use old mTextRect constraint document to width of viewable region
+ doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth();
+
+ mDocumentView->setShape(doc_rect);
+
+ //update mTextRect *after* mDocumentView has been resized
+ // so that scrollbars are added if document needs to scroll
+ // since mTextRect does not include scrollbars
LLRect old_text_rect = mTextRect;
mTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();
//FIXME: replace border with image?
@@ -2067,12 +2080,14 @@ void LLTextBase::updateTextRect()
{
mTextRect.stretch(-1);
}
- mTextRect.mLeft += mHPad;
- mTextRect.mTop -= mVPad;
if (mTextRect != old_text_rect)
{
needsReflow();
}
+
+ // update document container again, using new mTextRect
+ doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth();
+ mDocumentView->setShape(doc_rect);
}
@@ -2104,9 +2119,12 @@ LLRect LLTextBase::getVisibleDocumentRect() const
}
else
{
- // entire document rect when not scrolling
+ // entire document rect is visible when not scrolling
+ // but offset according to height of widget
LLRect doc_rect = mDocumentView->getLocalRect();
- doc_rect.translate(-mDocumentView->getRect().mLeft, -mDocumentView->getRect().mBottom);
+ doc_rect.mLeft -= mDocumentView->getRect().mLeft;
+ // adjust for height of text above widget baseline
+ doc_rect.mBottom = doc_rect.getHeight() - mTextRect.getHeight();
return doc_rect;
}
}
@@ -2118,12 +2136,11 @@ LLRect LLTextBase::getVisibleDocumentRect() const
LLTextSegment::~LLTextSegment()
{}
-S32 LLTextSegment::getWidth(S32 first_char, S32 num_chars) const { return 0; }
+bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { width = 0; height = 0; return false;}
S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; }
S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { return 0; }
void LLTextSegment::updateLayout(const LLTextBase& editor) {}
F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { return draw_rect.mLeft; }
-S32 LLTextSegment::getMaxHeight() const { return 0; }
bool LLTextSegment::canEdit() const { return false; }
void LLTextSegment::unlinkFromDocument(LLTextBase*) {}
void LLTextSegment::linkToDocument(LLTextBase*) {}
@@ -2161,7 +2178,7 @@ LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32
mToken(NULL),
mEditor(editor)
{
- mMaxHeight = llceil(mStyle->getFont()->getLineHeight());
+ mFontHeight = llceil(mStyle->getFont()->getLineHeight());
}
LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible)
@@ -2171,7 +2188,7 @@ LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32
{
mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color));
- mMaxHeight = llceil(mStyle->getFont()->getLineHeight());
+ mFontHeight = llceil(mStyle->getFont()->getLineHeight());
}
F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
@@ -2202,6 +2219,11 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
const LLWString &text = mEditor.getWText();
+ if ( text[seg_end-1] == '\n' )
+ {
+ --seg_end;
+ }
+
F32 right_x = rect.mLeft;
if (!mStyle->isVisible())
{
@@ -2269,11 +2291,6 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
return right_x;
}
-S32 LLNormalTextSegment::getMaxHeight() const
-{
- return mMaxHeight;
-}
-
BOOL LLNormalTextSegment::handleHover(S32 x, S32 y, MASK mask)
{
if (getStyle() && getStyle()->isLink())
@@ -2294,6 +2311,17 @@ BOOL LLNormalTextSegment::handleRightMouseDown(S32 x, S32 y, MASK mask)
return FALSE;
}
+BOOL LLNormalTextSegment::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (getStyle() && getStyle()->isLink())
+ {
+ // eat mouse down event on hyperlinks, so we get the mouse up
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
BOOL LLNormalTextSegment::handleMouseUp(S32 x, S32 y, MASK mask)
{
if (getStyle() && getStyle()->isLink())
@@ -2336,10 +2364,13 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip)
mTooltip = tooltip;
}
-S32 LLNormalTextSegment::getWidth(S32 first_char, S32 num_chars) const
+bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
{
LLWString text = mEditor.getWText();
- return mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
+
+ height = mFontHeight;
+ width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
+ return num_chars >= 1 && text[mStart + num_chars - 1] == '\n';
}
S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const
@@ -2355,6 +2386,20 @@ S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset,
S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
{
LLWString text = mEditor.getWText();
+
+ // search for newline and if found, truncate there
+ S32 last_char = mStart + segment_offset;
+ for (; last_char != mEnd; ++last_char)
+ {
+ if (text[last_char] == '\n')
+ {
+ break;
+ }
+ }
+
+ // set max characters to length of segment, or to first newline
+ max_chars = llmin(max_chars, last_char - (mStart + segment_offset));
+
S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart,
(F32)num_pixels,
max_chars,
@@ -2367,9 +2412,15 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
// If at the beginning of a line, and a single character won't fit, draw it anyway
num_chars = 1;
}
- if (mStart + segment_offset + num_chars == mEditor.getLength())
+
+ // include *either* the EOF or newline character in this run of text
+ // but not both
+ S32 last_char_in_run = mStart + segment_offset + num_chars;
+ // check length first to avoid indexing off end of string
+ if (last_char_in_run < mEnd
+ && (last_char_in_run >= mEditor.getLength()
+ || text[last_char_in_run] == '\n'))
{
- // include terminating NULL
num_chars++;
}
return num_chars;
@@ -2391,9 +2442,14 @@ void LLNormalTextSegment::dump() const
// LLInlineViewSegment
//
-LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end)
+LLInlineViewSegment::LLInlineViewSegment(const Params& p, S32 start, S32 end)
: LLTextSegment(start, end),
- mView(view)
+ mView(p.view),
+ mForceNewLine(p.force_newline),
+ mLeftPad(p.left_pad),
+ mRightPad(p.right_pad),
+ mTopPad(p.top_pad),
+ mBottomPad(p.bottom_pad)
{
}
@@ -2402,21 +2458,31 @@ LLInlineViewSegment::~LLInlineViewSegment()
mView->die();
}
-S32 LLInlineViewSegment::getWidth(S32 first_char, S32 num_chars) const
+bool LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
{
if (first_char == 0 && num_chars == 0)
{
- return 0;
+ // we didn't fit on a line, the widget will fall on the next line
+ // so dimensions here are 0
+ width = 0;
+ height = 0;
}
else
{
- return mView->getRect().getWidth();
+ width = mLeftPad + mRightPad + mView->getRect().getWidth();
+ height = mBottomPad + mTopPad + mView->getRect().getHeight();
}
+
+ return false;
}
S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
{
- if (line_offset != 0 && num_pixels < mView->getRect().getWidth())
+ // if putting a widget anywhere but at the beginning of a line
+ // and the widget doesn't fit or mForceNewLine is true
+ // then return 0 chars for that line, and all characters for the next
+ if (line_offset != 0
+ && (mForceNewLine || num_pixels < mView->getRect().getWidth()))
{
return 0;
}
@@ -2428,19 +2494,15 @@ S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
void LLInlineViewSegment::updateLayout(const LLTextBase& editor)
{
- LLRect start_rect = editor.getLocalRectFromDocIndex(mStart);
- LLRect doc_rect = editor.getDocumentView()->getRect();
- mView->setOrigin(doc_rect.mLeft + start_rect.mLeft, doc_rect.mBottom + start_rect.mBottom);
+ LLRect start_rect = editor.getDocRectFromDocIndex(mStart);
+ mView->setOrigin(start_rect.mLeft + mLeftPad, start_rect.mBottom + mBottomPad);
}
F32 LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
{
- return (F32)(draw_rect.mLeft + mView->getRect().getWidth());
-}
-
-S32 LLInlineViewSegment::getMaxHeight() const
-{
- return mView->getRect().getHeight();
+ // return padded width of widget
+ // widget is actually drawn during mDocumentView's draw()
+ return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mLeftPad + mRightPad);
}
void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor)
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 903396c78a..8cae8fde22 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -154,9 +154,13 @@ public:
LLRect getContentsRect();
LLRect getVisibleDocumentRect() const;
+ S32 getVPad() { return mVPad; }
+ S32 getHPad() { return mHPad; }
+
S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const;
LLRect getLocalRectFromDocIndex(S32 pos) const;
+ LLRect getDocRectFromDocIndex(S32 pos) const;
void setReadOnly(bool read_only) { mReadOnly = read_only; }
bool getReadOnly() { return mReadOnly; }
@@ -293,7 +297,7 @@ protected:
void endSelection();
// misc
- void updateTextRect();
+ void updateRects();
void needsReflow() { mReflowNeeded = TRUE; }
void needsScroll() { mScrollNeeded = TRUE; }
void replaceUrlLabel(const std::string &url, const std::string &label);
@@ -366,12 +370,11 @@ public:
LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){};
virtual ~LLTextSegment();
- virtual S32 getWidth(S32 first_char, S32 num_chars) const;
+ virtual bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
virtual void updateLayout(const class LLTextBase& editor);
virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
- virtual S32 getMaxHeight() const;
virtual bool canEdit() const;
virtual void unlinkFromDocument(class LLTextBase* editor);
virtual void linkToDocument(class LLTextBase* editor);
@@ -418,11 +421,10 @@ public:
LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor );
LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
- /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const;
+ /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
- /*virtual*/ S32 getMaxHeight() const;
/*virtual*/ bool canEdit() const { return true; }
/*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); }
/*virtual*/ void setColor(const LLColor4 &color) { mStyle->setColor(color); }
@@ -436,6 +438,7 @@ public:
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
@@ -445,7 +448,7 @@ protected:
protected:
class LLTextBase& mEditor;
LLStyleSP mStyle;
- S32 mMaxHeight;
+ S32 mFontHeight;
LLKeywordToken* mToken;
std::string mTooltip;
};
@@ -459,19 +462,33 @@ public:
class LLInlineViewSegment : public LLTextSegment
{
public:
- LLInlineViewSegment(LLView* widget, S32 start, S32 end);
+ struct Params : public LLInitParam::Block<Params>
+ {
+ Mandatory<LLView*> view;
+ Optional<bool> force_newline;
+ Optional<S32> left_pad,
+ right_pad,
+ bottom_pad,
+ top_pad;
+ };
+
+ LLInlineViewSegment(const Params& p, S32 start, S32 end);
~LLInlineViewSegment();
- /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const;
+ /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
/*virtual*/ void updateLayout(const class LLTextBase& editor);
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
- /*virtuaL*/ S32 getMaxHeight() const;
/*virtual*/ bool canEdit() const { return false; }
/*virtual*/ void unlinkFromDocument(class LLTextBase* editor);
/*virtual*/ void linkToDocument(class LLTextBase* editor);
private:
+ S32 mLeftPad;
+ S32 mRightPad;
+ S32 mTopPad;
+ S32 mBottomPad;
LLView* mView;
+ bool mForceNewLine;
};
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 20bceb4675..00f1d833a3 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -45,6 +45,9 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p)
mClickedCallback(NULL)
{}
+LLTextBox::~LLTextBox()
+{}
+
BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = LLTextBase::handleMouseDown(x, y, mask);
@@ -97,6 +100,18 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask)
return handled;
}
+BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = LLTextBase::handleHover(x, y, mask);
+ if (!handled && mClickedCallback)
+ {
+ // Clickable text boxes change the cursor to a hand
+ LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
+ return TRUE;
+ }
+ return handled;
+}
+
void LLTextBox::setText(const LLStringExplicit& text)
{
// does string argument insertion
@@ -105,6 +120,11 @@ void LLTextBox::setText(const LLStringExplicit& text)
LLTextBase::setText(mText.getString());
}
+void LLTextBox::setClickedCallback( boost::function<void (void*)> cb, void* userdata /*= NULL */ )
+{
+ mClickedCallback = boost::bind(cb, userdata);
+}
+
S32 LLTextBox::getTextPixelWidth()
{
return getContentsRect().getWidth();
@@ -115,6 +135,12 @@ S32 LLTextBox::getTextPixelHeight()
return getContentsRect().getHeight();
}
+
+LLSD LLTextBox::getValue() const
+{
+ return LLSD(getText());
+}
+
BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text )
{
mText.setArg(key, text);
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index da0bcbe972..73f8a7c299 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -33,8 +33,6 @@
#ifndef LL_LLTEXTBOX_H
#define LL_LLTEXTBOX_H
-#include "v4color.h"
-#include "llstring.h"
#include "lluistring.h"
#include "lltextbase.h"
@@ -54,28 +52,25 @@ protected:
friend class LLUICtrlFactory;
public:
- virtual ~LLTextBox() {}
+ virtual ~LLTextBox();
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
- /*virtual*/ void setText( const LLStringExplicit& text );
+ /*virtual*/ void setText( const LLStringExplicit& text );
void setRightAlign() { mHAlign = LLFontGL::RIGHT; }
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
- void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); } // mouse down and up within button
-
- //const LLFontGL* getFont() const { return mDefaultFont; }
- //void setFont(const LLFontGL* font) { mDefaultFont = font; }
+ void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL );
void reshapeToFitText();
- //const std::string& getText() const { return mText.getString(); }
S32 getTextPixelWidth();
S32 getTextPixelHeight();
- virtual LLSD getValue() const { return LLSD(getText()); }
- virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text );
+ /*virtual*/ LLSD getValue() const;
+ /*virtual*/ BOOL setTextArg( const std::string& key, const LLStringExplicit& text );
protected:
void onUrlLabelUpdated(const std::string &url, const std::string &label);
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 74373e7803..3ce5a0320b 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -63,6 +63,7 @@
#include "llpanel.h"
#include "llurlregistry.h"
#include "lltooltip.h"
+#include "llmenugl.h"
#include <queue>
#include "llcombobox.h"
@@ -252,7 +253,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mHandleEditKeysDirectly( p.handle_edit_keys_directly ),
mMouseDownX(0),
mMouseDownY(0),
- mTabsToNextField(p.ignore_tab)
+ mTabsToNextField(p.ignore_tab),
+ mContextMenu(NULL)
{
mDefaultFont = p.font;
@@ -273,7 +275,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
if (mShowLineNumbers)
{
mHPad += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
- updateTextRect();
+ updateRects();
}
}
@@ -301,6 +303,8 @@ LLTextEditor::~LLTextEditor()
// Scrollbar is deleted by LLView
std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());
+
+ delete mContextMenu;
}
////////////////////////////////////////////////////////////
@@ -648,6 +652,13 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
+ // set focus first, in case click callbacks want to change it
+ // RN: do we really need to have a tab stop?
+ if (hasTabStop())
+ {
+ setFocus( TRUE );
+ }
+
// Let scrollbar have first dibs
handled = LLTextBase::handleMouseDown(x, y, mask);
@@ -690,30 +701,40 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
handled = TRUE;
}
- if (hasTabStop())
- {
- setFocus( TRUE );
- handled = TRUE;
- }
-
// Delay cursor flashing
resetCursorBlink();
return handled;
}
+BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (hasTabStop())
+ {
+ setFocus(TRUE);
+ }
+ if (!LLTextBase::handleRightMouseDown(x, y, mask))
+ {
+ showContextMenu(x, y);
+ }
+ return TRUE;
+}
+
+
BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
{
- BOOL handled = FALSE;
- handled = LLTextBase::handleMouseDown(x, y, mask);
+ if (hasTabStop())
+ {
+ setFocus(TRUE);
+ }
- if (!handled)
+ if (!LLTextBase::handleMouseDown(x, y, mask))
{
- setFocus( TRUE );
if( canPastePrimary() )
{
setCursorAtLocalPos( x, y, true );
+ // does not rely on focus being set
pastePrimary();
}
}
@@ -736,7 +757,6 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
setCursorAtLocalPos( clamped_x, clamped_y, true );
mSelectionEnd = mCursorPos;
}
-
lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
getWindow()->setCursor(UI_CURSOR_IBEAM);
handled = TRUE;
@@ -990,7 +1010,7 @@ void LLTextEditor::removeChar()
// Add a single character to the text
S32 LLTextEditor::addChar(S32 pos, llwchar wc)
{
- if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) >= mMaxTextByteLength)
+ if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength)
{
make_ui_sound("UISndBadKeystroke");
return 0;
@@ -1991,6 +2011,21 @@ void LLTextEditor::setEnabled(BOOL enabled)
}
}
+void LLTextEditor::showContextMenu(S32 x, S32 y)
+{
+ if (!mContextMenu)
+ {
+ mContextMenu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_text_editor.xml",
+ LLMenuGL::sMenuContainer,
+ LLMenuHolderGL::child_registry_t::instance());
+ }
+
+ S32 screen_x, screen_y;
+ localPointToScreen(x, y, &screen_x, &screen_y);
+ mContextMenu->show(screen_x, screen_y);
+}
+
+
void LLTextEditor::drawPreeditMarker()
{
static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0);
@@ -2276,7 +2311,7 @@ void LLTextEditor::insertText(const std::string &new_text)
setEnabled( enabled );
}
-void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline)
+void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)
{
// Save old state
S32 selection_start = mSelectionStart;
@@ -2290,20 +2325,9 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
setCursorPos(old_length);
- LLWString widget_wide_text;
-
- // Add carriage return if not first line
- if (getLength() != 0
- && prepend_newline)
- {
- widget_wide_text = utf8str_to_wstring(std::string("\n") + widget_text);
- }
- else
- {
- widget_wide_text = utf8str_to_wstring(widget_text);
- }
+ LLWString widget_wide_text = utf8str_to_wstring(text);
- LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size());
+ LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size());
insert(getLength(), widget_wide_text, FALSE, segment);
needsReflow();
@@ -2326,7 +2350,7 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
setCursorPos(cursor_pos);
}
- if( !allow_undo )
+ if (!allow_undo)
{
blockUndo();
}
@@ -2505,6 +2529,8 @@ void LLTextEditor::updateSegments()
void LLTextEditor::updateLinkSegments()
{
+ LLWString wtext = getWText();
+
// update any segments that contain a link
for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it)
{
@@ -2514,13 +2540,13 @@ void LLTextEditor::updateLinkSegments()
// if the link's label (what the user can edit) is a valid Url,
// then update the link's HREF to be the same as the label text.
// This lets users edit Urls in-place.
- LLUrlMatch match;
LLStyleSP style = static_cast<LLStyleSP>(segment->getStyle());
- std::string url_label = getText().substr(segment->getStart(), segment->getEnd()-segment->getStart());
- if (LLUrlRegistry::instance().findUrl(url_label, match))
+ LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart());
+ if (LLUrlRegistry::instance().hasUrl(url_label))
{
- LLStringUtil::trim(url_label);
- style->setLinkHREF(url_label);
+ std::string new_url = wstring_to_utf8str(url_label);
+ LLStringUtil::trim(new_url);
+ style->setLinkHREF(new_url);
}
}
}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index e232efbfb3..10fc94dedc 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -99,6 +99,7 @@ public:
// mousehandler overrides
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+ virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask );
virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask);
@@ -165,7 +166,7 @@ public:
// inserts text at cursor
void insertText(const std::string &text);
- void appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline);
+ void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);
// Non-undoable
void setText(const LLStringExplicit &utf8str);
@@ -201,6 +202,7 @@ public:
void getSelectedSegments(segment_vec_t& segments) const;
protected:
+ void showContextMenu(S32 x, S32 y);
void drawPreeditMarker();
void assignEmbedded(const std::string &s);
@@ -328,6 +330,8 @@ private:
LLCoordGL mLastIMEPosition; // Last position of the IME editor
keystroke_signal_t mKeystrokeSignal;
+
+ LLContextMenu* mContextMenu;
}; // end class LLTextEditor
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index f30e56b907..4bc9a9c042 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -38,10 +38,11 @@
// Library includes
#include "lltextbox.h"
#include "lliconctrl.h"
+#include "llbutton.h"
#include "llmenugl.h" // hideMenus()
#include "llui.h" // positionViewNearMouse()
#include "llwindow.h"
-
+#include "lltrans.h"
//
// Constants
//
@@ -155,19 +156,23 @@ LLToolTip::Params::Params()
visible_time_near("visible_time_near", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )),
visible_time_far("visible_time_far", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )),
sticky_rect("sticky_rect"),
- image("image")
+ image("image"),
+ time_based_media("time_based_media", false),
+ web_based_media("web_based_media", false),
+ media_playing("media_playing", false)
{
- name = "tooltip";
- font = LLFontGL::getFontSansSerif();
- bg_opaque_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" );
- background_visible = true;
+ chrome = true;
}
LLToolTip::LLToolTip(const LLToolTip::Params& p)
: LLPanel(p),
mMaxWidth(p.max_width),
mHasClickCallback(p.click_callback.isProvided()),
- mPadding(p.padding)
+ mPadding(p.padding),
+ mTextBox(NULL),
+ mInfoButton(NULL),
+ mPlayMediaButton(NULL),
+ mHomePageButton(NULL)
{
LLTextBox::Params params;
params.initial_value = "tip_text";
@@ -183,27 +188,87 @@ 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
mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
addChild(mTextBox);
-
+
+ S32 TOOLTIP_ICON_SIZE = 0;
+ S32 TOOLTIP_PLAYBUTTON_SIZE = 0;
if (p.image.isProvided())
{
- LLIconCtrl::Params icon_params;
- icon_params.name = "tooltip_icon";
+ LLButton::Params icon_params;
+ icon_params.name = "tooltip_info";
+ icon_params.label(""); // provid label but set to empty so name does not overwrite it -angela
LLRect icon_rect;
LLUIImage* imagep = p.image;
- const S32 TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16);
+ TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16);
icon_rect.setOriginAndSize(mPadding, mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE);
icon_params.rect = icon_rect;
- icon_params.follows.flags = FOLLOWS_LEFT | FOLLOWS_BOTTOM;
- icon_params.image = p.image;
- icon_params.mouse_opaque = false;
- addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_params));
-
+ //icon_params.follows.flags = FOLLOWS_LEFT | FOLLOWS_BOTTOM;
+ icon_params.image_unselected(imagep);
+ icon_params.image_selected(imagep);
+
+ icon_params.scale_image(true);
+ icon_params.flash_color(icon_params.highlight_color());
+ mInfoButton = LLUICtrlFactory::create<LLButton>(icon_params);
+ if (p.click_callback.isProvided())
+ {
+ mInfoButton->setCommitCallback(boost::bind(p.click_callback()));
+ }
+ addChild(mInfoButton);
+
// move text over to fit image in
mTextBox->translate(TOOLTIP_ICON_SIZE + mPadding, 0);
}
-
+
+ if (p.time_based_media)
+ {
+ LLButton::Params p_button;
+ p_button.name(std::string("play_media"));
+ p_button.label(""); // provid label but set to empty so name does not overwrite it -angela
+ TOOLTIP_PLAYBUTTON_SIZE = 16;
+ LLRect button_rect;
+ button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE);
+ p_button.rect = button_rect;
+ p_button.image_selected.name("button_anim_pause.tga");
+ p_button.image_unselected.name("button_anim_play.tga");
+ p_button.scale_image(true);
+
+ mPlayMediaButton = LLUICtrlFactory::create<LLButton>(p_button);
+ if(p.click_playmedia_callback.isProvided())
+ {
+ mPlayMediaButton->setCommitCallback(boost::bind(p.click_playmedia_callback()));
+ }
+ mPlayMediaButton->setToggleState(p.media_playing);
+ addChild(mPlayMediaButton);
+
+ // move text over to fit image in
+ mTextBox->translate(TOOLTIP_PLAYBUTTON_SIZE + mPadding, 0);
+ }
+
+ if (p.web_based_media)
+ {
+ LLButton::Params p_w_button;
+ p_w_button.name(std::string("home_page"));
+ p_w_button.label(""); // provid label but set to empty so name does not overwrite it -angela
+ TOOLTIP_PLAYBUTTON_SIZE = 16;
+ LLRect button_rect;
+ button_rect.setOriginAndSize((mPadding +TOOLTIP_ICON_SIZE+ mPadding ), mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE);
+ p_w_button.rect = button_rect;
+ p_w_button.image_unselected.name("map_home.tga");
+ p_w_button.scale_image(true);
+
+ mHomePageButton = LLUICtrlFactory::create<LLButton>(p_w_button);
+ if(p.click_homepage_callback.isProvided())
+ {
+ mHomePageButton->setCommitCallback(boost::bind(p.click_homepage_callback()));
+ }
+ addChild(mHomePageButton);
+
+ // move text over to fit image in
+ mTextBox->translate(TOOLTIP_PLAYBUTTON_SIZE + mPadding, 0);
+ }
+
if (p.click_callback.isProvided())
{
setMouseUpCallback(boost::bind(p.click_callback()));
@@ -254,6 +319,10 @@ void LLToolTip::setVisible(BOOL visible)
BOOL LLToolTip::handleHover(S32 x, S32 y, MASK mask)
{
+ //mInfoButton->setFlashing(true);
+ if(mInfoButton)
+ mInfoButton->setHighlight(true);
+
LLPanel::handleHover(x, y, mask);
if (mHasClickCallback)
{
@@ -262,6 +331,14 @@ BOOL LLToolTip::handleHover(S32 x, S32 y, MASK mask)
return TRUE;
}
+void LLToolTip::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ //mInfoButton->setFlashing(true);
+ if(mInfoButton)
+ mInfoButton->setHighlight(false);
+ LLUICtrl::onMouseLeave(x, y, mask);
+}
+
void LLToolTip::draw()
{
F32 alpha = 1.f;
@@ -319,9 +396,16 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
LLToolTip::Params tooltip_params(params);
// block mouse events if there is a click handler registered (specifically, hover)
- tooltip_params.mouse_opaque = params.click_callback.isProvided();
+ if (params.click_callback.isProvided())
+ {
+ // set mouse_opaque to true if it wasn't already set to something else
+ // this prevents mouse down from going "through" the tooltip and ultimately
+ // causing the tooltip to disappear
+ tooltip_params.mouse_opaque.setIfNotProvided(true);
+ }
tooltip_params.rect = LLRect (0, 1, 1, 0);
+
mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
mToolTip->setValue(params.message());
gToolTipView->addChild(mToolTip);
@@ -370,7 +454,10 @@ void LLToolTipMgr::show(const std::string& msg)
void LLToolTipMgr::show(const LLToolTip::Params& params)
{
- if (!params.validateBlock())
+ // fill in default tooltip params from tool_tip.xml
+ LLToolTip::Params params_with_defaults(params);
+ params_with_defaults.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLToolTip>());
+ if (!params_with_defaults.validateBlock())
{
llwarns << "Could not display tooltip!" << llendl;
return;
@@ -382,10 +469,12 @@ void LLToolTipMgr::show(const LLToolTip::Params& params)
// are we ready to show the tooltip?
if (!mToolTipsBlocked // we haven't hit a key, moved the mouse, etc.
- && LLUI::getMouseIdleTime() > params.delay_time) // the mouse has been still long enough
+ && LLUI::getMouseIdleTime() > params_with_defaults.delay_time) // the mouse has been still long enough
{
- bool tooltip_changed = mLastToolTipParams.message() != params.message()
- || mLastToolTipParams.pos() != params.pos();
+ bool tooltip_changed = mLastToolTipParams.message() != params_with_defaults.message()
+ || mLastToolTipParams.pos() != params_with_defaults.pos()
+ || mLastToolTipParams.time_based_media() != params_with_defaults.time_based_media()
+ || mLastToolTipParams.web_based_media() != params_with_defaults.web_based_media();
bool tooltip_shown = mToolTip
&& mToolTip->getVisible()
@@ -393,7 +482,7 @@ void LLToolTipMgr::show(const LLToolTip::Params& params)
mNeedsToolTip = tooltip_changed || !tooltip_shown;
// store description of tooltip for later creation
- mNextToolTipParams = params;
+ mNextToolTipParams = params_with_defaults;
}
}
diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h
index 63e7249a12..30d251266c 100644
--- a/indra/llui/lltooltip.h
+++ b/indra/llui/lltooltip.h
@@ -78,9 +78,13 @@ public:
visible_time_far; // time for which tooltip is visible while mouse moved away
Optional<LLRect> sticky_rect;
Optional<const LLFontGL*> font;
-
- Optional<click_callback_t> click_callback;
Optional<LLUIImage*> image;
+ Optional<bool> time_based_media,
+ web_based_media,
+ media_playing;
+ Optional<click_callback_t> click_callback,
+ click_playmedia_callback,
+ click_homepage_callback;
Optional<S32> max_width;
Optional<S32> padding;
Optional<bool> wrap;
@@ -89,7 +93,7 @@ public:
};
/*virtual*/ void draw();
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
-
+ /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
/*virtual*/ void setValue(const LLSD& value);
/*virtual*/ void setVisible(BOOL visible);
@@ -101,6 +105,10 @@ public:
private:
class LLTextBox* mTextBox;
+ class LLButton* mInfoButton;
+ class LLButton* mPlayMediaButton;
+ class LLButton* mHomePageButton;
+
LLFrameTimer mFadeTimer;
LLFrameTimer mVisibleTimer;
S32 mMaxWidth;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 9a90ee267e..a82e6eb372 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1807,11 +1807,11 @@ void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen)
}
//static
-LLPointer<LLUIImage> LLUI::getUIImageByID(const LLUUID& image_id)
+LLPointer<LLUIImage> LLUI::getUIImageByID(const LLUUID& image_id, S32 priority)
{
if (sImageProvider)
{
- return sImageProvider->getUIImageByID(image_id);
+ return sImageProvider->getUIImageByID(image_id, priority);
}
else
{
@@ -1820,10 +1820,10 @@ LLPointer<LLUIImage> LLUI::getUIImageByID(const LLUUID& image_id)
}
//static
-LLPointer<LLUIImage> LLUI::getUIImage(const std::string& name)
+LLPointer<LLUIImage> LLUI::getUIImage(const std::string& name, S32 priority)
{
if (!name.empty() && sImageProvider)
- return sImageProvider->getUIImage(name);
+ return sImageProvider->getUIImage(name, priority);
else
return NULL;
}
@@ -1918,16 +1918,11 @@ namespace LLInitParam
declare("blue", LLColor4::blue);
}
- template<>
- class ParamCompare<const LLFontGL*>
+ bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b)
{
- public:
- static bool equals(const LLFontGL* a, const LLFontGL* b)
- {
- return !(a->getFontDesc() < b->getFontDesc())
- && !(b->getFontDesc() < a->getFontDesc());
- }
- };
+ return !(a->getFontDesc() < b->getFontDesc())
+ && !(b->getFontDesc() < a->getFontDesc());
+ }
TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count)
: super_t(descriptor, _name, value, func, min_count, max_count),
@@ -1957,7 +1952,7 @@ namespace LLInitParam
return fontp;
}
}
-
+
// default to current value
return mData.mValue;
}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index f071e8dc47..5ec07f1941 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -195,8 +195,8 @@ public:
static void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y);
static void setScaleFactor(const LLVector2& scale_factor);
static void setLineWidth(F32 width);
- static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id);
- static LLPointer<LLUIImage> getUIImage(const std::string& name);
+ static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0);
+ static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0);
static LLVector2 getWindowSize();
static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
@@ -241,8 +241,8 @@ protected:
LLImageProviderInterface() {};
virtual ~LLImageProviderInterface() {};
public:
- virtual LLPointer<LLUIImage> getUIImage(const std::string& name) = 0;
- virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id) = 0;
+ virtual LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) = 0;
+ virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) = 0;
virtual void cleanUp() = 0;
};
@@ -404,6 +404,20 @@ namespace LLInitParam
LLUIColor getValueFromBlock() const;
};
+ // provide a better default for Optional<const LLFontGL*> than NULL
+ template <>
+ struct DefaultInitializer<const LLFontGL*>
+ {
+ // return reference to a single default instance of T
+ // built-in types will be initialized to zero, default constructor otherwise
+ static const LLFontGL* get()
+ {
+ static const LLFontGL* sDefaultFont = LLFontGL::getFontDefault();
+ return sDefaultFont;
+ }
+ };
+
+
template<>
class TypedParam<const LLFontGL*>
: public BlockValue<const LLFontGL*>
@@ -437,6 +451,13 @@ namespace LLInitParam
};
template<>
+ struct ParamCompare<const LLFontGL*, false>
+ {
+ static bool equals(const LLFontGL* a, const LLFontGL* b);
+ };
+
+
+ template<>
class TypedParam<LLCoordGL>
: public BlockValue<LLCoordGL>
{
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index 087a99c2b0..851091f0ca 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -3,7 +3,30 @@
* @brief brief LLUIColorTable class implementation file
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
* Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
@@ -278,7 +301,7 @@ bool LLUIColorTable::loadFromFilename(const std::string& filename)
}
Params params;
- LLXUIParser::instance().readXUI(root, params);
+ LLXUIParser::instance().readXUI(root, params, filename);
if(params.validateBlock())
{
diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h
index f102a573b8..59be0c4f9a 100644
--- a/indra/llui/lluicolortable.h
+++ b/indra/llui/lluicolortable.h
@@ -3,7 +3,30 @@
* @brief brief LLUIColorTable class header file
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
* Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 5b72f87a78..08fc8fb784 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -42,6 +42,7 @@ static LLDefaultChildRegistry::Register<LLUICtrl> r("ui_ctrl");
LLUICtrl::Params::Params()
: tab_stop("tab_stop", true),
+ chrome("chrome", false),
label("label"),
initial_value("value"),
init_callback("init_callback"),
@@ -86,6 +87,7 @@ void LLUICtrl::initFromParams(const Params& p)
{
LLView::initFromParams(p);
+ setIsChrome(p.chrome);
setControlName(p.control_name);
if(p.enabled_controls.isProvided())
{
@@ -582,7 +584,6 @@ void LLUICtrl::setIsChrome(BOOL is_chrome)
// virtual
BOOL LLUICtrl::getIsChrome() const
{
-
LLView* parent_ctrl = getParent();
while(parent_ctrl)
{
@@ -795,16 +796,29 @@ bool LLUICtrl::findHelpTopic(std::string& help_topic_out)
LLUICtrl* ctrl = this;
// search back through the control's parents for a panel
- // with a help_topic string defined
+ // or tab with a help_topic string defined
while (ctrl)
{
LLPanel *panel = dynamic_cast<LLPanel *>(ctrl);
- if (panel && !panel->getHelpTopic().empty())
+
+ if (panel)
{
- help_topic_out = panel->getHelpTopic();
- return true; // success
+ // does the panel have an active tab with a help topic?
+ LLPanel *tab = panel->childGetVisibleTabWithHelp();
+ if (tab)
+ {
+ help_topic_out = tab->getHelpTopic();
+ return true; // success (tab)
+ }
+
+ // otherwise, does the panel have a help topic itself?
+ if (!panel->getHelpTopic().empty())
+ {
+ help_topic_out = panel->getHelpTopic();
+ return true; // success (panel)
+ }
}
-
+
ctrl = ctrl->getParentUICtrl();
}
@@ -836,24 +850,3 @@ BOOL LLUICtrl::getTentative() const
// virtual
void LLUICtrl::setColor(const LLColor4& color)
{ }
-
-
-namespace LLInitParam
-{
- template<>
- bool ParamCompare<LLUICtrl::commit_callback_t>::equals(
- const LLUICtrl::commit_callback_t &a,
- const LLUICtrl::commit_callback_t &b)
- {
- return false;
- }
-
-
- template<>
- bool ParamCompare<LLUICtrl::enable_callback_t>::equals(
- const LLUICtrl::enable_callback_t &a,
- const LLUICtrl::enable_callback_t &b)
- {
- return false;
- }
-}
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 69207eb8ea..dd22851100 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -126,7 +126,8 @@ public:
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Optional<std::string> label;
- Optional<bool> tab_stop;
+ Optional<bool> tab_stop,
+ chrome;
Optional<LLSD> initial_value;
Optional<CommitCallbackParam> init_callback,
@@ -228,7 +229,11 @@ public:
// Default to no-op:
virtual void onTabInto();
+
+ // Clear any user-provided input (text in a text editor, checked checkbox,
+ // selected radio button, etc.). Defaults to no-op.
virtual void clear();
+
virtual void setColor(const LLColor4& color);
BOOL focusNextItem(BOOL text_entry_only);
@@ -323,21 +328,4 @@ private:
class DefaultTabGroupFirstSorter;
};
-namespace LLInitParam
-{
- template<>
- bool ParamCompare<LLUICtrl::commit_callback_t>::equals(
- const LLUICtrl::commit_callback_t &a,
- const LLUICtrl::commit_callback_t &b);
-
- template<>
- bool ParamCompare<LLUICtrl::enable_callback_t>::equals(
- const LLUICtrl::enable_callback_t &a,
- const LLUICtrl::enable_callback_t &b);
-
- template<>
- bool ParamCompare<LLLazyValue<LLColor4> >::equals(
- const LLLazyValue<LLColor4> &a, const LLLazyValue<LLColor4> &b);
-}
-
#endif // LL_LLUICTRL_H
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 209ee76940..c3c0daed0f 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -34,6 +34,8 @@
#include "lluictrlfactory.h"
+#include "llxmlnode.h"
+
#include <fstream>
#include <boost/tokenizer.hpp>
@@ -83,8 +85,9 @@ LLUICtrlFactory::LLUICtrlFactory()
LLUICtrlFactory::~LLUICtrlFactory()
{
- delete mDummyPanel;
- mDummyPanel = NULL;
+ // go ahead and leak mDummyPanel since this is static destructor time
+ //delete mDummyPanel;
+ //mDummyPanel = NULL;
}
void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block)
@@ -94,7 +97,7 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa
if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
{
- LLXUIParser::instance().readXUI(root_node, block);
+ LLXUIParser::instance().readXUI(root_node, block, filename);
}
}
@@ -410,3 +413,39 @@ void LLUICtrlFactory::popFactoryFunctions()
mFactoryStack.pop_back();
}
}
+
+//static
+void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest)
+{
+ dest->setName(src->getName()->mString);
+}
+
+// adds a widget and its param block to various registries
+//static
+void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag)
+{
+ // associate parameter block type with template .xml file
+ std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type);
+ if (existing_tag != NULL && *existing_tag != tag)
+ {
+ llerrs << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << llendl;
+ }
+ LLWidgetNameRegistry ::instance().defaultRegistrar().add(param_block_type, tag);
+ // associate widget type with factory function
+ LLDefaultWidgetRegistry::instance().defaultRegistrar().add(widget_type, creator_func);
+ LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type);
+ //FIXME: comment this in when working on schema generation
+ //LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &getEmptyParamBlock<T>);
+}
+
+//static
+dummy_widget_creator_func_t* LLUICtrlFactory::getDefaultWidgetFunc(const std::type_info* widget_type)
+{
+ return LLDefaultWidgetRegistry::instance().getValue(widget_type);
+}
+
+//static
+const std::string* LLUICtrlFactory::getWidgetTag(const std::type_info* widget_type)
+{
+ return LLWidgetNameRegistry::instance().getValue(widget_type);
+}
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 5e6dad312c..17e32dc7a9 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -36,7 +36,7 @@
#include "llcallbackmap.h"
#include "llinitparam.h"
#include "llregistry.h"
-#include "llxmlnode.h"
+#include "v4color.h"
#include "llfasttimer.h"
#include "llxuiparser.h"
@@ -98,10 +98,11 @@ class LLDefaultWidgetRegistry
{};
// lookup function for generating empty param block by widget type
-typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
-class LLDefaultParamBlockRegistry
-: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry, LLCompareTypeID>
-{};
+// this is used for schema generation
+//typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
+//class LLDefaultParamBlockRegistry
+//: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry, LLCompareTypeID>
+//{};
extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP;
extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION;
@@ -124,7 +125,7 @@ private:
// recursively initialize from base class param block
((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY>::instance().get());
// after initializing base classes, look up template file for this param block
- std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK));
+ const std::string* param_block_tag = getWidgetTag(&typeid(PARAM_BLOCK));
if (param_block_tag)
{
LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, mPrototype);
@@ -241,7 +242,7 @@ fail:
template<class T>
static T* getDefaultWidget(const std::string& name)
{
- dummy_widget_creator_func_t* dummy_func = LLDefaultWidgetRegistry::instance().getValue(&typeid(T));
+ dummy_widget_creator_func_t* dummy_func = getDefaultWidgetFunc(&typeid(T));
return dummy_func ? dynamic_cast<T*>((*dummy_func)(name)) : NULL;
}
@@ -254,6 +255,8 @@ fail:
return create<T>(params);
}
+ static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
+
template<typename T>
static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
{
@@ -262,7 +265,7 @@ fail:
//#pragma message("Generating LLUICtrlFactory::defaultBuilder")
typename T::Params params(getDefaultParams<T>());
- LLXUIParser::instance().readXUI(node, params);
+ LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
if (output_node)
{
@@ -271,7 +274,7 @@ fail:
T::setupParamsForExport(output_params, parent);
// Export only the differences between this any default params
typename T::Params default_params(getDefaultParams<T>());
- output_node->setName(node->getName()->mString);
+ copyName(node, output_node);
LLXUIParser::instance().writeXUI(
output_node, output_params, &default_params);
}
@@ -320,7 +323,15 @@ fail:
static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
+ // helper function for adding widget type info to various registries
+ static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag);
+
private:
+ // return default widget instance factory func for a given type
+ static dummy_widget_creator_func_t* getDefaultWidgetFunc(const std::type_info* widget_type);
+
+ static const std::string* getWidgetTag(const std::type_info* widget_type);
+
// this exists to get around dependency on llview
static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group);
@@ -347,23 +358,12 @@ template<typename T>
LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreatorFunc func)
: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
{
- const std::type_info* widget_type_infop = &typeid(T);
- // associate parameter block type with template .xml file
- std::string* existing_tag = LLWidgetNameRegistry ::instance().getValue(&typeid(typename T::Params));
- if (existing_tag != NULL && *existing_tag != tag)
- {
- // duplicate entry for T::Params
- // try creating empty param block in derived classes that inherit T::Params
- int* crash = 0;
- *crash = 0;
- }
- LLWidgetNameRegistry ::instance().defaultRegistrar().add(&typeid(typename T::Params), tag);
- // associate widget type with factory function
- LLDefaultWidgetRegistry::instance().defaultRegistrar().add(widget_type_infop, &LLUICtrlFactory::createDefaultWidget<T>);
- LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type_infop);
- LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type_infop, &getEmptyParamBlock<T>);
+ // add this widget to various registries
+ LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), &LLUICtrlFactory::createDefaultWidget<T>, tag);
+
+ // since registry_t depends on T, do this in line here
typedef typename T::child_registry_t registry_t;
- LLChildRegistryRegistry::instance().defaultRegistrar().add(widget_type_infop, registry_t::instance());
+ LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
}
diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp
index ab0d65e731..6c1a32722f 100644
--- a/indra/llui/lluiimage.cpp
+++ b/indra/llui/lluiimage.cpp
@@ -152,8 +152,7 @@ namespace LLInitParam
}
- template<>
- bool ParamCompare<LLUIImage*>::equals(
+ bool ParamCompare<LLUIImage*, false>::equals(
LLUIImage* const &a,
LLUIImage* const &b)
{
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
index 4ec24e98dc..9d734bcfdf 100644
--- a/indra/llui/lluiimage.h
+++ b/indra/llui/lluiimage.h
@@ -108,8 +108,10 @@ namespace LLInitParam
// Need custom comparison function for our test app, which only loads
// LLUIImage* as NULL.
template<>
- bool ParamCompare<LLUIImage*>::equals(
- LLUIImage* const &a, LLUIImage* const &b);
+ struct ParamCompare<LLUIImage*, false>
+ {
+ static bool equals(LLUIImage* const &a, LLUIImage* const &b);
+ };
}
typedef LLPointer<LLUIImage> LLUIImagePtr;
diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp
index 20ff71378e..3a1e656364 100644
--- a/indra/llui/lluistring.cpp
+++ b/indra/llui/lluistring.cpp
@@ -35,8 +35,6 @@
#include "llsd.h"
#include "lltrans.h"
-const LLStringUtil::format_map_t LLUIString::sNullArgs;
-
LLFastTimer::DeclareTimer FTM_UI_STRING("UI String");
diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h
index aedeca27cb..763de4d6a3 100644
--- a/indra/llui/lluistring.h
+++ b/indra/llui/lluistring.h
@@ -51,9 +51,9 @@
// llinfos << mMessage.getString() << llendl; // outputs "Welcome Steve to Second Life"
// mMessage.setArg("[USERNAME]", "Joe");
// llinfos << mMessage.getString() << llendl; // outputs "Welcome Joe to Second Life"
-// mMessage = "Recepci￳n a la [SECONDLIFE] [USERNAME]"
+// mMessage = "Bienvenido a la [SECONDLIFE] [USERNAME]"
// mMessage.setArg("[SECONDLIFE]", "Segunda Vida");
-// llinfos << mMessage.getString() << llendl; // outputs "Recepci￳n a la Segunda Vida Joe"
+// llinfos << mMessage.getString() << llendl; // outputs "Bienvenido a la Segunda Vida Joe"
// Implementation Notes:
// Attempting to have operator[](const std::string& s) return mArgs[s] fails because we have
@@ -95,8 +95,6 @@ public:
void insert(S32 charidx, const LLWString& wchars);
void replace(S32 charidx, llwchar wc);
- static const LLStringUtil::format_map_t sNullArgs;
-
private:
void format();
diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp
index f3401f91f7..679db5e39b 100644
--- a/indra/llui/llurlaction.cpp
+++ b/indra/llui/llurlaction.cpp
@@ -121,6 +121,18 @@ void LLUrlAction::teleportToLocation(std::string url)
}
}
+void LLUrlAction::showLocationOnMap(std::string url)
+{
+ LLUrlMatch match;
+ if (LLUrlRegistry::instance().findUrl(url, match))
+ {
+ if (! match.getLocation().empty())
+ {
+ executeSLURL("secondlife:///app/worldmap/" + match.getLocation());
+ }
+ }
+}
+
void LLUrlAction::copyURLToClipboard(std::string url)
{
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url));
diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h
index 6b9d565b44..4830cf27ef 100644
--- a/indra/llui/llurlaction.h
+++ b/indra/llui/llurlaction.h
@@ -67,6 +67,9 @@ public:
/// if the Url specifies an SL location, teleport there
static void teleportToLocation(std::string url);
+ /// if the Url specifies an SL location, show it on a map
+ static void showLocationOnMap(std::string url);
+
/// perform the appropriate action for left-clicking on a Url
static void clickAction(std::string url);
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index c1da73fa83..dae4b512d1 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -145,6 +145,18 @@ void LLUrlEntryBase::callObservers(const std::string &id, const std::string &lab
}
}
+static std::string getStringAfterToken(const std::string str, const std::string token)
+{
+ size_t pos = str.find(token);
+ if (pos == std::string::npos)
+ {
+ return "";
+ }
+
+ pos += token.size();
+ return str.substr(pos, str.size() - pos);
+}
+
//
// LLUrlEntryHTTP Describes generic http: and https: Urls
//
@@ -154,7 +166,6 @@ LLUrlEntryHTTP::LLUrlEntryHTTP()
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_http.xml";
mTooltip = LLTrans::getString("TooltipHttpUrl");
- //mIcon = "gear.tga";
}
std::string LLUrlEntryHTTP::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
@@ -280,36 +291,52 @@ void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id,
std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
- std::string id = getIDStringFromUrl(url);
- if (gCacheName && ! id.empty())
+ if (!gCacheName)
{
- LLUUID uuid(id);
- std::string full_name;
- if (gCacheName->getFullName(uuid, full_name))
- {
- return full_name;
- }
- else
- {
- gCacheName->get(uuid, FALSE, boost::bind(&LLUrlEntryAgent::onAgentNameReceived, this, _1, _2, _3, _4));
- addObserver(id, url, cb);
- }
+ // probably at the login screen, use short string for layout
+ return LLTrans::getString("LoadingData");
}
- return LLTrans::getString("LoadingData");//unescapeUrl(url);
+ std::string agent_id_string = getIDStringFromUrl(url);
+ if (agent_id_string.empty())
+ {
+ // something went wrong, just give raw url
+ return unescapeUrl(url);
+ }
+
+ LLUUID agent_id(agent_id_string);
+ std::string full_name;
+ if (agent_id.isNull())
+ {
+ return LLTrans::getString("AvatarNameNobody");
+ }
+ else if (gCacheName->getFullName(agent_id, full_name))
+ {
+ return full_name;
+ }
+ else
+ {
+ gCacheName->get(agent_id, FALSE,
+ boost::bind(&LLUrlEntryAgent::onAgentNameReceived,
+ this, _1, _2, _3, _4));
+ addObserver(agent_id_string, url, cb);
+ return LLTrans::getString("LoadingData");
+ }
}
//
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
+// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
//
LLUrlEntryGroup::LLUrlEntryGroup()
{
- mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/about",
+ mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_group.xml";
mIcon = "Generic_Group";
mTooltip = LLTrans::getString("TooltipGroupUrl");
+ mColor = LLUIColorTable::instance().getColor("GroupLinkColor");
}
void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
@@ -323,23 +350,37 @@ void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
- std::string id = getIDStringFromUrl(url);
- if (gCacheName && ! id.empty())
+ if (!gCacheName)
{
- LLUUID uuid(id);
- std::string group_name;
- if (gCacheName->getGroupName(uuid, group_name))
- {
- return group_name;
- }
- else
- {
- gCacheName->get(uuid, TRUE, boost::bind(&LLUrlEntryGroup::onGroupNameReceived, this, _1, _2, _3, _4));
- addObserver(id, url, cb);
- }
+ // probably at login screen, give something short for layout
+ return LLTrans::getString("LoadingData");
}
- return unescapeUrl(url);
+ std::string group_id_string = getIDStringFromUrl(url);
+ if (group_id_string.empty())
+ {
+ // something went wrong, give raw url
+ return unescapeUrl(url);
+ }
+
+ LLUUID group_id(group_id_string);
+ std::string group_name;
+ if (group_id.isNull())
+ {
+ return LLTrans::getString("GroupNameNone");
+ }
+ else if (gCacheName->getGroupName(group_id, group_name))
+ {
+ return group_name;
+ }
+ else
+ {
+ gCacheName->get(group_id, TRUE,
+ boost::bind(&LLUrlEntryGroup::onGroupNameReceived,
+ this, _1, _2, _3, _4));
+ addObserver(group_id_string, url, cb);
+ return LLTrans::getString("LoadingData");
+ }
}
///
@@ -360,7 +401,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC
}
//
-// LLUrlEntryPlace Describes secondlife:///<location> URLs
+// LLUrlEntryPlace Describes secondlife://<location> URLs
//
LLUrlEntryPlace::LLUrlEntryPlace()
{
@@ -403,15 +444,7 @@ std::string LLUrlEntryPlace::getLabel(const std::string &url, const LLUrlLabelCa
std::string LLUrlEntryPlace::getLocation(const std::string &url) const
{
// return the part of the Url after secondlife:// part
- const std::string search_string = "://";
- size_t pos = url.find(search_string);
- if (pos == std::string::npos)
- {
- return "";
- }
-
- pos += search_string.size();
- return url.substr(pos, url.size() - pos);
+ return ::getStringAfterToken(url, "://");
}
//
@@ -438,6 +471,7 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe
LLURI uri(url);
LLSD path_array = uri.pathArray();
S32 path_parts = path_array.size();
+ const std::string label = LLTrans::getString("SLurlLabelTeleport");
if (path_parts == 6)
{
// handle teleport url with (X,Y,Z) coordinates
@@ -445,7 +479,7 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe
std::string x = path_array[path_parts-3];
std::string y = path_array[path_parts-2];
std::string z = path_array[path_parts-1];
- return "Teleport to " + location + " (" + x + "," + y + "," + z + ")";
+ return label + " " + location + " (" + x + "," + y + "," + z + ")";
}
else if (path_parts == 5)
{
@@ -453,20 +487,20 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe
std::string location = unescapeUrl(path_array[path_parts-3]);
std::string x = path_array[path_parts-2];
std::string y = path_array[path_parts-1];
- return "Teleport to " + location + " (" + x + "," + y + ")";
+ return label + " " + location + " (" + x + "," + y + ")";
}
else if (path_parts == 4)
{
// handle teleport url with (X) coordinate only
std::string location = unescapeUrl(path_array[path_parts-2]);
std::string x = path_array[path_parts-1];
- return "Teleport to " + location + " (" + x + ")";
+ return label + " " + location + " (" + x + ")";
}
else if (path_parts == 3)
{
// handle teleport url with no coordinates
std::string location = unescapeUrl(path_array[path_parts-1]);
- return "Teleport to " + location;
+ return label + " " + location;
}
return url;
@@ -475,15 +509,7 @@ std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabe
std::string LLUrlEntryTeleport::getLocation(const std::string &url) const
{
// return the part of the Url after ///app/teleport
- const std::string search_string = "teleport";
- size_t pos = url.find(search_string);
- if (pos == std::string::npos)
- {
- return "";
- }
-
- pos += search_string.size() + 1;
- return url.substr(pos, url.size() - pos);
+ return ::getStringAfterToken(url, "app/teleport/");
}
///
@@ -569,3 +595,43 @@ std::string LLUrlEntrySLLabel::getUrl(const std::string &string)
return getUrlFromWikiLink(string);
}
+//
+// LLUrlEntryWorldMap Describes secondlife:///<location> URLs
+//
+LLUrlEntryWorldMap::LLUrlEntryWorldMap()
+{
+ mPattern = boost::regex("secondlife:///app/worldmap/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*",
+ boost::regex::perl|boost::regex::icase);
+ mMenuName = "menu_url_map.xml";
+ mTooltip = LLTrans::getString("TooltipMapUrl");
+}
+
+std::string LLUrlEntryWorldMap::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+ //
+ // we handle SLURLs in the following formats:
+ // - secondlife:///app/worldmap/PLACE/X/Y/Z
+ // - secondlife:///app/worldmap/PLACE/X/Y
+ // - secondlife:///app/worldmap/PLACE/X
+ //
+ LLURI uri(url);
+ LLSD path_array = uri.pathArray();
+ S32 path_parts = path_array.size();
+ if (path_parts < 3)
+ {
+ return url;
+ }
+
+ const std::string label = LLTrans::getString("SLurlLabelShowOnMap");
+ std::string location = path_array[2];
+ std::string x = (path_parts > 3) ? path_array[3] : "128";
+ std::string y = (path_parts > 4) ? path_array[4] : "128";
+ std::string z = (path_parts > 5) ? path_array[5] : "0";
+ return label + " " + location + " (" + x + "," + y + "," + z + ")";
+}
+
+std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
+{
+ // return the part of the Url after secondlife:///app/worldmap/ part
+ return ::getStringAfterToken(url, "app/worldmap/");
+}
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index afb2fdcde9..4507572b1e 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -186,7 +186,7 @@ public:
///
/// LLUrlEntryPlace Describes a Second Life location Url, e.g.,
-/// secondlife:///Ahern/50/50/50
+/// secondlife://Ahern/50/50/50
///
class LLUrlEntryPlace : public LLUrlEntryBase
{
@@ -243,4 +243,16 @@ public:
/*virtual*/ std::string getUrl(const std::string &string);
};
+///
+/// LLUrlEntryWorldMap Describes a Second Life worldmap Url, e.g.,
+/// secondlife:///app/worldmap/Ahern/50/50/50
+///
+class LLUrlEntryWorldMap : public LLUrlEntryBase
+{
+public:
+ LLUrlEntryWorldMap();
+ /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+ /*virtual*/ std::string getLocation(const std::string &url) const;
+};
+
#endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 8413de0837..60275b60bc 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -51,6 +51,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryGroup());
registerUrl(new LLUrlEntryParcel());
registerUrl(new LLUrlEntryTeleport());
+ registerUrl(new LLUrlEntryWorldMap());
registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntrySL());
@@ -192,3 +193,15 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
}
return false;
}
+
+bool LLUrlRegistry::hasUrl(const std::string &text)
+{
+ LLUrlMatch match;
+ return findUrl(text, match);
+}
+
+bool LLUrlRegistry::hasUrl(const LLWString &text)
+{
+ LLUrlMatch match;
+ return findUrl(text, match);
+}
diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h
index 85e934e4b5..d7800d8cfc 100644
--- a/indra/llui/llurlregistry.h
+++ b/indra/llui/llurlregistry.h
@@ -81,6 +81,10 @@ public:
bool findUrl(const LLWString &text, LLUrlMatch &match,
const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback);
+ // return true if the given string contains a URL that findUrl would match
+ bool hasUrl(const std::string &text);
+ bool hasUrl(const LLWString &text);
+
private:
LLUrlRegistry();
friend class LLSingleton<LLUrlRegistry>;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 1df8838738..fe7fd59de8 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -57,14 +57,13 @@
#include "lltexteditor.h"
#include "lltextbox.h"
-BOOL LLView::sDebugRects = FALSE;
-BOOL LLView::sDebugKeys = FALSE;
S32 LLView::sDepth = 0;
-BOOL LLView::sDebugMouseHandling = FALSE;
+bool LLView::sDebugRects = false;
+bool LLView::sDebugRectsShowNames = true;
+bool LLView::sDebugKeys = false;
+bool LLView::sDebugMouseHandling = false;
std::string LLView::sMouseHandlerMessage;
-//BOOL LLView::sEditingUI = FALSE;
BOOL LLView::sForceReshape = FALSE;
-//LLView* LLView::sEditingUIView = NULL;
std::set<LLView*> LLView::sPreviewHighlightedElements;
BOOL LLView::sHighlightingDiffs = FALSE;
LLView* LLView::sPreviewClickedElement = NULL;
@@ -439,6 +438,18 @@ void LLView::setEnabled(BOOL enabled)
}
//virtual
+bool LLView::isAvailable() const
+{
+ return isInEnabledChain() && isInVisibleChain();
+}
+
+//static
+bool LLView::isAvailable(const LLView* view)
+{
+ return view && view->isAvailable();
+}
+
+//virtual
BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
{
return FALSE;
@@ -656,7 +667,7 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
@@ -673,6 +684,26 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
}
+LLView* LLView::childFromPoint(S32 x, S32 y)
+{
+ if (!getVisible() )
+ return false;
+ for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ {
+ LLView* viewp = *child_it;
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible() )
+ {
+ continue;
+ }
+ return viewp;
+
+ }
+ return 0;
+}
+
BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
@@ -896,18 +927,12 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
-
- if (viewp->blockMouseEvent(local_x, local_y))
- {
- handled_view = viewp;
- break;
- }
}
}
return handled_view;
@@ -934,7 +959,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
@@ -1024,7 +1049,7 @@ LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
@@ -1062,7 +1087,7 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
@@ -1101,7 +1126,7 @@ LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
@@ -1140,7 +1165,7 @@ LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
@@ -1177,7 +1202,7 @@ LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
@@ -1214,7 +1239,7 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
@@ -1251,7 +1276,7 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
@@ -1353,7 +1378,7 @@ void LLView::drawDebugRect()
LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
// draw red rectangle for the border
- LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
+ LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f);
if(preview_iter != sPreviewHighlightedElements.end())
{
if(LLView::sPreviewClickedElement && this == sPreviewClickedElement)
@@ -1388,7 +1413,9 @@ void LLView::drawDebugRect()
gGL.end();
// Draw the name if it's not a leaf node or not in editing or preview mode
- if (mChildList.size() && preview_iter == sPreviewHighlightedElements.end())
+ if (mChildList.size()
+ && preview_iter == sPreviewHighlightedElements.end()
+ && sDebugRectsShowNames)
{
//char temp[256];
S32 x, y;
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 7ddff2bd9e..c3b442e022 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -304,6 +304,11 @@ public:
BOOL getVisible() const { return mVisible; }
virtual void setEnabled(BOOL enabled);
BOOL getEnabled() const { return mEnabled; }
+ /// 'available' in this context means 'visible and enabled': in other
+ /// words, can a user actually interact with this?
+ virtual bool isAvailable() const;
+ /// The static isAvailable() tests an LLView* that could be NULL.
+ static bool isAvailable(const LLView* view);
U8 getSoundFlags() const { return mSoundFlags; }
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
@@ -445,6 +450,8 @@ public:
/*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
/*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
+ virtual LLView* childFromPoint(S32 x, S32 y);
+
// view-specific handlers
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
@@ -586,14 +593,20 @@ private:
default_widget_map_t& getDefaultWidgetMap() const;
public:
- static BOOL sDebugRects; // Draw debug rects behind everything.
- static BOOL sDebugKeys;
+ // Depth in view hierarchy during rendering
static S32 sDepth;
- static BOOL sDebugMouseHandling;
+
+ // Draw debug rectangles around widgets to help with alignment and spacing
+ static bool sDebugRects;
+
+ // Draw widget names and sizes when drawing debug rectangles, turning this
+ // off is useful to make the rectangles themselves easier to see.
+ static bool sDebugRectsShowNames;
+
+ static bool sDebugKeys;
+ static bool sDebugMouseHandling;
static std::string sMouseHandlerMessage;
static S32 sSelectID;
-// static BOOL sEditingUI;
-// static LLView* sEditingUIView;
static std::set<LLView*> sPreviewHighlightedElements; // DEV-16869
static BOOL sHighlightingDiffs; // DEV-16869
static LLView* sPreviewClickedElement; // DEV-16869
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 468fae2ec5..128cd134c1 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -308,6 +308,10 @@ namespace tut
"secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about",
"secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about");
+ testRegex("Group Url ", r,
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect",
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect");
+
testRegex("Group Url in text", r,
"XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX",
"secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about");