summaryrefslogtreecommitdiff
path: root/indra/llui/llview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llview.cpp')
-rw-r--r--indra/llui/llview.cpp2079
1 files changed, 1025 insertions, 1054 deletions
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 2350ea6050..f1b08c380b 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -33,6 +33,7 @@
#include "linden_common.h"
+#define LLVIEW_CPP
#include "llview.h"
#include <cassert>
@@ -40,7 +41,6 @@
#include "llrender.h"
#include "llevent.h"
-#include "llfontgl.h"
#include "llfocusmgr.h"
#include "llrect.h"
#include "llstl.h"
@@ -49,6 +49,7 @@
#include "llwindow.h"
#include "v3color.h"
#include "lluictrlfactory.h"
+#include "lltooltip.h"
// for ui edit hack
#include "llbutton.h"
@@ -56,95 +57,106 @@
#include "lltexteditor.h"
#include "lltextbox.h"
-//HACK: this allows you to instantiate LLView from xml with "<view/>" which we don't want
-static LLRegisterWidget<LLView> r("view");
-
-BOOL LLView::sDebugRects = FALSE;
-BOOL LLView::sDebugKeys = FALSE;
S32 LLView::sDepth = 0;
-BOOL LLView::sDebugMouseHandling = FALSE;
+bool LLView::sDebugRects = false;
+bool LLView::sDebugRectsShowNames = true;
+bool LLView::sDebugKeys = false;
+bool LLView::sDebugMouseHandling = false;
std::string LLView::sMouseHandlerMessage;
-BOOL LLView::sEditingUI = FALSE;
BOOL LLView::sForceReshape = FALSE;
-LLView* LLView::sEditingUIView = NULL;
+std::set<LLView*> LLView::sPreviewHighlightedElements;
+BOOL LLView::sHighlightingDiffs = FALSE;
+LLView* LLView::sPreviewClickedElement = NULL;
+BOOL LLView::sDrawPreviewHighlights = FALSE;
S32 LLView::sLastLeftXML = S32_MIN;
S32 LLView::sLastBottomXML = S32_MIN;
+std::vector<LLViewDrawContext*> LLViewDrawContext::sDrawContextStack;
+
#if LL_DEBUG
BOOL LLView::sIsDrawing = FALSE;
#endif
-LLView::LLView() :
- mParentView(NULL),
- mReshapeFlags(FOLLOWS_NONE),
- mDefaultTabGroup(0),
- mEnabled(TRUE),
- mMouseOpaque(TRUE),
- mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
- mSaveToXML(TRUE),
- mIsFocusRoot(FALSE),
- mLastVisible(TRUE),
- mUseBoundingRect(FALSE),
- mVisible(TRUE),
- mNextInsertionOrdinal(0),
- mHoverCursor(UI_CURSOR_ARROW)
-{
-}
-
-LLView::LLView(const std::string& name, BOOL mouse_opaque) :
+// Compiler optimization, generate extern template
+template class LLView* LLView::getChild<class LLView>(
+ const std::string& name, BOOL recurse) const;
+
+static LLDefaultChildRegistry::Register<LLView> r("view");
+
+LLView::Follows::Follows()
+: string(""),
+ flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP)
+{}
+
+LLView::Params::Params()
+: name("name", std::string("unnamed")),
+ enabled("enabled", true),
+ visible("visible", true),
+ mouse_opaque("mouse_opaque", true),
+ follows("follows"),
+ hover_cursor("hover_cursor", "UI_CURSOR_ARROW"),
+ use_bounding_rect("use_bounding_rect", false),
+ tab_group("tab_group", 0),
+ default_tab_group("default_tab_group"),
+ tool_tip("tool_tip"),
+ sound_flags("sound_flags", MOUSE_UP),
+ layout("layout"),
+ rect("rect"),
+ bottom_delta("bottom_delta", S32_MAX),
+ top_pad("top_pad"),
+ top_delta("top_delta", S32_MAX),
+ left_pad("left_pad"),
+ left_delta("left_delta", S32_MAX),
+ center_horiz("center_horiz", false),
+ center_vert("center_vert", false),
+ from_xui("from_xui", false),
+ user_resize("user_resize"),
+ auto_resize("auto_resize"),
+ needs_translate("translate"),
+ xmlns("xmlns"),
+ xmlns_xsi("xmlns:xsi"),
+ xsi_schemaLocation("xsi:schemaLocation"),
+ xsi_type("xsi:type")
+
+{
+ addSynonym(rect, "");
+}
+
+LLView::LLView(const LLView::Params& p)
+: mName(p.name),
mParentView(NULL),
- mName(name),
mReshapeFlags(FOLLOWS_NONE),
- mDefaultTabGroup(0),
- mEnabled(TRUE),
- mMouseOpaque(mouse_opaque),
- mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
- mSaveToXML(TRUE),
+ mFromXUI(p.from_xui),
mIsFocusRoot(FALSE),
- mLastVisible(TRUE),
- mUseBoundingRect(FALSE),
- mVisible(TRUE),
+ mLastVisible(FALSE),
mNextInsertionOrdinal(0),
- mHoverCursor(UI_CURSOR_ARROW)
-{
-}
-
-
-LLView::LLView(
- const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) :
- mParentView(NULL),
- mName(name),
- mRect(rect),
- mBoundingRect(rect),
- mReshapeFlags(reshape),
- mDefaultTabGroup(0),
- mEnabled(TRUE),
- mMouseOpaque(mouse_opaque),
- mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
- mSaveToXML(TRUE),
- mIsFocusRoot(FALSE),
- mLastVisible(TRUE),
- mUseBoundingRect(FALSE),
- mVisible(TRUE),
- mNextInsertionOrdinal(0),
- mHoverCursor(UI_CURSOR_ARROW)
+ mHoverCursor(getCursorFromString(p.hover_cursor)),
+ mEnabled(p.enabled),
+ mVisible(p.visible),
+ mMouseOpaque(p.mouse_opaque),
+ mSoundFlags(p.sound_flags),
+ mUseBoundingRect(p.use_bounding_rect),
+ mDefaultTabGroup(p.default_tab_group),
+ mLastTabGroup(0),
+ mToolTipMsg((LLStringExplicit)p.tool_tip()),
+ mDefaultWidgets(NULL)
{
+ // create rect first, as this will supply initial follows flags
+ setShape(p.rect);
+ parseFollowsFlags(p);
}
-
LLView::~LLView()
{
+ dirtyRect();
//llinfos << "Deleting view " << mName << ":" << (void*) this << llendl;
// llassert(LLView::sIsDrawing == FALSE);
- if( gFocusMgr.getKeyboardFocus() == this )
- {
- llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl;
- gFocusMgr.removeKeyboardFocusWithoutCallback( this );
- }
-
+
+// llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators
+
if( hasMouseCapture() )
{
- llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl;
+ //llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl;
gFocusMgr.removeMouseCaptureWithoutCallback( this );
}
@@ -155,22 +167,13 @@ LLView::~LLView()
mParentView->removeChild(this);
}
- dispatch_list_t::iterator itor;
- for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
+ if (mDefaultWidgets)
{
- (*itor).second->clearDispatchers();
+ std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(),
+ DeletePairedPointer());
+ delete mDefaultWidgets;
+ mDefaultWidgets = NULL;
}
-
- std::for_each(mFloaterControls.begin(), mFloaterControls.end(),
- DeletePairedPointer());
- std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(),
- DeletePairedPointer());
-}
-
-// virtual
-BOOL LLView::isView() const
-{
- return TRUE;
}
// virtual
@@ -185,7 +188,6 @@ BOOL LLView::isPanel() const
return FALSE;
}
-// virtual
void LLView::setToolTip(const LLStringExplicit& msg)
{
mToolTipMsg = msg;
@@ -224,27 +226,38 @@ BOOL LLView::getUseBoundingRect()
}
// virtual
-const std::string& LLView::getName() const
+std::string LLView::getName() const
{
- static const std::string unnamed("(no name)");
- return mName.empty() ? unnamed : mName;
+ return mName.empty() ? std::string("(no name)") : mName;
}
void LLView::sendChildToFront(LLView* child)
{
+// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
if (child && child->getParent() == this)
{
- mChildList.remove( child );
- mChildList.push_front(child);
+ // minor optimization, but more importantly,
+ // won't temporarily create an empty list
+ if (child != mChildList.front())
+ {
+ mChildList.remove( child );
+ mChildList.push_front(child);
+ }
}
}
void LLView::sendChildToBack(LLView* child)
{
+// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
if (child && child->getParent() == this)
{
- mChildList.remove( child );
- mChildList.push_back(child);
+ // minor optimization, but more importantly,
+ // won't temporarily create an empty list
+ if (child != mChildList.back())
+ {
+ mChildList.remove( child );
+ mChildList.push_back(child);
+ }
}
}
@@ -264,12 +277,18 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
}
}
-void LLView::addChild(LLView* child, S32 tab_group)
+// virtual
+bool LLView::addChild(LLView* child, S32 tab_group)
{
+ if (!child)
+ {
+ return false;
+ }
if (mParentView == child)
{
llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
}
+
// remove from current parent
if (child->mParentView)
{
@@ -282,55 +301,46 @@ void LLView::addChild(LLView* child, S32 tab_group)
// add to ctrl list if is LLUICtrl
if (child->isCtrl())
{
- // controls are stored in reverse order from render order
- addCtrlAtEnd((LLUICtrl*) child, tab_group);
+ LLUICtrl* ctrl = static_cast<LLUICtrl*>(child);
+ mCtrlOrder.insert(tab_order_pair_t(ctrl,
+ tab_order_t(tab_group, mNextInsertionOrdinal)));
+
+ mNextInsertionOrdinal++;
}
child->mParentView = this;
updateBoundingRect();
+ mLastTabGroup = tab_group;
+ return true;
}
-void LLView::addChildAtEnd(LLView* child, S32 tab_group)
+bool LLView::addChildInBack(LLView* child, S32 tab_group)
{
- if (mParentView == child)
- {
- llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
- }
- // remove from current parent
- if (child->mParentView)
+ if(addChild(child, tab_group))
{
- child->mParentView->removeChild(child);
+ sendChildToBack(child);
+ return true;
}
- // add to back of child list
- mChildList.push_back(child);
-
- // add to ctrl list if is LLUICtrl
- if (child->isCtrl())
- {
- // controls are stored in reverse order from render order
- addCtrl((LLUICtrl*) child, tab_group);
- }
-
- child->mParentView = this;
- updateBoundingRect();
+ return false;
}
// remove the specified child from the view, and set it's parent to NULL.
-void LLView::removeChild(LLView* child, BOOL deleteIt)
+void LLView::removeChild(LLView* child)
{
+ //llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
if (child->mParentView == this)
{
mChildList.remove( child );
child->mParentView = NULL;
if (child->isCtrl())
{
- removeCtrl((LLUICtrl*)child);
- }
- if (deleteIt)
- {
- delete child;
+ child_tab_order_t::iterator found = mCtrlOrder.find(static_cast<LLUICtrl*>(child));
+ if(found != mCtrlOrder.end())
+ {
+ mCtrlOrder.erase(found);
+ }
}
}
else
@@ -340,28 +350,6 @@ void LLView::removeChild(LLView* child, BOOL deleteIt)
updateBoundingRect();
}
-void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
-{
- mCtrlOrder.insert(tab_order_pair_t(ctrl,
- tab_order_t(tab_group, mNextInsertionOrdinal++)));
-}
-
-void LLView::addCtrl( LLUICtrl* ctrl, S32 tab_group)
-{
- // add to front of list by using negative ordinal, which monotonically increases
- mCtrlOrder.insert(tab_order_pair_t(ctrl,
- tab_order_t(tab_group, -1 * mNextInsertionOrdinal++)));
-}
-
-void LLView::removeCtrl(LLUICtrl* ctrl)
-{
- child_tab_order_t::iterator found = mCtrlOrder.find(ctrl);
- if(found != mCtrlOrder.end())
- {
- mCtrlOrder.erase(found);
- }
-}
-
LLView::ctrl_list_t LLView::getCtrlList() const
{
ctrl_list_t controls;
@@ -411,32 +399,28 @@ bool LLCompareByTabOrder::operator() (const LLView* const a, const LLView* const
return (a_score == b_score) ? a < b : a_score < b_score;
}
-BOOL LLView::isInVisibleChain() const
+bool LLView::trueToRoot(const boost::function<bool (const LLView*)>& predicate) const
{
const LLView* cur_view = this;
while(cur_view)
{
- if (!cur_view->getVisible())
+ if(!predicate(cur_view))
{
- return FALSE;
+ return false;
}
cur_view = cur_view->getParent();
}
- return TRUE;
+ return true;
+}
+
+BOOL LLView::isInVisibleChain() const
+{
+ return trueToRoot(&LLView::getVisible);
}
BOOL LLView::isInEnabledChain() const
{
- const LLView* cur_view = this;
- while(cur_view)
- {
- if (!cur_view->getEnabled())
- {
- return FALSE;
- }
- cur_view = cur_view->getParent();
- }
- return TRUE;
+ return trueToRoot(&LLView::getEnabled);
}
// virtual
@@ -463,31 +447,33 @@ void LLView::setEnabled(BOOL enabled)
}
//virtual
-BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
+bool LLView::isAvailable() const
{
- return FALSE;
+ return isInEnabledChain() && isInVisibleChain();
}
-//virtual
-LLRect LLView::getSnapRect() const
+//static
+bool LLView::isAvailable(const LLView* view)
{
- return mRect;
+ return view && view->isAvailable();
}
//virtual
-LLRect LLView::getRequiredRect()
+BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
{
- return mRect;
+ return FALSE;
}
//virtual
-void LLView::onFocusLost()
+LLRect LLView::getSnapRect() const
{
+ return mRect;
}
//virtual
-void LLView::onFocusReceived()
+LLRect LLView::getRequiredRect()
{
+ return mRect;
}
BOOL LLView::focusNextRoot()
@@ -617,14 +603,15 @@ void LLView::setVisible(BOOL visible)
if (!getParent() || getParent()->isInVisibleChain())
{
// tell all children of this view that the visibility may have changed
- onVisibilityChange( visible );
+ dirtyRect();
+ handleVisibilityChange( visible );
}
updateBoundingRect();
}
}
// virtual
-void LLView::onVisibilityChange ( BOOL new_visibility )
+void LLView::handleVisibilityChange ( BOOL new_visibility )
{
for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
@@ -632,7 +619,7 @@ void LLView::onVisibilityChange ( BOOL new_visibility )
// only views that are themselves visible will have their overall visibility affected by their ancestors
if (viewp->getVisible())
{
- viewp->onVisibilityChange ( new_visibility );
+ viewp->handleVisibilityChange ( new_visibility );
}
}
}
@@ -651,119 +638,111 @@ BOOL LLView::canSnapTo(const LLView* other_view)
}
// virtual
-void LLView::snappedTo(const LLView* snap_view)
+void LLView::setSnappedTo(const LLView* snap_view)
{
}
BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
{
- BOOL handled = childrenHandleHover( x, y, mask ) != NULL;
- if( !handled
- && blockMouseEvent(x, y) )
- {
- LLUI::sWindow->setCursor(mHoverCursor);
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
- handled = TRUE;
- }
+ return childrenHandleHover( x, y, mask ) != NULL;
+}
- return handled;
+void LLView::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ //llinfos << "Mouse entered " << getName() << llendl;
}
-std::string LLView::getShowNamesToolTip()
+void LLView::onMouseLeave(S32 x, S32 y, MASK mask)
{
- LLView* view = getParent();
- std::string name;
- std::string tool_tip = mName;
+ //llinfos << "Mouse left " << getName() << llendl;
+}
- while (view)
- {
- name = view->getName();
- if (name == "root") break;
+LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
+{
+ LLView* handled_view = NULL;
+ for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ {
+ LLView* viewp = *child_it;
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if(!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible())
+ {
+ continue;
+ }
- if (view->getToolTip().find(".xml") != std::string::npos)
+ if (viewp->handleToolTip(local_x, local_y, mask) )
{
- tool_tip = view->getToolTip() + "/" + tool_tip;
+ if (sDebugMouseHandling)
+ {
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
+ }
+
+ handled_view = viewp;
break;
}
- else
+
+ if (viewp->blockMouseEvent(local_x, local_y))
{
- tool_tip = view->getName() + "/" + tool_tip;
+ handled_view = viewp;
+ break;
}
-
- view = view->getParent();
}
-
- return "/" + tool_tip;
+ return handled_view;
}
-BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen)
+LLView* LLView::childFromPoint(S32 x, S32 y)
{
- BOOL handled = FALSE;
-
- std::string tool_tip;
-
+ if (!getVisible() )
+ return false;
for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
LLView* viewp = *child_it;
- S32 local_x = x - viewp->mRect.mLeft;
- S32 local_y = y - viewp->mRect.mBottom;
- // Allow tooltips for disabled views so we can explain to the user why
- // the view is disabled. JC
- if( viewp->pointInView(local_x, local_y)
- && viewp->getVisible()
- // && viewp->getEnabled()
- && viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ))
- {
- // child provided a tooltip, just return
- if (!msg.empty()) return TRUE;
-
- // otherwise, one of our children ate the event so don't traverse
- // siblings however, our child did not actually provide a tooltip
- // so we might want to
- handled = TRUE;
- break;
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible() )
+ {
+ continue;
}
- }
+ return viewp;
- // get our own tooltip
- tool_tip = mToolTipMsg.getString();
- if (
- LLUI::sShowXUINames
- && (tool_tip.find(".xml", 0) == std::string::npos)
- && (mName.find("Drag", 0) == std::string::npos))
- {
- tool_tip = getShowNamesToolTip();
}
+ return 0;
+}
- BOOL show_names_text_box = LLUI::sShowXUINames && dynamic_cast<LLTextBox*>(this) != NULL;
+BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = FALSE;
- // don't allow any siblings to handle this event
- // even if we don't have a tooltip
- if (getMouseOpaque() || show_names_text_box)
+ // parents provide tooltips first, which are optionally
+ // overridden by children, in case child is mouse_opaque
+ if (!mToolTipMsg.empty())
{
+ // allow "scrubbing" over ui by showing next tooltip immediately
+ // if previous one was still visible
+ F32 timeout = LLToolTipMgr::instance().toolTipVisible()
+ ? 0.f
+ : LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(mToolTipMsg)
+ .sticky_rect(calcScreenRect())
+ .delay_time(timeout));
+
handled = TRUE;
}
- if(!tool_tip.empty())
+ // child tooltips will override our own
+ LLView* child_handler = childrenHandleToolTip(x, y, mask);
+ if (child_handler)
{
- msg = tool_tip;
-
- // Convert rect local to screen coordinates
- localPointToScreen(
- 0, 0,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- localPointToScreen(
- mRect.getWidth(), mRect.getHeight(),
- &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
-
handled = TRUE;
}
return handled;
}
-
BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
{
BOOL handled = FALSE;
@@ -844,20 +823,7 @@ BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EAcceptance* accept,
std::string& tooltip_msg)
{
- // CRO this is an experiment to allow drag and drop into object inventory based on the DragAndDrop tool's permissions rather than the parent
- BOOL handled = childrenHandleDragAndDrop( x, y, mask, drop,
- cargo_type,
- cargo_data,
- accept,
- tooltip_msg) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- *accept = ACCEPT_NO;
- handled = TRUE;
- lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLView " << getName() << llendl;
- }
-
- return handled;
+ return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL;
}
LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
@@ -867,28 +833,33 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
EAcceptance* accept,
std::string& tooltip_msg)
{
- LLView* handled_view = FALSE;
- // CRO this is an experiment to allow drag and drop into object inventory based on the DragAndDrop tool's permissions rather than the parent
- if( getVisible() )
-// if( getVisible() && getEnabled() )
+ LLView* handled_view = NULL;
+ for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ LLView* viewp = *child_it;
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if( !viewp->pointInView(local_x, local_y) ||
+ !viewp->getVisible() ||
+ !viewp->getEnabled())
{
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if( viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleDragAndDrop(local_x, local_y, mask, drop,
- cargo_type,
- cargo_data,
- accept,
- tooltip_msg))
- {
- handled_view = viewp;
- break;
- }
+ continue;
+ }
+ if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
+ cargo_type,
+ cargo_data,
+ accept,
+ tooltip_msg))
+ {
+ handled_view = viewp;
+ break;
+ }
+
+ if (viewp->blockMouseEvent(x, y))
+ {
+ *accept = ACCEPT_NO;
+ handled_view = viewp;
+ break;
}
}
return handled_view;
@@ -905,110 +876,42 @@ BOOL LLView::hasMouseCapture()
BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
{
- BOOL handled = childrenHandleMouseUp( x, y, mask ) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- }
- return handled;
+ return childrenHandleMouseUp( x, y, mask ) != NULL;
}
BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = childrenHandleMouseDown( x, y, mask );
- BOOL handled = (handled_view != NULL);
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- handled_view = this;
- }
-
- // HACK If we're editing UI, select the leaf view that ate the click.
- if (sEditingUI && handled_view)
- {
- // need to find leaf views, big hack
- LLButton* buttonp = dynamic_cast<LLButton*>(handled_view);
- LLLineEditor* line_editorp = dynamic_cast<LLLineEditor*>(handled_view);
- LLTextEditor* text_editorp = dynamic_cast<LLTextEditor*>(handled_view);
- LLTextBox* text_boxp = dynamic_cast<LLTextBox*>(handled_view);
- if (buttonp
- || line_editorp
- || text_editorp
- || text_boxp)
- {
- sEditingUIView = handled_view;
- }
- }
-
- return handled;
+ return childrenHandleMouseDown( x, y, mask ) != NULL;
}
BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
{
- BOOL handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- handleMouseDown(x, y, mask);
- handled = TRUE;
- }
- return handled;
+ return childrenHandleDoubleClick( x, y, mask ) != NULL;
}
BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
- BOOL handled = FALSE;
- if( getVisible() && getEnabled() )
- {
- handled = childrenHandleScrollWheel( x, y, clicks ) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- }
- }
- return handled;
+ return childrenHandleScrollWheel( x, y, clicks ) != NULL;
}
BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
- BOOL handled = childrenHandleRightMouseDown( x, y, mask ) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- }
- return handled;
+ return childrenHandleRightMouseDown( x, y, mask ) != NULL;
}
BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask)
{
- BOOL handled = childrenHandleRightMouseUp( x, y, mask ) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- }
- return handled;
+ return childrenHandleRightMouseUp( x, y, mask ) != NULL;
}
BOOL LLView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
{
- LLView* handled_view = childrenHandleMiddleMouseDown( x, y, mask );
- BOOL handled = (handled_view != NULL);
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- handled_view = this;
- }
-
- return handled;
+ return childrenHandleMiddleMouseDown( x, y, mask ) != NULL;
}
BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
{
- BOOL handled = childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
- if( !handled && blockMouseEvent(x, y) )
- {
- handled = TRUE;
- }
- return handled;
+ return childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
}
@@ -1022,14 +925,18 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y)
- && viewp->getVisible()
- && viewp->getEnabled()
- && viewp->handleScrollWheel( local_x, local_y, clicks ))
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if (viewp->handleScrollWheel( local_x, local_y, clicks ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
@@ -1050,19 +957,31 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if(viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleHover(local_x, local_y, mask) )
+ if(!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if (viewp->handleHover(local_x, local_y, mask) )
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if (viewp->blockMouseEvent(local_x, local_y))
+ {
+ LLUI::sWindow->setCursor(viewp->getHoverCursor());
+
+ handled_view = viewp;
+ break;
+ }
}
}
return handled_view;
@@ -1128,18 +1047,28 @@ LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleMouseDown( local_x, local_y, mask ))
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if(viewp->handleMouseDown( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if(viewp->blockMouseEvent(local_x, local_y))
+ {
+ handled_view = viewp;
+ break;
+ }
}
return handled_view;
}
@@ -1155,15 +1084,27 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleRightMouseDown( local_x, local_y, mask ))
+
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if (viewp->handleRightMouseDown( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
+
+ handled_view = viewp;
+ break;
+ }
+
+ if (viewp->blockMouseEvent(local_x, local_y))
+ {
handled_view = viewp;
break;
}
@@ -1183,18 +1124,28 @@ LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleMiddleMouseDown( local_x, local_y, mask ))
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if(viewp->handleMiddleMouseDown( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if (viewp->blockMouseEvent(local_x, local_y))
+ {
+ handled_view = viewp;
+ break;
+ }
}
}
return handled_view;
@@ -1211,18 +1162,29 @@ LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleDoubleClick( local_x, local_y, mask ))
+
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if (viewp->handleDoubleClick( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if (viewp->blockMouseEvent(local_x, local_y))
+ {
+ handled_view = viewp;
+ break;
+ }
}
}
return handled_view;
@@ -1238,21 +1200,28 @@ LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (!viewp->pointInView(local_x, local_y))
- continue;
- if (!viewp->getVisible())
- continue;
- if (!viewp->getEnabled())
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
continue;
+ }
+
if (viewp->handleMouseUp( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if (viewp->blockMouseEvent(local_x, local_y))
+ {
+ handled_view = viewp;
+ break;
+ }
}
}
return handled_view;
@@ -1268,18 +1237,28 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleRightMouseUp( local_x, local_y, mask ))
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled() )
+ {
+ continue;
+ }
+
+ if(viewp->handleRightMouseUp( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if(viewp->blockMouseEvent(local_x, local_y))
+ {
+ handled_view = viewp;
+ break;
+ }
}
}
return handled_view;
@@ -1295,18 +1274,28 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
LLView* viewp = *child_it;
S32 local_x = x - viewp->getRect().mLeft;
S32 local_y = y - viewp->getRect().mBottom;
- if (viewp->pointInView(local_x, local_y) &&
- viewp->getVisible() &&
- viewp->getEnabled() &&
- viewp->handleMiddleMouseUp( local_x, local_y, mask ))
+ if (!viewp->pointInView(local_x, local_y)
+ || !viewp->getVisible()
+ || !viewp->getEnabled())
+ {
+ continue;
+ }
+
+ if(viewp->handleMiddleMouseUp( local_x, local_y, mask ))
{
if (sDebugMouseHandling)
{
- sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
+ sMouseHandlerMessage = std::string("/") + viewp->mName + sMouseHandlerMessage;
}
handled_view = viewp;
break;
}
+
+ if (viewp->blockMouseEvent(local_x, local_y))
+ {
+ handled_view = viewp;
+ break;
+ }
}
}
return handled_view;
@@ -1314,67 +1303,77 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
void LLView::draw()
{
- if (sDebugRects)
- {
- drawDebugRect();
-
- // Check for bogus rectangle
- if (getRect().mRight <= getRect().mLeft
- || getRect().mTop <= getRect().mBottom)
- {
- llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
- }
- }
-
- LLRect rootRect = getRootView()->getRect();
- LLRect screenRect;
+ drawChildren();
+}
- // draw focused control on top of everything else
- LLView* focus_view = gFocusMgr.getKeyboardFocus();
- if (focus_view && focus_view->getParent() != this)
+void LLView::drawChildren()
+{
+ if (!mChildList.empty())
{
- focus_view = NULL;
- }
+ LLRect rootRect = getRootView()->getRect();
+ LLRect screenRect;
- ++sDepth;
- for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
- {
- LLView *viewp = *child_iter;
+ ++sDepth;
- if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid())
+ for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter)
{
- // Only draw views that are within the root view
- localRectToScreen(viewp->getRect(),&screenRect);
- if ( rootRect.rectInRect(&screenRect) )
+ child_list_reverse_iter_t child = child_iter++;
+ LLView *viewp = *child;
+
+ if (viewp->getVisible() && viewp->getRect().isValid())
{
- glMatrixMode(GL_MODELVIEW);
- LLUI::pushMatrix();
+ // Only draw views that are within the root view
+ localRectToScreen(viewp->getRect(),&screenRect);
+ if ( rootRect.overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect))
{
- LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
- viewp->draw();
+ glMatrixMode(GL_MODELVIEW);
+ LLUI::pushMatrix();
+ {
+ LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
+ viewp->draw();
+
+ if (sDebugRects)
+ {
+ viewp->drawDebugRect();
+
+ // Check for bogus rectangle
+ if (!getRect().isValid())
+ {
+ llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
+ }
+ }
+ }
+ LLUI::popMatrix();
}
- LLUI::popMatrix();
}
- }
+ }
+ --sDepth;
}
- --sDepth;
- if (focus_view && focus_view->getVisible())
- {
- drawChild(focus_view);
- }
+ gGL.getTexUnit(0)->disable();
+}
- // HACK
- if (sEditingUI && this == sEditingUIView)
- {
- drawDebugRect();
+void LLView::dirtyRect()
+{
+ LLView* child = getParent();
+ LLView* parent = child ? child->getParent() : NULL;
+ LLView* cur = this;
+ while (child && parent && parent->getParent())
+ { //find third to top-most view
+ cur = child;
+ child = parent;
+ parent = parent->getParent();
}
+
+ LLUI::dirtyRect(cur->calcScreenRect());
}
//Draw a box for debugging.
void LLView::drawDebugRect()
{
+ std::set<LLView*>::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); // figure out if it's a previewed element
+
LLUI::pushMatrix();
{
// drawing solids requires texturing be disabled
@@ -1388,10 +1387,18 @@ void LLView::drawDebugRect()
LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
// draw red rectangle for the border
- LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
- if (sEditingUI)
+ LLColor4 border_color(0.25f, 0.25f, 0.25f, 1.f);
+ if(preview_iter != sPreviewHighlightedElements.end())
{
- border_color.mV[0] = 1.f;
+ if(LLView::sPreviewClickedElement && this == sPreviewClickedElement)
+ {
+ border_color = LLColor4::red;
+ }
+ else
+ {
+ static LLUIColor scroll_highlighted_color = LLUIColorTable::instance().getColor("ScrollHighlightedColor");
+ border_color = scroll_highlighted_color;
+ }
}
else
{
@@ -1414,8 +1421,10 @@ void LLView::drawDebugRect()
gGL.vertex2i(0, debug_rect.getHeight() - 1);
gGL.end();
- // Draw the name if it's not a leaf node
- if (mChildList.size() && !sEditingUI)
+ // Draw the name if it's not a leaf node or not in editing or preview mode
+ if (mChildList.size()
+ && preview_iter == sPreviewHighlightedElements.end()
+ && sDebugRectsShowNames)
{
//char temp[256];
S32 x, y;
@@ -1425,7 +1434,7 @@ void LLView::drawDebugRect()
std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
debug_rect.getWidth(), debug_rect.getHeight());
LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
- LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
+ LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, S32_MAX, NULL, FALSE);
}
}
@@ -1529,45 +1538,53 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
updateBoundingRect();
}
-void LLView::updateBoundingRect()
+LLRect LLView::calcBoundingRect()
{
- if (isDead()) return;
+ LLRect local_bounding_rect = LLRect::null;
- if (mUseBoundingRect)
+ child_list_const_iter_t child_it;
+ for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
- LLRect local_bounding_rect = LLRect::null;
-
- child_list_const_iter_t child_it;
- for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ LLView* childp = *child_it;
+ // ignore invisible and "top" children when calculating bounding rect
+ // such as combobox popups
+ if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl())
{
- LLView* childp = *child_it;
- // ignore invisible and "top" children when calculating bounding rect
- // such as combobox popups
- if (!childp->getVisible() || childp == gFocusMgr.getTopCtrl())
- {
- continue;
- }
+ continue;
+ }
- LLRect child_bounding_rect = childp->getBoundingRect();
+ LLRect child_bounding_rect = childp->getBoundingRect();
- if (local_bounding_rect.isNull())
- {
- // start out with bounding rect equal to first visible child's bounding rect
- local_bounding_rect = child_bounding_rect;
- }
- else
+ if (local_bounding_rect.isEmpty())
+ {
+ // start out with bounding rect equal to first visible child's bounding rect
+ local_bounding_rect = child_bounding_rect;
+ }
+ else
+ {
+ // accumulate non-null children rectangles
+ if (!child_bounding_rect.isEmpty())
{
- // accumulate non-null children rectangles
- if (!child_bounding_rect.isNull())
- {
- local_bounding_rect.unionWith(child_bounding_rect);
- }
+ local_bounding_rect.unionWith(child_bounding_rect);
}
}
+ }
+
+ // convert to parent-relative coordinates
+ local_bounding_rect.translate(mRect.mLeft, mRect.mBottom);
+ return local_bounding_rect;
+}
+
- mBoundingRect = local_bounding_rect;
- // translate into parent-relative coordinates
- mBoundingRect.translate(mRect.mLeft, mRect.mBottom);
+void LLView::updateBoundingRect()
+{
+ if (isDead()) return;
+
+ LLRect cur_rect = mBoundingRect;
+
+ if (mUseBoundingRect)
+ {
+ mBoundingRect = calcBoundingRect();
}
else
{
@@ -1579,17 +1596,36 @@ void LLView::updateBoundingRect()
{
getParent()->updateBoundingRect();
}
+
+ if (mBoundingRect != cur_rect)
+ {
+ dirtyRect();
+ }
+
}
-LLRect LLView::getScreenRect() const
+LLRect LLView::calcScreenRect() const
{
- // *FIX: check for one-off error
LLRect screen_rect;
localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom);
localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop);
return screen_rect;
}
+LLRect LLView::calcScreenBoundingRect() const
+{
+ LLRect screen_rect;
+ // get bounding rect, if used
+ LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect;
+
+ // convert to local coordinates, as defined by mRect
+ bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
+
+ localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom);
+ localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop);
+ return screen_rect;
+}
+
LLRect LLView::getLocalBoundingRect() const
{
LLRect local_bounding_rect = getBoundingRect();
@@ -1636,7 +1672,7 @@ BOOL LLView::hasAncestor(const LLView* parentp) const
BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const
{
- LLView *child = getChildView(childname, TRUE, FALSE);
+ LLView *child = findChildView(childname, TRUE);
if (child)
{
return gFocusMgr.childHasKeyboardFocus(child);
@@ -1651,14 +1687,31 @@ BOOL LLView::childHasKeyboardFocus( const std::string& childname ) const
BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const
{
- return getChildView(childname, recurse, FALSE) != NULL;
+ return findChildView(childname, recurse) != NULL;
}
//-----------------------------------------------------------------------------
// getChildView()
//-----------------------------------------------------------------------------
-LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const
+LLView* LLView::getChildView(const std::string& name, BOOL recurse) const
+{
+ LLView* child = findChildView(name, recurse);
+ if (!child)
+ {
+ child = getDefaultWidget<LLView>(name);
+ if (!child)
+ {
+ child = LLUICtrlFactory::createDefaultWidget<LLView>(name);
+ }
+ }
+ return child;
+}
+
+static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Widgets");
+
+LLView* LLView::findChildView(const std::string& name, BOOL recurse) const
{
+ LLFastTimer ft(FTM_FIND_VIEWS);
//richard: should we allow empty names?
//if(name.empty())
// return NULL;
@@ -1678,18 +1731,13 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_
for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
LLView* childp = *child_it;
- LLView* viewp = childp->getChildView(name, recurse, FALSE);
+ LLView* viewp = childp->findChildView(name, recurse);
if ( viewp )
{
return viewp;
}
}
}
-
- if (create_if_missing)
- {
- return createDummyWidget<LLView>(name);
- }
return NULL;
}
@@ -1777,82 +1825,152 @@ LLView* LLView::getRootView()
return view;
}
-BOOL LLView::deleteViewByHandle(LLHandle<LLView> handle)
+LLView* LLView::findPrevSibling(LLView* child)
+{
+ child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child);
+ if (prev_it != mChildList.end() && prev_it != mChildList.begin())
+ {
+ return *(--prev_it);
+ }
+ return NULL;
+}
+
+LLView* LLView::findNextSibling(LLView* child)
+{
+ child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child);
+ if (next_it != mChildList.end())
+ {
+ next_it++;
+ }
+
+ return (next_it != mChildList.end()) ? *next_it : NULL;
+}
+
+void LLView::deleteViewByHandle(LLHandle<LLView> handle)
{
LLView* viewp = handle.get();
delete viewp;
- return viewp != NULL;
}
-// Moves the view so that it is entirely inside of constraint.
-// If the view will not fit because it's too big, aligns with the top and left.
-// (Why top and left? That's where the drag bars are for floaters.)
-BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside )
+LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, BOOL allow_partial_outside)
{
- S32 delta_x = 0;
- S32 delta_y = 0;
+ LLCoordGL delta;
if (allow_partial_outside)
{
const S32 KEEP_ONSCREEN_PIXELS = 16;
- if( getRect().mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft )
+ if( input.mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft )
{
- delta_x = constraint.mLeft - (getRect().mRight - KEEP_ONSCREEN_PIXELS);
+ delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS);
}
else
- if( getRect().mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight )
+ if( input.mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight )
{
- delta_x = constraint.mRight - (getRect().mLeft + KEEP_ONSCREEN_PIXELS);
+ delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS);
}
- if( getRect().mTop > constraint.mTop )
+ if( input.mTop > constraint.mTop )
{
- delta_y = constraint.mTop - getRect().mTop;
+ delta.mY = constraint.mTop - input.mTop;
}
else
- if( getRect().mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom )
+ if( input.mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom )
{
- delta_y = constraint.mBottom - (getRect().mTop - KEEP_ONSCREEN_PIXELS);
+ delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS);
}
}
else
{
- if( getRect().mLeft < constraint.mLeft )
+ if( input.mLeft < constraint.mLeft )
{
- delta_x = constraint.mLeft - getRect().mLeft;
+ delta.mX = constraint.mLeft - input.mLeft;
}
else
- if( getRect().mRight > constraint.mRight )
+ if( input.mRight > constraint.mRight )
{
- delta_x = constraint.mRight - getRect().mRight;
+ delta.mX = constraint.mRight - input.mRight;
// compensate for left edge possible going off screen
- delta_x += llmax( 0, getRect().getWidth() - constraint.getWidth() );
+ delta.mX += llmax( 0, input.getWidth() - constraint.getWidth() );
}
- if( getRect().mTop > constraint.mTop )
+ if( input.mTop > constraint.mTop )
{
- delta_y = constraint.mTop - getRect().mTop;
+ delta.mY = constraint.mTop - input.mTop;
}
else
- if( getRect().mBottom < constraint.mBottom )
+ if( input.mBottom < constraint.mBottom )
{
- delta_y = constraint.mBottom - getRect().mBottom;
+ delta.mY = constraint.mBottom - input.mBottom;
// compensate for top edge possible going off screen
- delta_y -= llmax( 0, getRect().getHeight() - constraint.getHeight() );
+ delta.mY -= llmax( 0, input.getHeight() - constraint.getHeight() );
}
}
- if (delta_x != 0 || delta_y != 0)
+ return delta;
+}
+
+// Moves the view so that it is entirely inside of constraint.
+// If the view will not fit because it's too big, aligns with the top and left.
+// (Why top and left? That's where the drag bars are for floaters.)
+BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside )
+{
+ LLCoordGL translation = getNeededTranslation(getRect(), constraint, allow_partial_outside);
+
+ if (translation.mX != 0 || translation.mY != 0)
+ {
+ translate(translation.mX, translation.mY);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// move this view into "inside" but not onto "exclude"
+// NOTE: if this view is already contained in "inside", we ignore the "exclude" rect
+BOOL LLView::translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, BOOL allow_partial_outside )
+{
+ LLCoordGL translation = getNeededTranslation(getRect(), inside, allow_partial_outside);
+
+ if (translation.mX != 0 || translation.mY != 0)
{
- translate(delta_x, delta_y);
+ // translate ourselves into constraint rect
+ translate(translation.mX, translation.mY);
+
+ // do we overlap with exclusion area?
+ // keep moving in the same direction to the other side of the exclusion rect
+ if (exclude.overlaps(getRect()))
+ {
+ // moving right
+ if (translation.mX > 0)
+ {
+ translate(exclude.mRight - getRect().mLeft, 0);
+ }
+ // moving left
+ else if (translation.mX < 0)
+ {
+ translate(exclude.mLeft - getRect().mRight, 0);
+ }
+
+ // moving up
+ if (translation.mY > 0)
+ {
+ translate(0, exclude.mTop - getRect().mBottom);
+ }
+ // moving down
+ else if (translation.mY < 0)
+ {
+ translate(0, exclude.mBottom - getRect().mTop);
+ }
+ }
+
return TRUE;
}
return FALSE;
}
+
void LLView::centerWithin(const LLRect& bounds)
{
S32 left = bounds.mLeft + (bounds.getWidth() - getRect().getWidth()) / 2;
@@ -1943,132 +2061,6 @@ BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* o
return FALSE;
}
-// virtual
-LLXMLNodePtr LLView::getXML(bool save_children) const
-{
- //FIXME: need to provide actual derived type tag, probably outside this method
- LLXMLNodePtr node = new LLXMLNode("view", FALSE);
-
- node->createChild("name", TRUE)->setStringValue(getName());
- node->createChild("width", TRUE)->setIntValue(getRect().getWidth());
- node->createChild("height", TRUE)->setIntValue(getRect().getHeight());
-
- LLView* parent = getParent();
- S32 left = getRect().mLeft;
- S32 bottom = getRect().mBottom;
- if (parent) bottom -= parent->getRect().getHeight();
-
- node->createChild("left", TRUE)->setIntValue(left);
- node->createChild("bottom", TRUE)->setIntValue(bottom);
-
- U32 follows_flags = getFollows();
- if (follows_flags)
- {
- std::stringstream buffer;
- bool pipe = false;
- if (followsLeft())
- {
- buffer << "left";
- pipe = true;
- }
- if (followsTop())
- {
- if (pipe) buffer << "|";
- buffer << "top";
- pipe = true;
- }
- if (followsRight())
- {
- if (pipe) buffer << "|";
- buffer << "right";
- pipe = true;
- }
- if (followsBottom())
- {
- if (pipe) buffer << "|";
- buffer << "bottom";
- }
- node->createChild("follows", TRUE)->setStringValue(buffer.str());
- }
- // Export all widgets as enabled and visible - code must disable.
- node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque );
- if (!mToolTipMsg.getString().empty())
- {
- node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg.getString());
- }
- if (mSoundFlags != MOUSE_UP)
- {
- node->createChild("sound_flags", TRUE)->setIntValue((S32)mSoundFlags);
- }
-
- node->createChild("enabled", TRUE)->setBoolValue(getEnabled());
-
- if (!mControlName.empty())
- {
- node->createChild("control_name", TRUE)->setStringValue(mControlName);
- }
- return node;
-}
-
-//static
-LLView* LLView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
- LLView* viewp = new LLView();
- viewp->initFromXML(node, parent);
- return viewp;
-}
-
-// static
-void LLView::addColorXML(LLXMLNodePtr node, const LLColor4& color,
- const char* xml_name, const char* control_name)
-{
- if (color != LLUI::sColorsGroup->getColor(ll_safe_string(control_name)))
- {
- node->createChild(xml_name, TRUE)->setFloatValue(4, color.mV);
- }
-}
-
-//static
-std::string LLView::escapeXML(const std::string& xml, std::string& indent)
-{
- std::string ret = indent + "\"" + LLXMLNode::escapeXML(xml);
-
- //replace every newline with a close quote, new line, indent, open quote
- size_t index = ret.size()-1;
- size_t fnd;
-
- while ((fnd = ret.rfind("\n", index)) != std::string::npos)
- {
- ret.replace(fnd, 1, "\"\n" + indent + "\"");
- index = fnd-1;
- }
-
- //append close quote
- ret.append("\"");
-
- return ret;
-}
-
-// static
-LLWString LLView::escapeXML(const LLWString& xml)
-{
- LLWString out;
- for (LLWString::size_type i = 0; i < xml.size(); ++i)
- {
- llwchar c = xml[i];
- switch(c)
- {
- case '"': out.append(utf8string_to_wstring("&quot;")); break;
- case '\'': out.append(utf8string_to_wstring("&apos;")); break;
- case '&': out.append(utf8string_to_wstring("&amp;")); break;
- case '<': out.append(utf8string_to_wstring("&lt;")); break;
- case '>': out.append(utf8string_to_wstring("&gt;")); break;
- default: out.push_back(c); break;
- }
- }
- return out;
-}
-
// static
const LLCtrlQuery & LLView::getTabOrderQuery()
{
@@ -2105,7 +2097,12 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()
}
-void LLView::userSetShape(const LLRect& new_rect)
+void LLView::setShape(const LLRect& new_rect, bool by_user)
+{
+ handleReshape(new_rect, by_user);
+}
+
+void LLView::handleReshape(const LLRect& new_rect, bool by_user)
{
reshape(new_rect.getWidth(), new_rect.getHeight());
translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom);
@@ -2353,560 +2350,534 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna
// Listener dispatch functions
//-----------------------------------------------------------------------------
-void LLView::registerEventListener(std::string name, LLSimpleListener* function)
-{
- mDispatchList.insert(std::pair<std::string, LLSimpleListener*>(name, function));
-}
-
-void LLView::deregisterEventListener(std::string name)
-{
- dispatch_list_t::iterator itor = mDispatchList.find(name);
- if (itor != mDispatchList.end())
- {
- mDispatchList.erase(itor);
- }
-}
-std::string LLView::findEventListener(LLSimpleListener *listener) const
+LLControlVariable *LLView::findControl(const std::string& name)
{
- dispatch_list_t::const_iterator itor;
- for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
+ // parse the name to locate which group it belongs to
+ std::size_t key_pos= name.find(".");
+ if(key_pos!= std::string::npos )
{
- if (itor->second == listener)
+ std::string control_group_key = name.substr(0, key_pos);
+ LLControlVariable* control;
+ // check if it's in the control group that name indicated
+ if(LLUI::sSettingGroups[control_group_key])
{
- return itor->first;
+ control = LLUI::sSettingGroups[control_group_key]->getControl(name);
+ if (control)
+ {
+ return control;
+ }
}
}
- if (mParentView)
- {
- return mParentView->findEventListener(listener);
- }
- return LLStringUtil::null;
+
+ LLControlGroup& control_group = LLUI::getControlControlGroup(name);
+ return control_group.getControl(name);
}
-LLSimpleListener* LLView::getListenerByName(const std::string& callback_name)
+const S32 FLOATER_H_MARGIN = 15;
+const S32 MIN_WIDGET_HEIGHT = 10;
+const S32 VPAD = 4;
+
+void LLView::initFromParams(const LLView::Params& params)
{
- LLSimpleListener* callback = NULL;
- dispatch_list_t::iterator itor = mDispatchList.find(callback_name);
- if (itor != mDispatchList.end())
- {
- callback = itor->second;
- }
- else if (mParentView)
+ LLRect required_rect = getRequiredRect();
+
+ S32 width = llmax(getRect().getWidth(), required_rect.getWidth());
+ S32 height = llmax(getRect().getHeight(), required_rect.getHeight());
+
+ reshape(width, height);
+
+ // call virtual methods with most recent data
+ // use getters because these values might not come through parameter block
+ setEnabled(getEnabled());
+ setVisible(getVisible());
+
+ if (!params.name().empty())
{
- callback = mParentView->getListenerByName(callback_name);
+ setName(params.name());
}
- return callback;
+
+ mLayout = params.layout();
}
-LLControlVariable *LLView::findControl(const std::string& name)
+void LLView::parseFollowsFlags(const LLView::Params& params)
{
- control_map_t::iterator itor = mFloaterControls.find(name);
- if (itor != mFloaterControls.end())
+ // preserve follows flags set by code if user did not override
+ if (!params.follows.isProvided())
{
- return itor->second;
+ return;
}
- if (mParentView)
+
+ // interpret either string or bitfield version of follows
+ if (params.follows.string.isChosen())
{
- return mParentView->findControl(name);
- }
- return LLUI::sConfigGroup->getControl(name);
-}
+ setFollows(FOLLOWS_NONE);
-const S32 FLOATER_H_MARGIN = 15;
-const S32 MIN_WIDGET_HEIGHT = 10;
-const S32 VPAD = 4;
+ std::string follows = params.follows.string;
-// static
-U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect)
-{
- U32 follows = 0;
- S32 x = rect.mLeft;
- S32 y = rect.mBottom;
- S32 w = rect.getWidth();
- S32 h = rect.getHeight();
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|");
+ tokenizer tokens(follows, sep);
+ tokenizer::iterator token_iter = tokens.begin();
- U32 last_x = 0;
- U32 last_y = 0;
- if (parent_view)
- {
- last_y = parent_view->getRect().getHeight();
- child_list_t::const_iterator itor = parent_view->getChildList()->begin();
- if (itor != parent_view->getChildList()->end())
+ while(token_iter != tokens.end())
{
- LLView *last_view = (*itor);
- if (last_view->getSaveToXML())
+ const std::string& token_str = *token_iter;
+ if (token_str == "left")
{
- last_x = last_view->getRect().mLeft;
- last_y = last_view->getRect().mBottom;
+ setFollowsLeft();
}
+ else if (token_str == "right")
+ {
+ setFollowsRight();
+ }
+ else if (token_str == "top")
+ {
+ setFollowsTop();
+ }
+ else if (token_str == "bottom")
+ {
+ setFollowsBottom();
+ }
+ else if (token_str == "all")
+ {
+ setFollowsAll();
+ }
+ ++token_iter;
}
}
-
- std::string rect_control;
- node->getAttributeString("rect_control", rect_control);
- if (! rect_control.empty())
+ else if (params.follows.flags.isChosen())
{
- LLRect rect = LLUI::sConfigGroup->getRect(rect_control);
- x = rect.mLeft;
- y = rect.mBottom;
- w = rect.getWidth();
- h = rect.getHeight();
- }
-
- if (node->hasAttribute("left"))
- {
- node->getAttributeS32("left", x);
- }
- if (node->hasAttribute("bottom"))
- {
- node->getAttributeS32("bottom", y);
+ setFollows(params.follows.flags);
}
+}
- // Make your width the width of the containing
- // view if you don't specify a width.
- if (parent_view)
- {
- if(w == 0)
- {
- w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
- }
- if(h == 0)
- {
- h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
+// static
+//LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
+//{
+// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
+//
+// if (node->hasAttribute("halign"))
+// {
+// std::string horizontal_align_name;
+// node->getAttributeString("halign", horizontal_align_name);
+// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
+// }
+// return gl_hfont_align;
+//}
+
+// Return the rectangle of the last-constructed child,
+// if present and a first-class widget (eg, not a close box or drag handle)
+// Returns true if found
+static bool get_last_child_rect(LLView* parent, LLRect *rect)
+{
+ if (!parent) return false;
+
+ LLView::child_list_t::const_iterator itor =
+ parent->getChildList()->begin();
+ for (;itor != parent->getChildList()->end(); ++itor)
+ {
+ LLView *last_view = (*itor);
+ if (last_view->getFromXUI())
+ {
+ *rect = last_view->getRect();
+ return true;
}
}
+ return false;
+}
- if (node->hasAttribute("width"))
- {
- node->getAttributeS32("width", w);
- }
- if (node->hasAttribute("height"))
+//static
+void LLView::applyXUILayout(LLView::Params& p, LLView* parent)
+{
+ const S32 VPAD = 4;
+ const S32 MIN_WIDGET_HEIGHT = 10;
+
+ // *NOTE: This will confuse export of floater/panel coordinates unless
+ // the default is also "topleft". JC
+ if (p.layout().empty() && parent)
{
- node->getAttributeS32("height", h);
+ p.layout = parent->getLayout();
}
- if (parent_view)
+
+ if (parent)
{
- if (node->hasAttribute("left_delta"))
- {
- S32 left_delta = 0;
- node->getAttributeS32("left_delta", left_delta);
- x = last_x + left_delta;
- }
- else if (node->hasAttribute("left") && node->hasAttribute("right"))
+ LLRect parent_rect = parent->getLocalRect();
+ // overwrite uninitialized rect params, using context
+ LLRect last_rect = parent->getLocalRect();
+
+ bool layout_topleft = (p.layout() == "topleft");
+ if (layout_topleft)
{
- // compute width based on left and right
- S32 right = 0;
- node->getAttributeS32("right", right);
- if (right < 0)
- {
- right = parent_view->getRect().getWidth() + right;
- }
- w = right - x;
+ //invert top to bottom
+ if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
+ if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom;
}
- else if (node->hasAttribute("left"))
+
+ // convert negative or centered coordinates to parent relative values
+ // Note: some of this logic matches the logic in TypedParam<LLRect>::setValueFromBlock()
+
+ if (p.center_horiz)
{
- if (x < 0)
+ if (p.rect.left.isProvided() && p.rect.right.isProvided())
{
- x = parent_view->getRect().getWidth() + x;
- follows |= FOLLOWS_RIGHT;
+ S32 width = p.rect.right - p.rect.left;
+ width = llmax(width, 0);
+ S32 offset = parent_rect.getWidth()/2 - width/2;
+ p.rect.left = p.rect.left + offset;
+ p.rect.right = p.rect.right + offset;
}
else
{
- follows |= FOLLOWS_LEFT;
+ p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2;
+ p.rect.right.setProvided(false); // recalculate the right
}
}
- else if (node->hasAttribute("width") && node->hasAttribute("right"))
+ else
+ {
+ if (p.rect.left.isProvided() && p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
+ if (p.rect.right.isProvided() && p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
+ }
+ if (p.center_vert)
{
- S32 right = 0;
- node->getAttributeS32("right", right);
- if (right < 0)
+ if (p.rect.bottom.isProvided() && p.rect.top.isProvided())
{
- right = parent_view->getRect().getWidth() + right;
+ S32 height = p.rect.top - p.rect.bottom;
+ height = llmax(height, 0);
+ S32 offset = parent_rect.getHeight()/2 - height/2;
+ p.rect.bottom = p.rect.bottom + offset;
+ p.rect.top = p.rect.top + offset;
+ }
+ else
+ {
+ p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2;
+ p.rect.top.setProvided(false); // recalculate the top
}
- x = right - w;
}
else
{
- // left not specified, same as last
- x = last_x;
+ if (p.rect.bottom.isProvided() && p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
+ if (p.rect.top.isProvided() && p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
}
- if (node->hasAttribute("bottom_delta"))
+
+ // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels
+ if (!p.rect.height.isProvided() && !p.rect.top.isProvided() && p.rect.height == 0)
{
- S32 bottom_delta = 0;
- node->getAttributeS32("bottom_delta", bottom_delta);
- y = last_y + bottom_delta;
+ p.rect.height = MIN_WIDGET_HEIGHT;
}
- else if (node->hasAttribute("top"))
+
+ last_rect.translate(0, last_rect.getHeight());
+
+ // If there was a recently constructed child, use its rectangle
+ get_last_child_rect(parent, &last_rect);
+
+ if (layout_topleft)
{
- // compute height based on top
- S32 top = 0;
- node->getAttributeS32("top", top);
- if (top < 0)
+ p.bottom_delta.setIfNotProvided(0, false);
+
+ // Invert the sense of bottom_delta for topleft layout
+ if (p.bottom_delta.isProvided())
{
- top = parent_view->getRect().getHeight() + top;
+ p.bottom_delta = -p.bottom_delta;
}
- h = top - y;
- }
- else if (node->hasAttribute("bottom"))
- {
- if (y < 0)
+ else if (p.top_pad.isProvided())
{
- y = parent_view->getRect().getHeight() + y;
- follows |= FOLLOWS_TOP;
+ p.bottom_delta = -(p.rect.height + p.top_pad);
}
- else
+ else if (p.top_delta.isProvided())
{
- follows |= FOLLOWS_BOTTOM;
+ p.bottom_delta =
+ -(p.top_delta + p.rect.height - last_rect.getHeight());
}
- }
- else
- {
- // if bottom not specified, generate automatically
- if (last_y == 0)
+ else if (!p.bottom_delta.isProvided()
+ && !p.left_delta.isProvided()
+ && !p.top_pad.isProvided()
+ && !p.left_pad.isProvided())
{
- // treat first child as "bottom"
- y = parent_view->getRect().getHeight() - (h + VPAD);
- follows |= FOLLOWS_TOP;
+ // set default position is just below last rect
+ p.bottom_delta.set(-(p.rect.height + VPAD), false);
}
- else
+
+ // default to same left edge
+ p.left_delta.setIfNotProvided(0, false);
+ if (p.left_pad.isProvided())
{
- // treat subsequent children as "bottom_delta"
- y = last_y - (h + VPAD);
+ // left_pad is based on prior widget's right edge
+ p.left_delta.set(p.left_pad + last_rect.getWidth(), false);
}
+
+ last_rect.translate(p.left_delta, p.bottom_delta);
+ }
+ else
+ {
+ // set default position is just below last rect
+ p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false);
+ p.left_delta.setIfNotProvided(0, false);
+ last_rect.translate(p.left_delta, p.bottom_delta);
}
- }
- else
- {
- x = llmax(x, 0);
- y = llmax(y, 0);
- follows = FOLLOWS_LEFT | FOLLOWS_TOP;
- }
- rect.setOriginAndSize(x, y, w, h);
-
- return follows;
-}
-
-void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
-{
- // create rect first, as this will supply initial follows flags
- LLRect view_rect;
- U32 follows_flags = createRect(node, view_rect, parent, getRequiredRect());
- // call reshape in case there are any child elements that need to be layed out
- reshape(view_rect.getWidth(), view_rect.getHeight());
- setRect(view_rect);
- setFollows(follows_flags);
-
- parseFollowsFlags(node);
- if (node->hasAttribute("control_name"))
- {
- std::string control_name;
- node->getAttributeString("control_name", control_name);
- setControlName(control_name, NULL);
- }
+ // this handles case where *both* x and x_delta are provided
+ // ignore x in favor of default x + x_delta
+ if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false);
+ if (p.left_delta.isProvided()) p.rect.left.set(0, false);
- if (node->hasAttribute("tool_tip"))
- {
- std::string tool_tip_msg;
- node->getAttributeString("tool_tip", tool_tip_msg);
- setToolTip(tool_tip_msg);
+ // selectively apply rectangle defaults, making sure that
+ // params are not flagged as having been "provided"
+ // as rect params are overconstrained and rely on provided flags
+ p.rect.left.setIfNotProvided(last_rect.mLeft, false);
+ p.rect.bottom.setIfNotProvided(last_rect.mBottom, false);
+ p.rect.top.setIfNotProvided(last_rect.mTop, false);
+ p.rect.right.setIfNotProvided(last_rect.mRight, false);
+ p.rect.width.setIfNotProvided(last_rect.getWidth(), false);
+ p.rect.height.setIfNotProvided(last_rect.getHeight(), false);
}
+}
- if (node->hasAttribute("enabled"))
- {
- BOOL enabled;
- node->getAttributeBOOL("enabled", enabled);
- setEnabled(enabled);
- }
-
- if (node->hasAttribute("visible"))
+static S32 invert_vertical(S32 y, LLView* parent)
+{
+ if (y < 0)
{
- BOOL visible;
- node->getAttributeBOOL("visible", visible);
- setVisible(visible);
+ // already based on top-left, just invert
+ return -y;
}
-
- if (node->hasAttribute("hover_cursor"))
+ else if (parent)
{
- std::string cursor_string;
- node->getAttributeString("hover_cursor", cursor_string);
- mHoverCursor = getCursorFromString(cursor_string);
+ // use parent to flip coordinate
+ S32 parent_height = parent->getRect().getHeight();
+ return parent_height - y;
}
-
- node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect);
- node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
-
- node->getAttributeS32("default_tab_group", mDefaultTabGroup);
-
- reshape(view_rect.getWidth(), view_rect.getHeight());
-}
-
-void LLView::parseFollowsFlags(LLXMLNodePtr node)
-{
- if (node->hasAttribute("follows"))
+ else
{
- setFollowsNone();
-
- std::string follows;
- node->getAttributeString("follows", follows);
-
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("|");
- tokenizer tokens(follows, sep);
- tokenizer::iterator token_iter = tokens.begin();
-
- while(token_iter != tokens.end())
- {
- const std::string& token_str = *token_iter;
- if (token_str == "left")
- {
- setFollowsLeft();
- }
- else if (token_str == "right")
+ llwarns << "Attempting to convert layout to top-left with no parent" << llendl;
+ return y;
+ }
+}
+
+// Assumes that input is in bottom-left coordinates, hence must call
+// _before_ convert_coords_to_top_left().
+static void convert_to_relative_layout(LLView::Params& p, LLView* parent)
+{
+ // Use setupParams to get the final widget rectangle
+ // according to our wacky layout rules.
+ LLView::Params final = p;
+ LLView::applyXUILayout(final, parent);
+ // Must actually extract the rectangle to get consistent
+ // right = left+width, top = bottom+height
+ LLRect final_rect = final.rect;
+
+ // We prefer to write out top edge instead of bottom, regardless
+ // of whether we use relative positioning
+ bool converted_top = false;
+
+ // Look for a last rectangle
+ LLRect last_rect;
+ if (get_last_child_rect(parent, &last_rect))
+ {
+ // ...we have a previous widget to compare to
+ const S32 EDGE_THRESHOLD_PIXELS = 4;
+ S32 left_pad = final_rect.mLeft - last_rect.mRight;
+ S32 left_delta = final_rect.mLeft - last_rect.mLeft;
+ S32 top_pad = final_rect.mTop - last_rect.mBottom;
+ S32 top_delta = final_rect.mTop - last_rect.mTop;
+ // If my left edge is almost the same, or my top edge is
+ // almost the same...
+ if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS
+ || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS)
+ {
+ // ...use relative positioning
+ // prefer top_pad if widgets are stacking vertically
+ // (coordinate system is still bottom-left here)
+ if (top_pad < 0)
{
- setFollowsRight();
+ p.top_pad = top_pad;
+ p.top_delta.setProvided(false);
}
- else if (token_str == "top")
+ else
{
- setFollowsTop();
+ p.top_pad.setProvided(false);
+ p.top_delta = top_delta;
}
- else if (token_str == "bottom")
+ // null out other vertical specifiers
+ p.rect.top.setProvided(false);
+ p.rect.bottom.setProvided(false);
+ p.bottom_delta.setProvided(false);
+ converted_top = true;
+
+ // prefer left_pad if widgets are stacking horizontally
+ if (left_pad > 0)
{
- setFollowsBottom();
+ p.left_pad = left_pad;
+ p.left_delta.setProvided(false);
}
- else if (token_str == "all")
+ else
{
- setFollowsAll();
+ p.left_pad.setProvided(false);
+ p.left_delta = left_delta;
}
- ++token_iter;
+ p.rect.left.setProvided(false);
+ p.rect.right.setProvided(false);
}
}
+
+ if (!converted_top)
+ {
+ // ...this is the first widget, or one that wasn't aligned
+ // prefer top/left specification
+ p.rect.top = final_rect.mTop;
+ p.rect.bottom.setProvided(false);
+ p.bottom_delta.setProvided(false);
+ p.top_pad.setProvided(false);
+ p.top_delta.setProvided(false);
+ }
}
-// static
-LLFontGL* LLView::selectFont(LLXMLNodePtr node)
+static void convert_coords_to_top_left(LLView::Params& p, LLView* parent)
{
- std::string font_name, font_size, font_style;
- U8 style = 0;
-
- if (node->hasAttribute("font"))
+ // Convert the coordinate system to be top-left based.
+ if (p.rect.top.isProvided())
{
- node->getAttributeString("font", font_name);
+ p.rect.top = invert_vertical(p.rect.top, parent);
}
-
- if (node->hasAttribute("font_size"))
+ if (p.rect.bottom.isProvided())
{
- node->getAttributeString("font_size", font_size);
+ p.rect.bottom = invert_vertical(p.rect.bottom, parent);
}
-
- if (node->hasAttribute("font_style"))
+ if (p.top_pad.isProvided())
{
- node->getAttributeString("font_style", font_style);
- style = LLFontGL::getStyleFromString(font_style);
+ p.top_pad = -p.top_pad;
}
-
- if (node->hasAttribute("font-style"))
+ if (p.top_delta.isProvided())
{
- node->getAttributeString("font-style", font_style);
- style = LLFontGL::getStyleFromString(font_style);
+ p.top_delta = -p.top_delta;
}
-
- if (font_name.empty())
- return NULL;
-
- LLFontDescriptor desc(font_name, font_size, style);
- LLFontGL* gl_font = LLFontGL::getFont(desc);
-
- return gl_font;
-}
-
-// static
-LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
-{
- LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
-
- if (node->hasAttribute("halign"))
+ if (p.bottom_delta.isProvided())
{
- std::string horizontal_align_name;
- node->getAttributeString("halign", horizontal_align_name);
- gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
+ p.bottom_delta = -p.bottom_delta;
}
- return gl_hfont_align;
+ p.layout = "topleft";
}
-// static
-LLFontGL::VAlign LLView::selectFontVAlign(LLXMLNodePtr node)
+//static
+void LLView::setupParamsForExport(Params& p, LLView* parent)
{
- LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
-
- if (node->hasAttribute("valign"))
+ // Don't convert if already top-left based
+ if (p.layout() == "topleft")
{
- std::string vert_align_name;
- node->getAttributeString("valign", vert_align_name);
- gl_vfont_align = LLFontGL::vAlignFromName(vert_align_name);
+ return;
}
- return gl_vfont_align;
-}
-
-// static
-LLFontGL::StyleFlags LLView::selectFontStyle(LLXMLNodePtr node)
-{
- LLFontGL::StyleFlags gl_font_style = LLFontGL::NORMAL;
- if (node->hasAttribute("style"))
+ // heuristic: Many of our floaters and panels were bulk-exported.
+ // These specify exactly bottom/left and height/width.
+ // Others were done by hand using bottom_delta and/or left_delta.
+ // Some rely on not specifying left to mean align with left edge.
+ // Try to convert both to use relative layout, but using top-left
+ // coordinates.
+ // Avoid rectangles where top/bottom/left/right was specified.
+ if (p.rect.height.isProvided() && p.rect.width.isProvided())
{
- std::string style_flags_name;
- node->getAttributeString("style", style_flags_name);
-
- if (style_flags_name == "normal")
- {
- gl_font_style = LLFontGL::NORMAL;
- }
- else if (style_flags_name == "bold")
+ if (p.rect.bottom.isProvided() && p.rect.left.isProvided())
{
- gl_font_style = LLFontGL::BOLD;
+ // standard bulk export, convert it
+ convert_to_relative_layout(p, parent);
}
- else if (style_flags_name == "italic")
+ else if (p.rect.bottom.isProvided() && p.left_delta.isProvided())
{
- gl_font_style = LLFontGL::ITALIC;
+ // hand layout with left_delta
+ convert_to_relative_layout(p, parent);
}
- else if (style_flags_name == "underline")
+ else if (p.bottom_delta.isProvided())
{
- gl_font_style = LLFontGL::UNDERLINE;
+ // hand layout with bottom_delta
+ // don't check for p.rect.left or p.left_delta because sometimes
+ // this layout doesn't set it for widgets that are left-aligned
+ convert_to_relative_layout(p, parent);
}
- //else leave left
}
- return gl_font_style;
+
+ convert_coords_to_top_left(p, parent);
}
-bool LLView::setControlValue(const LLSD& value)
-{
- std::string ctrlname = getControlName();
- if (!ctrlname.empty())
- {
- LLUI::sConfigGroup->setValue(ctrlname, value);
- return true;
- }
- return false;
+LLView::tree_iterator_t LLView::beginTreeDFS()
+{
+ return tree_iterator_t(this,
+ boost::bind(boost::mem_fn(&LLView::beginChild), _1),
+ boost::bind(boost::mem_fn(&LLView::endChild), _1));
}
-//virtual
-void LLView::setControlName(const std::string& control_name, LLView *context)
-{
- if (context == NULL)
- {
- context = this;
- }
+LLView::tree_iterator_t LLView::endTreeDFS()
+{
+ // an empty iterator is an "end" iterator
+ return tree_iterator_t();
+}
- if (!mControlName.empty())
- {
- llwarns << "setControlName called twice on same control!" << llendl;
- mControlConnection.disconnect(); // disconnect current signal
- mControlName.clear();
- }
-
- // Register new listener
- if (!control_name.empty())
- {
- LLControlVariable *control = context->findControl(control_name);
- if (control)
- {
- mControlName = control_name;
- mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _1, getHandle(), std::string("value")));
- setValue(control->getValue());
- }
- }
+LLView::tree_post_iterator_t LLView::beginTreeDFSPost()
+{
+ return tree_post_iterator_t(this,
+ boost::bind(boost::mem_fn(&LLView::beginChild), _1),
+ boost::bind(boost::mem_fn(&LLView::endChild), _1));
}
-// static
-bool LLView::controlListener(const LLSD& newvalue, LLHandle<LLView> handle, std::string type)
+LLView::tree_post_iterator_t LLView::endTreeDFSPost()
+{
+ // an empty iterator is an "end" iterator
+ return tree_post_iterator_t();
+}
+
+
+LLView::root_to_view_iterator_t LLView::beginRootToView()
{
- LLView* view = handle.get();
- if (view)
- {
- if (type == "value")
- {
- view->setValue(newvalue);
- return true;
- }
- else if (type == "enabled")
- {
- view->setEnabled(newvalue.asBoolean());
- return true;
- }
- else if (type == "visible")
- {
- view->setVisible(newvalue.asBoolean());
- return true;
- }
- }
- return false;
+ return root_to_view_iterator_t(this, boost::bind(&LLView::getParent, _1));
}
-void LLView::addBoolControl(const std::string& name, bool initial_value)
+LLView::root_to_view_iterator_t LLView::endRootToView()
{
- mFloaterControls[name] = new LLControlVariable(name, TYPE_BOOLEAN, initial_value, std::string("Internal floater control"));
+ return root_to_view_iterator_t();
}
-LLControlVariable *LLView::getControl(const std::string& name)
+
+// only create maps on demand, as they incur heap allocation/deallocation cost
+// when a view is constructed/deconstructed
+LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const
{
- control_map_t::iterator itor = mFloaterControls.find(name);
- if (itor != mFloaterControls.end())
+ if (!mDefaultWidgets)
{
- return itor->second;
+ mDefaultWidgets = new default_widget_map_t();
}
- return NULL;
+ return *mDefaultWidgets;
}
-//virtual
-void LLView::setValue(const LLSD& value)
+S32 LLView::notifyParent(const LLSD& info)
{
+ LLView* parent = getParent();
+ if(parent)
+ return parent->notifyParent(info);
+ return 0;
}
-
-//virtual
-LLSD LLView::getValue() const
+bool LLView::notifyChildren(const LLSD& info)
{
- return LLSD();
+ bool ret = false;
+ for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ {
+ ret |= (*child_it)->notifyChildren(info);
+ }
+ return ret;
}
-LLView* LLView::createWidget(LLXMLNodePtr xml_node) const
+// convenient accessor for draw context
+const LLViewDrawContext& LLView::getDrawContext()
{
- // forward requests to ui ctrl factory
- return LLUICtrlFactory::getInstance()->createCtrlWidget(NULL, xml_node);
-}
-
-//
-// LLWidgetClassRegistry
-//
-
-LLWidgetClassRegistry::LLWidgetClassRegistry()
-{
-}
-
-void LLWidgetClassRegistry::registerCtrl(const std::string& tag, LLWidgetClassRegistry::factory_func_t function)
-{
- std::string lower_case_tag = tag;
- LLStringUtil::toLower(lower_case_tag);
-
- mCreatorFunctions[lower_case_tag] = function;
+ return LLViewDrawContext::getCurrentContext();
}
-BOOL LLWidgetClassRegistry::isTagRegistered(const std::string &tag)
-{
- return mCreatorFunctions.find(tag) != mCreatorFunctions.end();
-}
+const LLViewDrawContext& LLViewDrawContext::getCurrentContext()
+{
+ static LLViewDrawContext default_context;
-LLWidgetClassRegistry::factory_func_t LLWidgetClassRegistry::getCreatorFunc(const std::string& ctrl_type)
-{
- factory_map_t::const_iterator found_it = mCreatorFunctions.find(ctrl_type);
- if (found_it == mCreatorFunctions.end())
- {
- return NULL;
- }
- return found_it->second;
+ if (sDrawContextStack.empty())
+ return default_context;
+
+ return *sDrawContextStack.back();
}
-