summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt4
-rw-r--r--indra/llui/llbutton.cpp35
-rw-r--r--indra/llui/llbutton.h10
-rw-r--r--indra/llui/llconsole.cpp5
-rw-r--r--indra/llui/lldraghandle.cpp9
-rw-r--r--indra/llui/llfloater.cpp292
-rw-r--r--indra/llui/llfloater.h27
-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/lliconctrl.cpp23
-rw-r--r--indra/llui/lliconctrl.h13
-rw-r--r--indra/llui/lllineeditor.cpp25
-rw-r--r--indra/llui/lllineeditor.h2
-rw-r--r--indra/llui/lllocalcliprect.cpp3
-rw-r--r--indra/llui/llmenubutton.cpp2
-rw-r--r--indra/llui/llmenugl.cpp33
-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.cpp3
-rw-r--r--indra/llui/llnotifications.h17
-rw-r--r--indra/llui/llnotificationslistener.cpp55
-rw-r--r--indra/llui/llnotificationslistener.h34
-rw-r--r--indra/llui/llpanel.cpp47
-rw-r--r--indra/llui/llpanel.h30
-rw-r--r--indra/llui/llradiogroup.cpp2
-rw-r--r--indra/llui/llscrollcontainer.cpp2
-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.cpp43
-rw-r--r--indra/llui/lltabcontainer.h3
-rw-r--r--indra/llui/lltextbase.cpp245
-rw-r--r--indra/llui/lltextbase.h29
-rw-r--r--indra/llui/lltextbox.cpp26
-rw-r--r--indra/llui/lltextbox.h21
-rw-r--r--indra/llui/lltexteditor.cpp72
-rw-r--r--indra/llui/lltexteditor.h6
-rw-r--r--indra/llui/lltooltip.cpp125
-rw-r--r--indra/llui/lltooltip.h14
-rw-r--r--indra/llui/llui.cpp10
-rw-r--r--indra/llui/llui.h22
-rw-r--r--indra/llui/lluictrl.cpp3
-rw-r--r--indra/llui/lluictrl.h3
-rw-r--r--indra/llui/llurlaction.cpp12
-rw-r--r--indra/llui/llurlaction.h3
-rw-r--r--indra/llui/llurlentry.cpp84
-rw-r--r--indra/llui/llurlentry.h14
-rw-r--r--indra/llui/llurlregistry.cpp1
-rw-r--r--indra/llui/llview.cpp12
-rw-r--r--indra/llui/llview.h5
57 files changed, 1197 insertions, 489 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index f4d1284095..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
@@ -127,6 +129,7 @@ set(llui_HEADER_FILES
llflatlistview.h
llfloater.h
llfloaterreg.h
+ llfloaterreglistener.h
llflyoutbutton.h
llfocusmgr.h
llfunctorregistry.h
@@ -145,6 +148,7 @@ set(llui_HEADER_FILES
llmultisliderctrl.h
llmultislider.h
llnotifications.h
+ llnotificationslistener.h
llpanel.h
llprogressbar.h
llradiogroup.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index fd369730d6..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;
@@ -153,17 +152,9 @@ LLButton::LLButton(const LLButton::Params& p)
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
@@ -486,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))
@@ -1095,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 7fc4997133..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; }
@@ -241,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();
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/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/llfloater.cpp b/indra/llui/llfloater.cpp
index 0c0c5921ce..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
@@ -1386,7 +1423,10 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock)
mButtonsEnabled[BUTTON_DOCK] = !mDocked;
mButtonsEnabled[BUTTON_UNDOCK] = mDocked;
updateButtons();
+
+ storeDockStateControl();
}
+
}
// static
@@ -1399,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
{
@@ -1558,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)
{
- static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor");
+ // We're using images for this floater's backgrounds
+ image->draw(getLocalRect(), UI_VERTEX_COLOR % alpha);
+ }
+ else
+ {
+ // 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);
+ }
}
}
@@ -1627,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())
@@ -1687,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)
@@ -1788,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]);
@@ -1801,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);
@@ -2123,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();
@@ -2498,6 +2543,11 @@ void LLFloater::setInstanceName(const std::string& name)
{
mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName);
}
+ if(!mDocStateControl.empty())
+ {
+ mDocStateControl = LLFloaterReg::declareDockStateControl(mInstanceName);
+ }
+
}
}
@@ -2538,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);
@@ -2549,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;
@@ -2565,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())
@@ -2609,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);
@@ -2626,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 123de12398..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,6 +212,7 @@ 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);
@@ -268,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);
@@ -294,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
@@ -308,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;
@@ -332,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/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/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index e053477d58..75905d0927 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -1544,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);
@@ -1608,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.
@@ -1632,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
{
@@ -1641,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*/));
}
}
}
@@ -1684,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,
@@ -1758,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,
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 3d7bbdff89..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(); }
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 cf013efca0..956e843987 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -459,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();
@@ -482,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 );
}
}
@@ -1460,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())
{
@@ -1480,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
@@ -1555,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);
@@ -2894,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)
{
@@ -3435,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());
@@ -3479,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 a0e51151c9..ef222bad60 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -40,6 +40,7 @@
#include "lldir.h"
#include "llsdserialize.h"
#include "lltrans.h"
+#include "llnotificationslistener.h"
#include <algorithm>
#include <boost/regex.hpp>
@@ -945,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 cd05db3c30..0d7cb74f70 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -102,6 +102,7 @@
#include "llfunctorregistry.h"
#include "llpointer.h"
#include "llinitparam.h"
+#include "llnotificationslistener.h"
class LLNotification;
typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
@@ -812,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
{
@@ -838,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);
@@ -917,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 095200ddc3..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");
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index e8db68ffbb..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; }
@@ -248,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/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index d8606c6889..5e17372fe9 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -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/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 732c01614b..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"
//----------------------------------------------------------------------------
@@ -153,6 +154,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mRightTabBtnOffset(p.tab_padding_right),
mTotalTabWidth(0),
mTabPosition(p.tab_position),
+ mFontHalign(p.font_halign),
+ mFont(p.font),
mFirstTabParams(p.first_tab),
mMiddleTabParams(p.middle_tab),
mLastTabParams(p.last_tab)
@@ -401,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++;
}
@@ -641,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;
}
@@ -836,8 +827,6 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
// 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);
@@ -847,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
@@ -934,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
@@ -950,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(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);
@@ -965,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;
@@ -1002,7 +988,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM;
}
- btn = LLUICtrlFactory::create<LLButton>(p);
+++ btn = LLUICtrlFactory::create<LLButton>(p);
}
}
@@ -1505,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();
@@ -1516,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 a81974cd42..be9c6c7d06 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -262,6 +262,9 @@ private:
S32 mTabHeight;
LLFrameTimer mDragAndDropDelayTimer;
+
+ LLFontGL::HAlign mFontHalign;
+ const LLFontGL* mFont;
TabParams mFirstTabParams;
TabParams mMiddleTabParams;
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 22cce755b0..97ba691341 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -232,7 +232,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
createDefaultSegment();
- updateTextRect();
+ updateRects();
}
LLTextBase::~LLTextBase()
@@ -419,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();
@@ -538,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,
@@ -940,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()
@@ -957,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
@@ -975,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();
@@ -1028,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;
}
}
@@ -1042,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();
@@ -1072,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;
@@ -1104,7 +1108,7 @@ void LLTextBase::reflow(S32 start_index)
S32_MAX);
S32 segment_width, segment_height;
- segment->getDimensions(seg_offset, character_count, 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;
@@ -1149,65 +1153,25 @@ void LLTextBase::reflow(S32 start_index)
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();
@@ -1244,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()
@@ -1468,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));
@@ -1499,9 +1463,7 @@ void LLTextBase::setText(const LLStringExplicit &utf8str)
appendText(text, false);
- //resetDirty();
onValueChange(0, getLength());
- needsReflow();
}
//virtual
@@ -1679,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 )
{
@@ -2075,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?
@@ -2084,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);
}
@@ -2121,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;
}
}
@@ -2135,7 +2136,7 @@ LLRect LLTextBase::getVisibleDocumentRect() const
LLTextSegment::~LLTextSegment()
{}
-void LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { width = 0; height = 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) {}
@@ -2218,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())
{
@@ -2358,21 +2364,13 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip)
mTooltip = tooltip;
}
-void LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
+bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
{
LLWString text = mEditor.getWText();
- // look for any printable character, then return the font height
- height = 0;
- for (S32 index = mStart + first_char; index < mStart + first_char + num_chars; ++index)
- {
- if (text[index] != '\n')
- {
- height = mFontHeight;
- break;
- }
- }
+ 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
@@ -2393,7 +2391,10 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
S32 last_char = mStart + segment_offset;
for (; last_char != mEnd; ++last_char)
{
- if (text[last_char] == '\n') break;
+ if (text[last_char] == '\n')
+ {
+ break;
+ }
}
// set max characters to length of segment, or to first newline
@@ -2411,12 +2412,14 @@ 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 terminating NULL
- num_chars++;
- }
- else if (text[mStart + segment_offset + num_chars] == '\n')
+
+ // 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'))
{
num_chars++;
}
@@ -2439,12 +2442,14 @@ void LLNormalTextSegment::dump() const
// LLInlineViewSegment
//
-LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end, bool force_new_line, S32 hpad, S32 vpad)
+LLInlineViewSegment::LLInlineViewSegment(const Params& p, S32 start, S32 end)
: LLTextSegment(start, end),
- mView(view),
- mForceNewLine(force_new_line),
- mHPad(hpad), // one sided padding (applied to left and right)
- mVPad(vpad)
+ mView(p.view),
+ mForceNewLine(p.force_newline),
+ mLeftPad(p.left_pad),
+ mRightPad(p.right_pad),
+ mTopPad(p.top_pad),
+ mBottomPad(p.bottom_pad)
{
}
@@ -2453,7 +2458,7 @@ LLInlineViewSegment::~LLInlineViewSegment()
mView->die();
}
-void LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
+bool LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
{
if (first_char == 0 && num_chars == 0)
{
@@ -2464,9 +2469,11 @@ void LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
}
else
{
- width = mHPad * 2 + mView->getRect().getWidth();
- height = mVPad * 2 + mView->getRect().getHeight();
+ 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
@@ -2488,14 +2495,14 @@ S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
void LLInlineViewSegment::updateLayout(const LLTextBase& editor)
{
LLRect start_rect = editor.getDocRectFromDocIndex(mStart);
- mView->setOrigin(start_rect.mLeft + mHPad, start_rect.mBottom + mVPad);
+ 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 padded width of widget
// widget is actually drawn during mDocumentView's draw()
- return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mHPad * 2);
+ 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 f0b8878491..8cae8fde22 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -154,6 +154,9 @@ 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;
@@ -294,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);
@@ -367,7 +370,7 @@ public:
LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){};
virtual ~LLTextSegment();
- virtual void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) 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);
@@ -418,7 +421,7 @@ 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*/ void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) 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);
@@ -459,9 +462,19 @@ public:
class LLInlineViewSegment : public LLTextSegment
{
public:
- LLInlineViewSegment(LLView* widget, S32 start, S32 end, bool force_new_line, S32 hpad = 0, S32 vpad = 0);
+ 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*/ void getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) 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);
@@ -470,8 +483,10 @@ public:
/*virtual*/ void linkToDocument(class LLTextBase* editor);
private:
- S32 mHPad;
- S32 mVPad;
+ 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 d507cf7ce4..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;
@@ -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 force_new_line, S32 hpad, S32 vpad)
+void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)
{
// Save old state
S32 selection_start = mSelectionStart;
@@ -2290,12 +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
- 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(), force_new_line, hpad, vpad);
+ LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size());
insert(getLength(), widget_wide_text, FALSE, segment);
needsReflow();
@@ -2318,7 +2350,7 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
setCursorPos(cursor_pos);
}
- if( !allow_undo )
+ if (!allow_undo)
{
blockUndo();
}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 481a4d1a78..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 force_newline, S32 hpad, S32 vpad);
+ 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 c8094f9c7c..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";
@@ -186,25 +191,84 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
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()));
@@ -255,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)
{
@@ -263,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;
@@ -378,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;
@@ -390,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()
@@ -401,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 f253857851..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;
}
@@ -1952,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 6ab78ab3cd..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*>
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 0faff5eff6..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)
{
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 45fe47772b..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,
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 52e4229fb4..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)
@@ -390,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()
{
@@ -433,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, "://");
}
//
@@ -468,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
@@ -475,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)
{
@@ -483,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;
@@ -505,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/");
}
///
@@ -599,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 249c7320d6..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());
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 31f12fe312..fe7fd59de8 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -438,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;
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 73146b2c1f..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 );