summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llbutton.cpp37
-rw-r--r--indra/llui/llbutton.h7
-rw-r--r--indra/llui/llcombobox.cpp280
-rw-r--r--indra/llui/llcombobox.h29
-rw-r--r--indra/llui/lldraghandle.cpp8
-rw-r--r--indra/llui/llfloater.cpp35
-rw-r--r--indra/llui/llfocusmgr.cpp69
-rw-r--r--indra/llui/llfocusmgr.h16
-rw-r--r--indra/llui/lllineeditor.cpp34
-rw-r--r--indra/llui/lllineeditor.h7
-rw-r--r--indra/llui/llmenugl.cpp30
-rw-r--r--indra/llui/llmenugl.h1
-rw-r--r--indra/llui/llmodaldialog.cpp20
-rw-r--r--indra/llui/llresizebar.cpp129
-rw-r--r--indra/llui/llresizebar.h4
-rw-r--r--indra/llui/llresizehandle.cpp117
-rw-r--r--indra/llui/llresizehandle.h4
-rw-r--r--indra/llui/llscrollbar.cpp10
-rw-r--r--indra/llui/llscrollcontainer.cpp2
-rw-r--r--indra/llui/llscrolllistctrl.cpp908
-rw-r--r--indra/llui/llscrolllistctrl.h133
-rw-r--r--indra/llui/llslider.cpp12
-rw-r--r--indra/llui/llsliderctrl.cpp2
-rw-r--r--indra/llui/llspinctrl.cpp4
-rw-r--r--indra/llui/lltabcontainer.cpp8
-rw-r--r--indra/llui/lltextbox.cpp6
-rw-r--r--indra/llui/lltexteditor.cpp16
-rw-r--r--indra/llui/lltexteditor.h3
-rw-r--r--indra/llui/llui.cpp4
-rw-r--r--indra/llui/lluictrl.cpp13
-rw-r--r--indra/llui/lluictrl.h2
-rw-r--r--indra/llui/lluictrlfactory.cpp4
-rw-r--r--indra/llui/llview.cpp38
-rw-r--r--indra/llui/llview.h10
34 files changed, 1288 insertions, 714 deletions
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index ffa9262e21..8e81fec33b 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -46,7 +46,9 @@ LLButton::LLButton( const LLString& name, const LLRect& rect, const LLString& co
mMouseUpCallback( NULL ),
mHeldDownCallback( NULL ),
mGLFont( NULL ),
+ mMouseDownFrame( 0 ),
mHeldDownDelay( 0.5f ), // seconds until held-down callback is called
+ mHeldDownFrameDelay( 0 ),
mImageUnselected( NULL ),
mImageSelected( NULL ),
mImageHoverSelected( NULL ),
@@ -99,7 +101,9 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
mMouseUpCallback( NULL ),
mHeldDownCallback( NULL ),
mGLFont( NULL ),
+ mMouseDownFrame( 0 ),
mHeldDownDelay( 0.5f ), // seconds until held-down callback is called
+ mHeldDownFrameDelay( 0 ),
mImageUnselected( NULL ),
mImageSelected( NULL ),
mImageHoverSelected( NULL ),
@@ -196,9 +200,9 @@ void LLButton::init(void (*click_callback)(void*), void *callback_data, const LL
LLButton::~LLButton()
{
- if( this == gFocusMgr.getMouseCapture() )
+ if( hasMouseCapture() )
{
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
}
}
@@ -284,7 +288,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent )
BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
// Route future Mouse messages here preemptively. (Release on mouse up.)
- gFocusMgr.setMouseCapture( this, &LLButton::onMouseCaptureLost );
+ gFocusMgr.setMouseCapture( this );
if (hasTabStop() && !getIsChrome())
{
@@ -297,6 +301,7 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
}
mMouseDownTimer.start();
+ mMouseDownFrame = LLFrameTimer::getFrameCount();
if (mSoundFlags & MOUSE_DOWN)
{
@@ -310,19 +315,17 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
{
// We only handle the click if the click both started and ended within us
- if( this == gFocusMgr.getMouseCapture() )
+ if( hasMouseCapture() )
{
+ // Always release the mouse
+ gFocusMgr.setMouseCapture( NULL );
+
// Regardless of where mouseup occurs, handle callback
if (mMouseUpCallback)
{
(*mMouseUpCallback)(mCallbackUserData);
}
- mMouseDownTimer.stop();
-
- // Always release the mouse
- gFocusMgr.setMouseCapture( NULL, NULL );
-
// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
// If mouseup in the widget, it's been clicked
if (pointInView(x, y))
@@ -337,6 +340,9 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
(*mClickedCallback)( mCallbackUserData );
}
}
+
+ mMouseDownTimer.stop();
+ mMouseDownTimer.reset();
}
return TRUE;
@@ -356,14 +362,14 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback)
{
F32 elapsed = mMouseDownTimer.getElapsedTimeF32();
- if( mHeldDownDelay < elapsed )
+ if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= LLFrameTimer::getFrameCount() - mMouseDownFrame)
{
mHeldDownCallback( mCallbackUserData );
}
}
// We only handle the click if the click both started and ended within us
- if( this == gFocusMgr.getMouseCapture() )
+ if( hasMouseCapture() )
{
handled = TRUE;
}
@@ -412,7 +418,7 @@ void LLButton::draw()
cursor_pos_gl.mY = llround((F32)cursor_pos_gl.mY / LLUI::sGLScaleFactor.mV[VY]);
screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y);
- BOOL pressed = pressed_by_keyboard || (this == gFocusMgr.getMouseCapture() && pointInView(local_mouse_x, local_mouse_y));
+ BOOL pressed = pressed_by_keyboard || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y));
BOOL display_state = FALSE;
if( pressed )
@@ -800,11 +806,10 @@ void LLButton::setHoverImages( const LLString& image_name, const LLString& selec
setImageHoverSelected(selected_name);
}
-// static
-void LLButton::onMouseCaptureLost( LLMouseHandler* old_captor )
+void LLButton::onMouseCaptureLost()
{
- LLButton* self = (LLButton*) old_captor;
- self->mMouseDownTimer.stop();
+ mMouseDownTimer.stop();
+ mMouseDownTimer.reset();
}
//-------------------------------------------------------------------------
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 1982c2e36f..3dea4434a9 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -75,6 +75,8 @@ public:
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual void draw();
+ virtual void onMouseCaptureLost();
+
// HACK: "committing" a button is the same as clicking on it.
virtual void onCommit();
@@ -85,7 +87,7 @@ public:
void setMouseDownCallback( void (*cb)(void *data) ) { mMouseDownCallback = cb; } // mouse down within button
void setMouseUpCallback( void (*cb)(void *data) ) { mMouseUpCallback = cb; } // mouse up, EVEN IF NOT IN BUTTON
void setHeldDownCallback( void (*cb)(void *data) ) { mHeldDownCallback = cb; } // Mouse button held down and in button
- void setHeldDownDelay( F32 seconds) { mHeldDownDelay = seconds; }
+ void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; }
F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); }
@@ -140,7 +142,6 @@ public:
void setBorderEnabled(BOOL b) { mBorderEnabled = b; }
static void onHeldDown(void *userdata); // to be called by gIdleCallbacks
- static void onMouseCaptureLost(LLMouseHandler* old_captor);
void setFixedBorder(S32 width, S32 height) { mFixedWidth = width; mFixedHeight = height; }
void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
@@ -175,7 +176,9 @@ protected:
const LLFontGL *mGLFont;
LLFrameTimer mMouseDownTimer;
+ S32 mMouseDownFrame;
F32 mHeldDownDelay; // seconds, after which held-down callbacks get called
+ S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called
LLPointer<LLImageGL> mImageUnselected;
LLUIString mUnselectedLabel;
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 667985c699..e439cd0acc 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -40,7 +40,7 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
)
: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata,
FOLLOWS_LEFT | FOLLOWS_TOP),
- mDrawButton(TRUE),
+ mDrawArrow(TRUE),
mTextEntry(NULL),
mArrowImage(NULL),
mArrowImageWidth(8),
@@ -48,8 +48,8 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
mMaxChars(20),
mTextEntryTentative(TRUE),
mPrearrangeCallback( NULL ),
- mTextEntryCallback( NULL ),
- mListWidth(list_width)
+ mListPosition(BELOW),
+ mTextEntryCallback( NULL )
{
// For now, all comboboxes don't take keyboard focus when clicked.
// This might change if it is part of a modal dialog.
@@ -57,7 +57,7 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
// Revert to standard behavior. When this control's parent is hidden, it needs to
// hide this ctrl--which won't just happen automatically since when LLComboBox is
- // showing its list, it's also set to TopView. When keyboard focus is cleared all
+ // showing its list, it's also set to TopCtrl. When keyboard focus is cleared all
// controls (including this one) know that they are no longer editing.
mKeyboardFocusOnClick = TRUE;
@@ -68,7 +68,8 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
// Text label button
mButton = new LLSquareButton("comboxbox button",
r, label, NULL, LLString::null,
- &LLComboBox::onButtonClick, this);
+ NULL, this);
+ mButton->setMouseDownCallback(onButtonDown);
mButton->setFont(LLFontGL::sSansSerifSmall);
mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
mButton->setHAlign( LLFontGL::LEFT );
@@ -91,6 +92,7 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
mList->setVisible(FALSE);
mList->setBgWriteableColor( LLColor4(1,1,1,1) );
mList->setCommitOnKeyboardMovement(FALSE);
+ mList->setFocusChangedCallback(onListFocusChanged);
addChild(mList);
LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
@@ -204,111 +206,6 @@ void LLComboBox::setEnabled(BOOL enabled)
mButton->setEnabled(enabled);
}
-// *HACK: these are all hacks to support the fact that the combobox
-// has mouse capture so we can hide the list when we don't handle the
-// mouse up event
-BOOL LLComboBox::handleHover(S32 x, S32 y, MASK mask)
-{
- if (mList->getVisible())
- {
- S32 local_x, local_y;
- LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
- if (mList->pointInView(local_x, local_y))
- {
- return mList->handleHover(local_x, local_y, mask);
- }
- }
- return LLUICtrl::handleHover(x, y, mask);
-}
-
-BOOL LLComboBox::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- if (mList->getVisible())
- {
- S32 local_x, local_y;
- LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
- if (mList->pointInView(local_x, local_y))
- {
- return mList->handleMouseDown(local_x, local_y, mask);
- }
- }
- BOOL has_focus_now = hasFocus();
- BOOL handled = LLUICtrl::handleMouseDown(x, y, mask);
- if (handled && !has_focus_now)
- {
- onFocusReceived();
- }
-
- return handled;
-}
-
-BOOL LLComboBox::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- if (mList->getVisible())
- {
- S32 local_x, local_y;
- LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
- if (mList->pointInView(local_x, local_y))
- {
- return mList->handleRightMouseDown(local_x, local_y, mask);
- }
- }
- return LLUICtrl::handleRightMouseDown(x, y, mask);
-}
-
-BOOL LLComboBox::handleRightMouseUp(S32 x, S32 y, MASK mask)
-{
- if (mList->getVisible())
- {
- S32 local_x, local_y;
- LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
- if (mList->pointInView(local_x, local_y))
- {
- return mList->handleRightMouseUp(local_x, local_y, mask);
- }
- }
- return LLUICtrl::handleRightMouseUp(x, y, mask);
-}
-
-BOOL LLComboBox::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
- if (mList->getVisible())
- {
- S32 local_x, local_y;
- LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
- if (mList->pointInView(local_x, local_y))
- {
- return mList->handleDoubleClick(local_x, local_y, mask);
- }
- }
- return LLUICtrl::handleDoubleClick(x, y, mask);
-}
-
-BOOL LLComboBox::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- BOOL handled = childrenHandleMouseUp(x, y, mask) != NULL;
-
- if (!handled && mList->getVisible())
- {
- S32 local_x, local_y;
- LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
- if (mList->pointInView(local_x, local_y))
- {
- handled = mList->handleMouseUp(local_x, local_y, mask);
- }
- }
-
- if( !handled && gFocusMgr.getMouseCapture() == this )
- {
- // Mouse events that we didn't handle cause the list to be hidden.
- // Eat mouse event, regardless of where on the screen it happens.
- hideList();
- handled = TRUE;
- }
-
- return handled;
-}
-
void LLComboBox::clear()
{
if (mTextEntry)
@@ -493,12 +390,13 @@ void LLComboBox::onFocusLost()
{
mTextEntry->selectAll();
}
+ LLUICtrl::onFocusLost();
}
void LLComboBox::setButtonVisible(BOOL visible)
{
mButton->setVisible(visible);
- mDrawButton = visible;
+ mDrawArrow = visible;
if (mTextEntry)
{
LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
@@ -522,15 +420,17 @@ void LLComboBox::draw()
// Draw children
LLUICtrl::draw();
- if (mDrawButton)
+ if (mDrawArrow)
{
// Paste the graphic on the right edge
if (!mArrowImage.isNull())
{
- S32 left = mRect.getWidth() - mArrowImageWidth - LLUI::sConfigGroup->getS32("DropShadowButton");
+ S32 arrow_height = llmin(mRect.getHeight(), mArrowImage->getHeight());
+ S32 arrow_width = llround((F32)mArrowImage->getWidth() * ((F32)arrow_height / (F32)mArrowImage->getHeight()));
+
+ S32 left = mRect.getWidth() - mArrowImage->getWidth() - LLUI::sConfigGroup->getS32("DropShadowButton");
- gl_draw_image( left, 0, mArrowImage,
- LLColor4::white);
+ gl_draw_scaled_image( left, 0, arrow_width, arrow_height, mArrowImage, LLColor4::white);
}
}
}
@@ -576,18 +476,60 @@ void LLComboBox::showList()
//HACK: shouldn't have to know about scale here
mList->arrange( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
- // Move rect so it hangs off the bottom of this view
+ // Make sure that we can see the whole list
+ LLRect floater_area_local;
+ gFloaterView->localRectToOtherView(gFloaterView->getLocalSnapRect(), &floater_area_local, this);
+
LLRect rect = mList->getRect();
- rect.setLeftTopAndSize(0, 0, rect.getWidth(), rect.getHeight() );
- mList->setRect(rect);
+ if (mListPosition == BELOW)
+ {
+ if (rect.getHeight() <= -floater_area_local.mBottom)
+ {
+ // Move rect so it hangs off the bottom of this view
+ rect.setLeftTopAndSize(0, 0, rect.getWidth(), rect.getHeight() );
+ }
+ else
+ {
+ // stack on top or bottom, depending on which has more room
+ if (-floater_area_local.mBottom > floater_area_local.mTop - mRect.getHeight())
+ {
+ // Move rect so it hangs off the bottom of this view
+ rect.setLeftTopAndSize(0, 0, rect.getWidth(), llmin(-floater_area_local.mBottom, rect.getHeight()));
+ }
+ else
+ {
+ // move rect so it stacks on top of this view (clipped to size of screen)
+ rect.setOriginAndSize(0, mRect.getHeight(), rect.getWidth(), llmin(floater_area_local.mTop - mRect.getHeight(), rect.getHeight()));
+ }
+ }
+ }
+ else // ABOVE
+ {
+ if (rect.getHeight() <= floater_area_local.mTop - mRect.getHeight())
+ {
+ // move rect so it stacks on top of this view (clipped to size of screen)
+ rect.setOriginAndSize(0, mRect.getHeight(), rect.getWidth(), llmin(floater_area_local.mTop - mRect.getHeight(), rect.getHeight()));
+ }
+ else
+ {
+ // stack on top or bottom, depending on which has more room
+ if (-floater_area_local.mBottom > floater_area_local.mTop - mRect.getHeight())
+ {
+ // Move rect so it hangs off the bottom of this view
+ rect.setLeftTopAndSize(0, 0, rect.getWidth(), llmin(-floater_area_local.mBottom, rect.getHeight()));
+ }
+ else
+ {
+ // move rect so it stacks on top of this view (clipped to size of screen)
+ rect.setOriginAndSize(0, mRect.getHeight(), rect.getWidth(), llmin(floater_area_local.mTop - mRect.getHeight(), rect.getHeight()));
+ }
+ }
- // Make sure that we can see the whole list
- LLRect floater_area_screen;
- LLRect floater_area_local;
- gFloaterView->getParent()->localRectToScreen( gFloaterView->getRect(), &floater_area_screen );
- screenRectToLocal( floater_area_screen, &floater_area_local );
- mList->translateIntoRect( floater_area_local, FALSE );
+ }
+ mList->setOrigin(rect.mLeft, rect.mBottom);
+ mList->reshape(rect.getWidth(), rect.getHeight());
+ mList->translateIntoRect(floater_area_local, FALSE);
// Make sure we didn't go off bottom of screen
S32 x, y;
@@ -598,7 +540,12 @@ void LLComboBox::showList()
mList->translate(0, -y);
}
- gFocusMgr.setMouseCapture( this, LLComboBox::onMouseCaptureLost );
+ // pass mouse capture on to list if button is depressed
+ if (mButton->hasMouseCapture())
+ {
+ gFocusMgr.setMouseCapture(mList);
+ }
+
// NB: this call will trigger the focuslost callback which will hide the list, so do it first
// before finally showing the list
@@ -608,14 +555,13 @@ void LLComboBox::showList()
// so that the callback is not immediately triggered on setFocus()
mList->selectFirstItem();
}
- gFocusMgr.setKeyboardFocus(mList, onListFocusLost);
+ mList->setFocus(TRUE);
// Show the list and push the button down
mButton->setToggleState(TRUE);
mList->setVisible(TRUE);
- gFocusMgr.setTopView(mList, LLComboBox::onTopViewLost );
-
+ gFocusMgr.setTopCtrl(mList);
}
void LLComboBox::hideList()
@@ -624,37 +570,21 @@ void LLComboBox::hideList()
mList->setVisible(FALSE);
mList->highlightNthItem(-1);
- if( gFocusMgr.getTopView() == mList )
+ if( gFocusMgr.getTopCtrl() == mList )
{
- gFocusMgr.setTopView(NULL, NULL);
+ gFocusMgr.setTopCtrl(NULL);
}
- if( gFocusMgr.getMouseCapture() == this )
- {
- gFocusMgr.setMouseCapture( NULL, NULL );
- }
-
- if( gFocusMgr.getKeyboardFocus() == mList )
- {
- if (mAllowTextEntry)
- {
- mTextEntry->setFocus(TRUE);
- }
- else
- {
- setFocus(TRUE);
- }
- }
+ //mList->setFocus(FALSE);
}
-
//------------------------------------------------------------------
// static functions
//------------------------------------------------------------------
// static
-void LLComboBox::onButtonClick(void *userdata)
+void LLComboBox::onButtonDown(void *userdata)
{
LLComboBox *self = (LLComboBox *)userdata;
@@ -701,50 +631,46 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
const LLString& name = self->mList->getSimpleSelectedItem();
- self->hideList();
-
S32 cur_id = self->getCurrentIndex();
if (cur_id != -1)
{
- self->setLabel(self->mList->getSimpleSelectedItem());
+ self->setLabel(name);
if (self->mAllowTextEntry)
{
- self->mTextEntry->setText(name);
- self->mTextEntry->setTentative(FALSE);
gFocusMgr.setKeyboardFocus(self->mTextEntry, NULL);
self->mTextEntry->selectAll();
}
- else
- {
- self->mButton->setLabelUnselected( name );
- self->mButton->setLabelSelected( name );
- self->mButton->setDisabledLabel( name );
- self->mButton->setDisabledSelectedLabel( name );
- }
+ }
+ else
+ {
+ // invalid selection, just restore existing value
+ self->mList->selectSimpleItem(self->mButton->getLabelSelected());
}
self->onCommit();
-}
-// static
-void LLComboBox::onTopViewLost(LLView* old_focus)
-{
- LLComboBox *self = (LLComboBox *) old_focus->getParent();
self->hideList();
}
-
// static
-void LLComboBox::onMouseCaptureLost(LLMouseHandler*)
+void LLComboBox::onListFocusChanged(LLUICtrl* list, void* user_data)
{
- // Can't hide the list here. If the list scrolls off the screen,
- // and you click in the arrow buttons of the scroll bar, they must capture
- // the mouse to handle scrolling-while-mouse-down.
+ LLComboBox *self = (LLComboBox *) list->getParent();
+ if (!list->hasFocus())
+ {
+ //*HACK: store the original value explicitly somewhere, not just in label
+ LLString orig_selection = self->mAllowTextEntry ? self->mTextEntry->getText() : self->mButton->getLabelSelected();
+
+ self->hideList();
+
+ // reassert original selection
+ self->mList->selectSimpleItem(orig_selection, FALSE);
+ }
}
BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
{
-
+
LLString tool_tip;
if (LLUI::sShowXUINames)
@@ -1122,15 +1048,3 @@ BOOL LLComboBox::operateOnAll(EOperation op)
}
return FALSE;
}
-
-//static
-void LLComboBox::onListFocusLost(LLUICtrl* old_focus)
-{
- // if focus is going to nothing (user hit ESC), take it back
- LLComboBox* combo = (LLComboBox*)old_focus->getParent();
- combo->hideList();
- if (gFocusMgr.getKeyboardFocus() == NULL)
- {
- combo->focusFirstItem();
- }
-}
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index faf99937c9..2b19c3c2e5 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -34,6 +34,12 @@ class LLComboBox
: public LLUICtrl, public LLCtrlListInterface
{
public:
+ typedef enum e_preferred_position
+ {
+ ABOVE,
+ BELOW
+ } EPreferredPosition;
+
LLComboBox(
const LLString& name,
const LLRect &rect,
@@ -58,12 +64,6 @@ public:
virtual BOOL handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect);
virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
virtual BOOL handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
- virtual BOOL handleHover(S32 x, S32 y, MASK mask);
- virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
- virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
- virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
// LLUICtrl interface
virtual void clear(); // select nothing
@@ -146,34 +146,31 @@ public:
void setButtonVisible(BOOL visible);
- static void onButtonClick(void *userdata);
+ static void onButtonDown(void *userdata);
static void onItemSelected(LLUICtrl* item, void *userdata);
- static void onTopViewLost(LLView* old_focus);
- static void onMouseCaptureLost(LLMouseHandler* old_captor);
+ static void onListFocusChanged(LLUICtrl* item, void *userdata);
static void onTextEntry(LLLineEditor* line_editor, void* user_data);
static void onTextCommit(LLUICtrl* caller, void* user_data);
void updateSelection();
- void showList();
- void hideList();
-
- static void onListFocusLost(LLUICtrl* old_focus);
-
+ virtual void showList();
+ virtual void hideList();
+
protected:
LLButton* mButton;
LLScrollListCtrl* mList;
LLViewBorder* mBorder;
BOOL mKeyboardFocusOnClick;
- BOOL mDrawButton;
+ BOOL mDrawArrow;
LLLineEditor* mTextEntry;
LLPointer<LLImageGL> mArrowImage;
S32 mArrowImageWidth;
BOOL mAllowTextEntry;
S32 mMaxChars;
BOOL mTextEntryTentative;
+ EPreferredPosition mListPosition;
void (*mPrearrangeCallback)(LLUICtrl*,void*);
void (*mTextEntryCallback)(LLLineEditor*, void*);
- S32 mListWidth; // width of pop-up list, 0 = use combobox width
};
#endif
diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp
index a88fbb7744..599a85021b 100644
--- a/indra/llui/lldraghandle.cpp
+++ b/indra/llui/lldraghandle.cpp
@@ -269,7 +269,7 @@ BOOL LLDragHandle::handleMouseDown(S32 x, S32 y, MASK mask)
{
// Route future Mouse messages here preemptively. (Release on mouse up.)
// No handler needed for focus lost since this clas has no state that depends on it.
- gFocusMgr.setMouseCapture(this, NULL );
+ gFocusMgr.setMouseCapture(this);
localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
mLastMouseScreenX = mDragLastScreenX;
@@ -282,10 +282,10 @@ BOOL LLDragHandle::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLDragHandle::handleMouseUp(S32 x, S32 y, MASK mask)
{
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
// Release the mouse
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
}
// Note: don't pass on to children
@@ -298,7 +298,7 @@ BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
// We only handle the click if the click both started and ended within us
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
S32 screen_x;
S32 screen_y;
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 0922de70af..1f71de1c87 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -279,7 +279,6 @@ void LLFloater::init(const LLString& title,
mRect.getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
mDragHandle = new LLDragHandleLeft("drag", drag_handle_rect, title );
}
- mDragHandle->setSaveToXML(false);
addChild(mDragHandle);
// Resize Handle
@@ -295,28 +294,24 @@ void LLFloater::init(const LLString& title,
"resizebar_left",
LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0),
min_width, min_height, LLResizeBar::LEFT );
- mResizeBar[0]->setSaveToXML(false);
addChild( mResizeBar[0] );
mResizeBar[1] = new LLResizeBar(
"resizebar_top",
LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS),
min_width, min_height, LLResizeBar::TOP );
- mResizeBar[1]->setSaveToXML(false);
addChild( mResizeBar[1] );
mResizeBar[2] = new LLResizeBar(
"resizebar_right",
LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
min_width, min_height, LLResizeBar::RIGHT );
- mResizeBar[2]->setSaveToXML(false);
addChild( mResizeBar[2] );
mResizeBar[3] = new LLResizeBar(
"resizebar_bottom",
LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0),
min_width, min_height, LLResizeBar::BOTTOM );
- mResizeBar[3]->setSaveToXML(false);
addChild( mResizeBar[3] );
@@ -327,7 +322,6 @@ void LLFloater::init(const LLString& title,
min_width,
min_height,
LLResizeHandle::RIGHT_BOTTOM);
- mResizeHandle[0]->setSaveToXML(false);
addChild(mResizeHandle[0]);
mResizeHandle[1] = new LLResizeHandle( "resize",
@@ -335,7 +329,6 @@ void LLFloater::init(const LLString& title,
min_width,
min_height,
LLResizeHandle::RIGHT_TOP );
- mResizeHandle[1]->setSaveToXML(false);
addChild(mResizeHandle[1]);
mResizeHandle[2] = new LLResizeHandle( "resize",
@@ -343,7 +336,6 @@ void LLFloater::init(const LLString& title,
min_width,
min_height,
LLResizeHandle::LEFT_BOTTOM );
- mResizeHandle[2]->setSaveToXML(false);
addChild(mResizeHandle[2]);
mResizeHandle[3] = new LLResizeHandle( "resize",
@@ -351,7 +343,6 @@ void LLFloater::init(const LLString& title,
min_width,
min_height,
LLResizeHandle::LEFT_TOP );
- mResizeHandle[3]->setSaveToXML(false);
addChild(mResizeHandle[3]);
}
else
@@ -463,14 +454,14 @@ void LLFloater::setVisible( BOOL visible )
if( !visible )
{
- if( gFocusMgr.childIsTopView( this ) )
+ if( gFocusMgr.childIsTopCtrl( this ) )
{
- gFocusMgr.setTopView(NULL, NULL);
+ gFocusMgr.setTopCtrl(NULL);
}
if( gFocusMgr.childHasMouseCapture( this ) )
{
- gFocusMgr.setMouseCapture(NULL, NULL);
+ gFocusMgr.setMouseCapture(NULL);
}
}
@@ -584,9 +575,9 @@ void LLFloater::close(bool app_quitting)
void LLFloater::releaseFocus()
{
- if( gFocusMgr.childIsTopView( this ) )
+ if( gFocusMgr.childIsTopCtrl( this ) )
{
- gFocusMgr.setTopView(NULL, NULL);
+ gFocusMgr.setTopCtrl(NULL);
}
if( gFocusMgr.childHasKeyboardFocus( this ) )
@@ -596,7 +587,7 @@ void LLFloater::releaseFocus()
if( gFocusMgr.childHasMouseCapture( this ) )
{
- gFocusMgr.setMouseCapture(NULL, NULL);
+ gFocusMgr.setMouseCapture(NULL);
}
}
@@ -1464,28 +1455,24 @@ void LLFloater::setCanResize(BOOL can_resize)
"resizebar_left",
LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0),
mMinWidth, mMinHeight, LLResizeBar::LEFT );
- mResizeBar[0]->setSaveToXML(false);
addChild( mResizeBar[0] );
mResizeBar[1] = new LLResizeBar(
"resizebar_top",
LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS),
mMinWidth, mMinHeight, LLResizeBar::TOP );
- mResizeBar[1]->setSaveToXML(false);
addChild( mResizeBar[1] );
mResizeBar[2] = new LLResizeBar(
"resizebar_right",
LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
mMinWidth, mMinHeight, LLResizeBar::RIGHT );
- mResizeBar[2]->setSaveToXML(false);
addChild( mResizeBar[2] );
mResizeBar[3] = new LLResizeBar(
"resizebar_bottom",
LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0),
mMinWidth, mMinHeight, LLResizeBar::BOTTOM );
- mResizeBar[3]->setSaveToXML(false);
addChild( mResizeBar[3] );
@@ -1496,7 +1483,6 @@ void LLFloater::setCanResize(BOOL can_resize)
mMinWidth,
mMinHeight,
LLResizeHandle::RIGHT_BOTTOM);
- mResizeHandle[0]->setSaveToXML(false);
addChild(mResizeHandle[0]);
mResizeHandle[1] = new LLResizeHandle( "resize",
@@ -1504,7 +1490,6 @@ void LLFloater::setCanResize(BOOL can_resize)
mMinWidth,
mMinHeight,
LLResizeHandle::RIGHT_TOP );
- mResizeHandle[1]->setSaveToXML(false);
addChild(mResizeHandle[1]);
mResizeHandle[2] = new LLResizeHandle( "resize",
@@ -1512,7 +1497,6 @@ void LLFloater::setCanResize(BOOL can_resize)
mMinWidth,
mMinHeight,
LLResizeHandle::LEFT_BOTTOM );
- mResizeHandle[2]->setSaveToXML(false);
addChild(mResizeHandle[2]);
mResizeHandle[3] = new LLResizeHandle( "resize",
@@ -1520,7 +1504,6 @@ void LLFloater::setCanResize(BOOL can_resize)
mMinWidth,
mMinHeight,
LLResizeHandle::LEFT_TOP );
- mResizeHandle[3]->setSaveToXML(false);
addChild(mResizeHandle[3]);
}
mResizable = can_resize;
@@ -2022,8 +2005,7 @@ void LLFloaterView::focusFrontFloater()
void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
{
S32 col = 0;
- LLRect snap_rect_local = getSnapRect();
- snap_rect_local.translate(-mRect.mLeft, -mRect.mBottom);
+ LLRect snap_rect_local = getLocalSnapRect();
for(S32 row = snap_rect_local.mBottom;
row < snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE;
row += LLFLOATER_HEADER_SIZE ) //loop rows
@@ -2146,8 +2128,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
S32 screen_width = getSnapRect().getWidth();
S32 screen_height = getSnapRect().getHeight();
// convert to local coordinate frame
- LLRect snap_rect_local = getSnapRect();
- snap_rect_local.translate(-mRect.mLeft, -mRect.mBottom);
+ LLRect snap_rect_local = getLocalSnapRect();
if( floater->isResizable() )
{
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 030fbf0653..da53e3d104 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -21,18 +21,16 @@ LLFocusMgr::LLFocusMgr()
mLockedView( NULL ),
mKeyboardLockedFocusLostCallback( NULL ),
mMouseCaptor( NULL ),
- mMouseCaptureLostCallback( NULL ),
mKeyboardFocus( NULL ),
mDefaultKeyboardFocus( NULL ),
mKeyboardFocusLostCallback( NULL ),
- mTopView( NULL ),
- mTopViewLostCallback( NULL ),
+ mTopCtrl( NULL ),
mFocusWeight(0.f),
mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true
#ifdef _DEBUG
, mMouseCaptorName("none")
, mKeyboardFocusName("none")
- , mTopViewName("none")
+ , mTopCtrlName("none")
#endif
{
}
@@ -46,7 +44,7 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
{
if( childHasMouseCapture( view ) )
{
- setMouseCapture( NULL, NULL );
+ setMouseCapture( NULL );
}
if( childHasKeyboardFocus( view ))
@@ -63,9 +61,9 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
}
}
- if( childIsTopView( view ) )
+ if( childIsTopCtrl( view ) )
{
- setTopView( NULL, NULL );
+ setTopCtrl( NULL );
}
}
@@ -108,13 +106,13 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focu
// If we've got a default keyboard focus, and the caller is
// releasing keyboard focus, move to the default.
- if (mDefaultKeyboardFocus != NULL && new_focus == NULL)
+ if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL)
{
mDefaultKeyboardFocus->setFocus(TRUE);
}
- LLView* focus_subtree = new_focus;
- LLView* viewp = new_focus;
+ LLView* focus_subtree = mKeyboardFocus;
+ LLView* viewp = mKeyboardFocus;
// find root-most focus root
while(viewp)
{
@@ -128,13 +126,13 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focu
if (focus_subtree)
{
- mFocusHistory[focus_subtree->mViewHandle] = new_focus ? new_focus->mViewHandle : LLViewHandle::sDeadHandle;
+ mFocusHistory[focus_subtree->mViewHandle] = mKeyboardFocus ? mKeyboardFocus->mViewHandle : LLViewHandle::sDeadHandle;
}
}
if (lock)
{
- mLockedView = new_focus;
+ mLockedView = mKeyboardFocus;
mKeyboardLockedFocusLostCallback = on_focus_lost;
}
}
@@ -198,16 +196,13 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( LLView* focus )
}
-void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor, void (*on_capture_lost)(LLMouseHandler* old_captor) )
+void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
{
//if (mFocusLocked)
//{
// return;
//}
- void (*old_callback)(LLMouseHandler*) = mMouseCaptureLostCallback;
- mMouseCaptureLostCallback = on_capture_lost;
-
if( new_captor != mMouseCaptor )
{
LLMouseHandler* old_captor = mMouseCaptor;
@@ -230,9 +225,9 @@ void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor, void (*on_capture_
}
*/
- if( old_callback )
+ if( old_captor )
{
- old_callback( old_captor );
+ old_captor->onMouseCaptureLost();
}
#ifdef _DEBUG
@@ -250,7 +245,6 @@ void LLFocusMgr::removeMouseCaptureWithoutCallback( LLMouseHandler* captor )
if( mMouseCaptor == captor )
{
mMouseCaptor = NULL;
- mMouseCaptureLostCallback = NULL;
#ifdef _DEBUG
mMouseCaptorName = "none";
#endif
@@ -258,9 +252,9 @@ void LLFocusMgr::removeMouseCaptureWithoutCallback( LLMouseHandler* captor )
}
-BOOL LLFocusMgr::childIsTopView( LLView* parent )
+BOOL LLFocusMgr::childIsTopCtrl( LLView* parent )
{
- LLView* top_view = mTopView;
+ LLView* top_view = (LLView*)mTopCtrl;
while( top_view )
{
if( top_view == parent )
@@ -275,36 +269,25 @@ BOOL LLFocusMgr::childIsTopView( LLView* parent )
// set new_top = NULL to release top_view.
-void LLFocusMgr::setTopView( LLView* new_top, void (*on_top_lost)(LLView* old_top) )
+void LLFocusMgr::setTopCtrl( LLUICtrl* new_top )
{
- void (*old_callback)(LLView*) = mTopViewLostCallback;
- mTopViewLostCallback = on_top_lost;
-
- if( new_top != mTopView )
+ if( new_top != mTopCtrl )
{
- LLView* old_top = mTopView;
- mTopView = new_top;
- if( old_callback )
- {
- old_callback( old_top );
- }
-
- mTopView = new_top;
+ mTopCtrl = new_top;
#ifdef _DEBUG
- mTopViewName = new_top ? new_top->getName() : "none";
+ mTopCtrlName = new_top ? new_top->getName() : "none";
#endif
}
}
-void LLFocusMgr::removeTopViewWithoutCallback( LLView* top_view )
+void LLFocusMgr::removeTopCtrlWithoutCallback( LLUICtrl* top_view )
{
- if( mTopView == top_view )
+ if( mTopCtrl == top_view )
{
- mTopView = NULL;
- mTopViewLostCallback = NULL;
+ mTopCtrl = NULL;
#ifdef _DEBUG
- mTopViewName = "none";
+ mTopCtrlName = "none";
#endif
}
}
@@ -343,6 +326,12 @@ void LLFocusMgr::setAppHasFocus(BOOL focus)
{
triggerFocusFlash();
}
+
+ // release focus from "top ctrl"s, which generally hides them
+ if (!focus && mTopCtrl && mTopCtrl->hasFocus())
+ {
+ mTopCtrl->setFocus(FALSE);
+ }
mAppHasFocus = focus;
}
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index cb555fca91..dc8025d4c0 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -27,7 +27,7 @@ public:
~LLFocusMgr();
// Mouse Captor
- void setMouseCapture(LLMouseHandler* new_captor,void (*on_capture_lost)(LLMouseHandler* old_captor)); // new_captor = NULL to release the mouse.
+ void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse.
LLMouseHandler* getMouseCapture() { return mMouseCaptor; }
void removeMouseCaptureWithoutCallback( LLMouseHandler* captor );
BOOL childHasMouseCapture( LLView* parent );
@@ -54,10 +54,10 @@ public:
// Top View
- void setTopView(LLView* new_top, void (*on_top_lost)(LLView* old_top));
- LLView* getTopView() const { return mTopView; }
- void removeTopViewWithoutCallback( LLView* top_view );
- BOOL childIsTopView( LLView* parent );
+ void setTopCtrl(LLUICtrl* new_top);
+ LLUICtrl* getTopCtrl() const { return mTopCtrl; }
+ void removeTopCtrlWithoutCallback( LLUICtrl* top_view );
+ BOOL childIsTopCtrl( LLView* parent );
// All Three
void releaseFocusIfNeeded( LLView* top_view );
@@ -70,7 +70,6 @@ protected:
// Mouse Captor
LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object
- void (*mMouseCaptureLostCallback)(LLMouseHandler*); // The object to which mouse events are routed is called before another object takes its place
// Keyboard Focus
LLUICtrl* mKeyboardFocus; // Keyboard events are preemptively routed to this object
@@ -78,8 +77,7 @@ protected:
FocusLostCallback mKeyboardFocusLostCallback; // The object to which keyboard events are routed is called before another object takes its place
// Top View
- LLView* mTopView;
- void (*mTopViewLostCallback)(LLView*);
+ LLUICtrl* mTopCtrl;
LLFrameTimer mFocusTimer;
F32 mFocusWeight;
@@ -92,7 +90,7 @@ protected:
#ifdef _DEBUG
LLString mMouseCaptorName;
LLString mKeyboardFocusName;
- LLString mTopViewName;
+ LLString mTopCtrlName;
#endif
};
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 46d66b3cd4..7422a039dd 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -96,7 +96,7 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
S32 max_length_bytes,
void (*commit_callback)(LLUICtrl* caller, void* user_data ),
void (*keystroke_callback)(LLLineEditor* caller, void* user_data ),
- void (*focus_lost_callback)(LLLineEditor* caller, void* user_data ),
+ void (*focus_lost_callback)(LLUICtrl* caller, void* user_data ),
void* userdata,
LLLinePrevalidateFunc prevalidate_func,
LLViewBorder::EBevel border_bevel,
@@ -113,7 +113,6 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
mCommitOnFocusLost( TRUE ),
mRevertOnEsc( TRUE ),
mKeystrokeCallback( keystroke_callback ),
- mFocusLostCallback( focus_lost_callback ),
mIsSelecting( FALSE ),
mSelectionStart( 0 ),
mSelectionEnd( 0 ),
@@ -147,6 +146,8 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
mGLFont = LLFontGL::sSansSerifSmall;
}
+ setFocusLostCallback(focus_lost_callback);
+
mMinHPixels = mBorderThickness + UI_LINEEDITOR_H_PAD + mBorderLeft;
mMaxHPixels = mRect.getWidth() - mMinHPixels - mBorderThickness - mBorderRight;
@@ -167,7 +168,6 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
LLLineEditor::~LLLineEditor()
{
- mFocusLostCallback = NULL;
mCommitOnFocusLost = FALSE;
gFocusMgr.releaseFocusIfNeeded( this );
@@ -192,11 +192,8 @@ LLString LLLineEditor::getWidgetTag() const
void LLLineEditor::onFocusLost()
{
- if( mFocusLostCallback )
- {
- mFocusLostCallback( this, mCallbackUserData );
- }
-
+ LLUICtrl::onFocusLost();
+
if( mCommitOnFocusLost && mText.getString() != mPrevText)
{
onCommit();
@@ -483,7 +480,7 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
startSelection();
}
- gFocusMgr.setMouseCapture( this, &LLLineEditor::onMouseCaptureLost );
+ gFocusMgr.setMouseCapture( this );
}
// delay cursor flashing
@@ -496,14 +493,14 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- if (gFocusMgr.getMouseCapture() != this && (x < mBorderLeft || x > (mRect.getWidth() - mBorderRight)))
+ if (!hasMouseCapture() && (x < mBorderLeft || x > (mRect.getWidth() - mBorderRight)))
{
return LLUICtrl::handleHover(x, y, mask);
}
if( getVisible() )
{
- if( (gFocusMgr.getMouseCapture() == this) && mIsSelecting )
+ if( (hasMouseCapture()) && mIsSelecting )
{
if (x != mLastSelectionX || y != mLastSelectionY)
{
@@ -561,9 +558,9 @@ BOOL LLLineEditor::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
handled = TRUE;
}
@@ -1897,11 +1894,9 @@ BOOL LLLineEditor::prevalidateASCII(const LLWString &str)
return rv;
}
-//static
-void LLLineEditor::onMouseCaptureLost( LLMouseHandler* old_captor )
+void LLLineEditor::onMouseCaptureLost()
{
- LLLineEditor* self = (LLLineEditor*) old_captor;
- self->endSelection();
+ endSelection();
}
@@ -1916,11 +1911,6 @@ void LLLineEditor::setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor*
mKeystrokeCallback = keystroke_callback;
}
-void LLLineEditor::setFocusLostCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data))
-{
- mFocusLostCallback = keystroke_callback;
-}
-
// virtual
LLXMLNodePtr LLLineEditor::getXML(bool save_children) const
{
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index ef2f43a1d3..27ae351d1f 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -51,7 +51,7 @@ public:
S32 max_length_bytes = 254,
void (*commit_callback)(LLUICtrl* caller, void* user_data) = NULL,
void (*keystroke_callback)(LLLineEditor* caller, void* user_data) = NULL,
- void (*focus_lost_callback)(LLLineEditor* caller, void* user_data) = NULL,
+ void (*focus_lost_callback)(LLUICtrl* caller, void* user_data) = NULL,
void* userdata = NULL,
LLLinePrevalidateFunc prevalidate_func = NULL,
LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_IN,
@@ -72,6 +72,7 @@ public:
/*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent );
/*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
+ /*virtual*/ void onMouseCaptureLost();
// LLEditMenuHandler overrides
virtual void cut();
@@ -166,7 +167,6 @@ public:
void setSelectAllonFocusReceived(BOOL b);
void setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data));
- void setFocusLostCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data));
void setMaxTextLength(S32 max_text_length);
void setBorderWidth(S32 left, S32 right);
@@ -186,8 +186,6 @@ public:
static BOOL postvalidateFloat(const LLString &str);
- static void onMouseCaptureLost( LLMouseHandler* old_captor );
-
protected:
void removeChar();
void addChar(const llwchar c);
@@ -222,7 +220,6 @@ protected:
BOOL mRevertOnEsc;
void (*mKeystrokeCallback)( LLLineEditor* caller, void* userdata );
- void (*mFocusLostCallback)( LLLineEditor* caller, void* userdata );
BOOL mIsSelecting; // Selection for clipboard operations
S32 mSelectionStart;
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index d46a866e2b..79c38a87c0 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3235,6 +3235,7 @@ LLPieMenu::LLPieMenu(const LLString& name, const LLString& label)
mUseInfiniteRadius(FALSE),
mHoverItem(NULL),
mHoverThisFrame(FALSE),
+ mHoveredAnyItem(FALSE),
mOuterRingAlpha(1.f),
mCurRadius(0.f),
mRightMouseDown(FALSE)
@@ -3249,6 +3250,7 @@ LLPieMenu::LLPieMenu(const LLString& name)
mUseInfiniteRadius(FALSE),
mHoverItem(NULL),
mHoverThisFrame(FALSE),
+ mHoveredAnyItem(FALSE),
mOuterRingAlpha(1.f),
mCurRadius(0.f),
mRightMouseDown(FALSE)
@@ -3319,12 +3321,12 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
// release mouse capture after short period of visibility if we're using a finite boundary
// so that right click outside of boundary will trigger new pie menu
- if (gFocusMgr.getMouseCapture() == this &&
+ if (hasMouseCapture() &&
!mRightMouseDown &&
mShrinkBorderTimer.getStarted() &&
mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
{
- gFocusMgr.setMouseCapture(NULL, NULL);
+ gFocusMgr.setMouseCapture(NULL);
mUseInfiniteRadius = FALSE;
}
@@ -3376,6 +3378,7 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
break;
}
}
+ mHoveredAnyItem = TRUE;
}
else
{
@@ -3437,7 +3440,7 @@ BOOL LLPieMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
if (clicked_in_pie)
{
// capture mouse cursor as if on initial menu show
- gFocusMgr.setMouseCapture(this, NULL);
+ gFocusMgr.setMouseCapture(this);
mShrinkBorderTimer.stop();
mUseInfiniteRadius = TRUE;
handled = TRUE;
@@ -3463,11 +3466,22 @@ BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME)
{
mUseInfiniteRadius = FALSE;
- gFocusMgr.setMouseCapture(NULL, NULL);
+ gFocusMgr.setMouseCapture(NULL);
}
+ S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
+ S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
+ if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE)
+ {
+ // user released right mouse button in middle of pie, interpret this as closing the menu
+ sMenuContainer->hideMenus();
+ return TRUE;
+ }
+
+
BOOL result = handleMouseUp( x, y, mask );
mRightMouseDown = FALSE;
+ mHoveredAnyItem = FALSE;
return result;
}
@@ -3874,6 +3888,8 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
mRightMouseDown = mouse_down;
mFirstMouseDown = mouse_down;
mUseInfiniteRadius = TRUE;
+ mHoveredAnyItem = FALSE;
+
if (!mFirstMouseDown)
{
make_ui_sound("UISndPieMenuAppear");
@@ -3883,7 +3899,7 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
// we want all mouse events in case user does quick right click again off of pie menu
// rectangle, to support gestural menu traversal
- gFocusMgr.setMouseCapture(this, NULL);
+ gFocusMgr.setMouseCapture(this);
if (mouse_down)
{
@@ -3910,10 +3926,11 @@ void LLPieMenu::hide(BOOL item_selected)
mFirstMouseDown = FALSE;
mRightMouseDown = FALSE;
mUseInfiniteRadius = FALSE;
+ mHoveredAnyItem = FALSE;
LLView::setVisible(FALSE);
- gFocusMgr.setMouseCapture(NULL, NULL);
+ gFocusMgr.setMouseCapture(NULL);
}
///============================================================================
@@ -4510,6 +4527,7 @@ void LLTearOffMenu::onFocusLost()
{
// remove highlight from parent item and our own menu
mMenu->clearHoverItem();
+ LLFloater::onFocusLost();
}
BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index e60f267702..36ca815ef3 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -672,6 +672,7 @@ private:
BOOL mUseInfiniteRadius; // allow picking pie menu items anywhere outside of center circle
LLMenuItemGL* mHoverItem;
BOOL mHoverThisFrame;
+ BOOL mHoveredAnyItem;
LLFrameTimer mShrinkBorderTimer;
F32 mOuterRingAlpha; // for rendering pie menus as both bounded and unbounded
F32 mCurRadius;
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index 4eaf6b7559..4453767f92 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -65,8 +65,8 @@ void LLModalDialog::startModal()
}
// This is a modal dialog. It sucks up all mouse and keyboard operations.
- gFocusMgr.setMouseCapture( this, NULL );
- gFocusMgr.setTopView( this, NULL );
+ gFocusMgr.setMouseCapture( this );
+ gFocusMgr.setTopCtrl( this );
setFocus(TRUE);
sModalStack.push_front( this );
@@ -107,10 +107,10 @@ void LLModalDialog::setVisible( BOOL visible )
if( visible )
{
// This is a modal dialog. It sucks up all mouse and keyboard operations.
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
// The dialog view is a root view
- gFocusMgr.setTopView( this, NULL );
+ gFocusMgr.setTopCtrl( this );
setFocus( TRUE );
}
else
@@ -222,9 +222,9 @@ void LLModalDialog::draw()
if (mModal)
{
// If we've lost focus to a non-child, get it back ASAP.
- if( gFocusMgr.getTopView() != this )
+ if( gFocusMgr.getTopCtrl() != this )
{
- gFocusMgr.setTopView( this, NULL);
+ gFocusMgr.setTopCtrl( this );
}
if( !gFocusMgr.childHasKeyboardFocus( this ) )
@@ -234,7 +234,7 @@ void LLModalDialog::draw()
if( !gFocusMgr.childHasMouseCapture( this ) )
{
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
}
}
}
@@ -259,7 +259,7 @@ void LLModalDialog::onAppFocusLost()
LLModalDialog* instance = LLModalDialog::sModalStack.front();
if( gFocusMgr.childHasMouseCapture( instance ) )
{
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
}
if( gFocusMgr.childHasKeyboardFocus( instance ) )
@@ -277,9 +277,9 @@ void LLModalDialog::onAppFocusGained()
LLModalDialog* instance = LLModalDialog::sModalStack.front();
// This is a modal dialog. It sucks up all mouse and keyboard operations.
- gFocusMgr.setMouseCapture( instance, NULL );
+ gFocusMgr.setMouseCapture( instance );
instance->setFocus(TRUE);
- gFocusMgr.setTopView( instance, NULL );
+ gFocusMgr.setTopCtrl( instance );
instance->centerOnScreen();
}
diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp
index c6bc7fb355..0128b4ebbc 100644
--- a/indra/llui/llresizebar.cpp
+++ b/indra/llui/llresizebar.cpp
@@ -21,8 +21,8 @@
LLResizeBar::LLResizeBar( const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, Side side )
:
LLView( name, rect, TRUE ),
- mDragStartScreenX( 0 ),
- mDragStartScreenY( 0 ),
+ mDragLastScreenX( 0 ),
+ mDragLastScreenY( 0 ),
mLastMouseScreenX( 0 ),
mLastMouseScreenY( 0 ),
mMinWidth( min_width ),
@@ -55,6 +55,8 @@ LLResizeBar::LLResizeBar( const LLString& name, const LLRect& rect, S32 min_widt
default:
break;
}
+ // this is just a decorator
+ setSaveToXML(FALSE);
}
@@ -64,12 +66,11 @@ BOOL LLResizeBar::handleMouseDown(S32 x, S32 y, MASK mask)
{
// Route future Mouse messages here preemptively. (Release on mouse up.)
// No handler needed for focus lost since this clas has no state that depends on it.
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
- //localPointToScreen(x, y, &mDragStartScreenX, &mDragStartScreenX);
- localPointToOtherView(x, y, &mDragStartScreenX, &mDragStartScreenY, getParent()->getParent());
- mLastMouseScreenX = mDragStartScreenX;
- mLastMouseScreenY = mDragStartScreenY;
+ localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
+ mLastMouseScreenX = mDragLastScreenX;
+ mLastMouseScreenY = mDragLastScreenY;
}
return TRUE;
@@ -80,10 +81,10 @@ BOOL LLResizeBar::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
// Release the mouse
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
handled = TRUE;
}
else
@@ -108,74 +109,73 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
// We only handle the click if the click both started and ended within us
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
- // *NOTE: this, of course, is fragile
- LLView* floater_view = getParent()->getParent();
- S32 floater_view_x;
- S32 floater_view_y;
- localPointToOtherView(x, y, &floater_view_x, &floater_view_y, floater_view);
+ S32 screen_x;
+ S32 screen_y;
+ localPointToScreen(x, y, &screen_x, &screen_y);
- S32 delta_x = floater_view_x - mDragStartScreenX;
- S32 delta_y = floater_view_y - mDragStartScreenY;
+ S32 delta_x = screen_x - mDragLastScreenX;
+ S32 delta_y = screen_y - mDragLastScreenY;
LLCoordGL mouse_dir;
// use hysteresis on mouse motion to preserve user intent when mouse stops moving
- mouse_dir.mX = (floater_view_x == mLastMouseScreenX) ? mLastMouseDir.mX : floater_view_x - mLastMouseScreenX;
- mouse_dir.mY = (floater_view_y == mLastMouseScreenY) ? mLastMouseDir.mY : floater_view_y - mLastMouseScreenY;
+ mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
+ mouse_dir.mY = (screen_y == mLastMouseScreenY) ? mLastMouseDir.mY : screen_y - mLastMouseScreenY;
mLastMouseDir = mouse_dir;
- mLastMouseScreenX = floater_view_x;
- mLastMouseScreenY = floater_view_y;
+ mLastMouseScreenX = screen_x;
+ mLastMouseScreenY = screen_y;
// Make sure the mouse in still over the application. We don't want to make the parent
// so big that we can't see the resize handle any more.
- LLRect valid_rect = floater_view->getRect();
- LLView* parentView = getParent();
- if( valid_rect.localPointInRect( floater_view_x, floater_view_y ) && parentView )
+ LLRect valid_rect = getRootView()->getRect();
+ LLView* resizing_view = getParent();
+
+ if( valid_rect.localPointInRect( screen_x, screen_y ) && resizing_view )
{
// Resize the parent
- LLRect parent_rect = parentView->getRect();
- LLRect scaled_rect = parent_rect;
+ LLRect orig_rect = resizing_view->getRect();
+ LLRect scaled_rect = orig_rect;
- S32 new_width = parent_rect.getWidth();
- S32 new_height = parent_rect.getHeight();
+ S32 new_width = orig_rect.getWidth();
+ S32 new_height = orig_rect.getHeight();
switch( mSide )
{
case LEFT:
- new_width = parent_rect.getWidth() - delta_x;
+ new_width = orig_rect.getWidth() - delta_x;
if( new_width < mMinWidth )
{
new_width = mMinWidth;
- delta_x = parent_rect.getWidth() - mMinWidth;
+ delta_x = orig_rect.getWidth() - mMinWidth;
}
scaled_rect.translate(delta_x, 0);
break;
case TOP:
- new_height = parent_rect.getHeight() + delta_y;
+ new_height = orig_rect.getHeight() + delta_y;
if( new_height < mMinHeight )
{
new_height = mMinHeight;
- delta_y = mMinHeight - parent_rect.getHeight();
+ delta_y = mMinHeight - orig_rect.getHeight();
}
break;
case RIGHT:
- new_width = parent_rect.getWidth() + delta_x;
+ new_width = orig_rect.getWidth() + delta_x;
if( new_width < mMinWidth )
{
new_width = mMinWidth;
- delta_x = mMinWidth - parent_rect.getWidth();
+ delta_x = mMinWidth - orig_rect.getWidth();
}
break;
case BOTTOM:
- new_height = parent_rect.getHeight() - delta_y;
+ new_height = orig_rect.getHeight() - delta_y;
if( new_height < mMinHeight )
{
new_height = mMinHeight;
- delta_y = parent_rect.getHeight() - mMinHeight;
+ delta_y = orig_rect.getHeight() - mMinHeight;
}
scaled_rect.translate(0, delta_y);
break;
@@ -183,56 +183,59 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
scaled_rect.mTop = scaled_rect.mBottom + new_height;
scaled_rect.mRight = scaled_rect.mLeft + new_width;
- parentView->setRect(scaled_rect);
-
- S32 snap_delta_x = 0;
- S32 snap_delta_y = 0;
+ resizing_view->setRect(scaled_rect);
LLView* snap_view = NULL;
switch( mSide )
{
case LEFT:
- snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_x -= scaled_rect.mLeft;
- scaled_rect.mLeft += snap_delta_x;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
break;
case TOP:
- snap_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_y -= scaled_rect.mTop;
- scaled_rect.mTop += snap_delta_y;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
break;
case RIGHT:
- snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_x -= scaled_rect.mRight;
- scaled_rect.mRight += snap_delta_x;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
break;
case BOTTOM:
- snap_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_y -= scaled_rect.mBottom;
- scaled_rect.mBottom += snap_delta_y;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
break;
}
- parentView->snappedTo(snap_view);
+ // register "snap" behavior with snapped view
+ resizing_view->snappedTo(snap_view);
- parentView->setRect(parent_rect);
+ // restore original rectangle so the appropriate changes are detected
+ resizing_view->setRect(orig_rect);
+ // change view shape as user operation
+ resizing_view->userSetShape(scaled_rect);
- parentView->reshape(scaled_rect.getWidth(), scaled_rect.getHeight(), FALSE);
- parentView->translate(scaled_rect.mLeft - parentView->getRect().mLeft, scaled_rect.mBottom - parentView->getRect().mBottom);
-
- floater_view_x = mDragStartScreenX + delta_x;
- floater_view_y = mDragStartScreenY + delta_y;
- mDragStartScreenX = floater_view_x + snap_delta_x;
- mDragStartScreenY = floater_view_y + snap_delta_y;
+ // update last valid mouse cursor position based on resized view's actual size
+ LLRect new_rect = resizing_view->getRect();
+ switch(mSide)
+ {
+ case LEFT:
+ mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
+ break;
+ case RIGHT:
+ mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
+ break;
+ case TOP:
+ mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
+ break;
+ case BOTTOM:
+ mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
+ break;
+ default:
+ break;
+ }
}
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
handled = TRUE;
}
else
{
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;
handled = TRUE;
}
diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h
index c2a07fd3e3..7a77cce8a6 100644
--- a/indra/llui/llresizebar.h
+++ b/indra/llui/llresizebar.h
@@ -30,8 +30,8 @@ public:
void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; }
protected:
- S32 mDragStartScreenX;
- S32 mDragStartScreenY;
+ S32 mDragLastScreenX;
+ S32 mDragLastScreenY;
S32 mLastMouseScreenX;
S32 mLastMouseScreenY;
LLCoordGL mLastMouseDir;
diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp
index 77101fa296..e4035b3ab2 100644
--- a/indra/llui/llresizehandle.cpp
+++ b/indra/llui/llresizehandle.cpp
@@ -23,8 +23,8 @@ const S32 RESIZE_BORDER_WIDTH = 3;
LLResizeHandle::LLResizeHandle( const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, ECorner corner )
:
LLView( name, rect, TRUE ),
- mDragStartScreenX( 0 ),
- mDragStartScreenY( 0 ),
+ mDragLastScreenX( 0 ),
+ mDragLastScreenY( 0 ),
mLastMouseScreenX( 0 ),
mLastMouseScreenY( 0 ),
mImage( NULL ),
@@ -47,6 +47,9 @@ LLResizeHandle::LLResizeHandle( const LLString& name, const LLRect& rect, S32 mi
case RIGHT_TOP: setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP ); break;
case RIGHT_BOTTOM: setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); break;
}
+
+ // decorator object, don't serialize
+ setSaveToXML(FALSE);
}
EWidgetType LLResizeHandle::getWidgetType() const
@@ -69,11 +72,11 @@ BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask)
{
// Route future Mouse messages here preemptively. (Release on mouse up.)
// No handler needed for focus lost since this clas has no state that depends on it.
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
- localPointToScreen(x, y, &mDragStartScreenX, &mDragStartScreenY);
- mLastMouseScreenX = mDragStartScreenX;
- mLastMouseScreenY = mDragStartScreenY;
+ localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
+ mLastMouseScreenX = mDragLastScreenX;
+ mLastMouseScreenY = mDragLastScreenY;
}
}
@@ -85,10 +88,10 @@ BOOL LLResizeHandle::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
// Release the mouse
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
handled = TRUE;
}
else
@@ -106,7 +109,7 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
// We only handle the click if the click both started and ended within us
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
// Make sure the mouse in still over the application. We don't want to make the parent
// so big that we can't see the resize handle any more.
@@ -114,18 +117,18 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
S32 screen_x;
S32 screen_y;
localPointToScreen(x, y, &screen_x, &screen_y);
- const LLRect& valid_rect = gFloaterView->getRect(); // Assumes that the parent is a floater.
+ const LLRect valid_rect = getRootView()->getRect();
screen_x = llclamp( screen_x, valid_rect.mLeft, valid_rect.mRight );
screen_y = llclamp( screen_y, valid_rect.mBottom, valid_rect.mTop );
- LLView* parentView = getParent();
- if( parentView )
+ LLView* resizing_view = getParent();
+ if( resizing_view )
{
// Resize the parent
- LLRect parent_rect = parentView->getRect();
- LLRect scaled_rect = parent_rect;
- S32 delta_x = screen_x - mDragStartScreenX;
- S32 delta_y = screen_y - mDragStartScreenY;
+ LLRect orig_rect = resizing_view->getRect();
+ LLRect scaled_rect = orig_rect;
+ S32 delta_x = screen_x - mDragLastScreenX;
+ S32 delta_y = screen_y - mDragLastScreenY;
LLCoordGL mouse_dir;
// use hysteresis on mouse motion to preserve user intent when mouse stops moving
mouse_dir.mX = (screen_x == mLastMouseScreenX) ? mLastMouseDir.mX : screen_x - mLastMouseScreenX;
@@ -156,18 +159,18 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
break;
}
- S32 new_width = parent_rect.getWidth() + x_multiple * delta_x;
+ S32 new_width = orig_rect.getWidth() + x_multiple * delta_x;
if( new_width < mMinWidth )
{
new_width = mMinWidth;
- delta_x = x_multiple * (mMinWidth - parent_rect.getWidth());
+ delta_x = x_multiple * (mMinWidth - orig_rect.getWidth());
}
- S32 new_height = parent_rect.getHeight() + y_multiple * delta_y;
+ S32 new_height = orig_rect.getHeight() + y_multiple * delta_y;
if( new_height < mMinHeight )
{
new_height = mMinHeight;
- delta_y = y_multiple * (mMinHeight - parent_rect.getHeight());
+ delta_y = y_multiple * (mMinHeight - orig_rect.getHeight());
}
switch( mCorner )
@@ -188,10 +191,7 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
// temporarily set new parent rect
scaled_rect.mRight = scaled_rect.mLeft + new_width;
scaled_rect.mTop = scaled_rect.mBottom + new_height;
- parentView->setRect(scaled_rect);
-
- S32 snap_delta_x = 0;
- S32 snap_delta_y = 0;
+ resizing_view->setRect(scaled_rect);
LLView* snap_view = NULL;
LLView* test_view = NULL;
@@ -200,77 +200,78 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
switch(mCorner)
{
case LEFT_TOP:
- snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_x -= scaled_rect.mLeft;
- test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_y -= scaled_rect.mTop;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+ test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
if (!snap_view)
{
snap_view = test_view;
}
- scaled_rect.mLeft += snap_delta_x;
- scaled_rect.mTop += snap_delta_y;
break;
case LEFT_BOTTOM:
- snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_x -= scaled_rect.mLeft;
- test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_y -= scaled_rect.mBottom;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+ test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
if (!snap_view)
{
snap_view = test_view;
}
- scaled_rect.mLeft += snap_delta_x;
- scaled_rect.mBottom += snap_delta_y;
break;
case RIGHT_TOP:
- snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_x -= scaled_rect.mRight;
- test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_y -= scaled_rect.mTop;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+ test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
if (!snap_view)
{
snap_view = test_view;
}
- scaled_rect.mRight += snap_delta_x;
- scaled_rect.mTop += snap_delta_y;
break;
case RIGHT_BOTTOM:
- snap_view = parentView->findSnapEdge(snap_delta_x, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_x -= scaled_rect.mRight;
- test_view = parentView->findSnapEdge(snap_delta_y, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
- snap_delta_y -= scaled_rect.mBottom;
+ snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+ test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
if (!snap_view)
{
snap_view = test_view;
}
- scaled_rect.mRight += snap_delta_x;
- scaled_rect.mBottom += snap_delta_y;
break;
}
- parentView->snappedTo(snap_view);
+ // register "snap" behavior with snapped view
+ resizing_view->snappedTo(snap_view);
// reset parent rect
- parentView->setRect(parent_rect);
+ resizing_view->setRect(orig_rect);
// translate and scale to new shape
- parentView->reshape(scaled_rect.getWidth(), scaled_rect.getHeight(), FALSE);
- parentView->translate(scaled_rect.mLeft - parentView->getRect().mLeft, scaled_rect.mBottom - parentView->getRect().mBottom);
+ resizing_view->userSetShape(scaled_rect);
- screen_x = mDragStartScreenX + delta_x + snap_delta_x;
- screen_y = mDragStartScreenY + delta_y + snap_delta_y;
- mDragStartScreenX = screen_x;
- mDragStartScreenY = screen_y;
+ // update last valid mouse cursor position based on resized view's actual size
+ LLRect new_rect = resizing_view->getRect();
+ switch(mCorner)
+ {
+ case LEFT_TOP:
+ mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
+ mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
+ break;
+ case LEFT_BOTTOM:
+ mDragLastScreenX += new_rect.mLeft - orig_rect.mLeft;
+ mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
+ break;
+ case RIGHT_TOP:
+ mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
+ mDragLastScreenY += new_rect.mTop - orig_rect.mTop;
+ break;
+ case RIGHT_BOTTOM:
+ mDragLastScreenX += new_rect.mRight - orig_rect.mRight;
+ mDragLastScreenY += new_rect.mBottom- orig_rect.mBottom;
+ break;
+ default:
+ break;
+ }
}
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active) " << llendl;
handled = TRUE;
}
else
if( getVisible() && pointInHandle( x, y ) )
{
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive) " << llendl;
handled = TRUE;
}
diff --git a/indra/llui/llresizehandle.h b/indra/llui/llresizehandle.h
index 1350d1af20..cf383a33cc 100644
--- a/indra/llui/llresizehandle.h
+++ b/indra/llui/llresizehandle.h
@@ -37,8 +37,8 @@ protected:
BOOL pointInHandle( S32 x, S32 y );
protected:
- S32 mDragStartScreenX;
- S32 mDragStartScreenY;
+ S32 mDragLastScreenX;
+ S32 mDragLastScreenY;
S32 mLastMouseScreenX;
S32 mLastMouseScreenY;
LLCoordGL mLastMouseDir;
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index c21bbdcc75..f4aea3fa11 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -214,7 +214,7 @@ BOOL LLScrollbar::handleMouseDown(S32 x, S32 y, MASK mask)
{
// Start dragging the thumb
// No handler needed for focus lost since this clas has no state that depends on it.
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
mDragStartX = x;
mDragStartY = y;
mOrigRect.mTop = mThumbRect.mTop;
@@ -255,7 +255,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
// because they'll capture the mouse whenever they need hover events.
BOOL handled = FALSE;
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
S32 height = mRect.getHeight();
S32 width = mRect.getWidth();
@@ -408,9 +408,9 @@ BOOL LLScrollbar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
handled = TRUE;
}
else
@@ -442,7 +442,7 @@ void LLScrollbar::draw()
screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &local_mouse_x, &local_mouse_y);
BOOL other_captor = gFocusMgr.getMouseCapture() && gFocusMgr.getMouseCapture() != this;
- BOOL hovered = mEnabled && !other_captor && (gFocusMgr.getMouseCapture() == this || mThumbRect.pointInRect(local_mouse_x, local_mouse_y));
+ BOOL hovered = mEnabled && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y));
if (hovered)
{
mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLCriticalDamp::getInterpolant(0.05f));
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 15bb8e3f24..e5e31e45a9 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -437,7 +437,7 @@ void LLScrollableContainerView::draw()
// auto-focus when scrollbar active
// this allows us to capture user intent (i.e. stop automatically scrolling the view/etc)
if (!gFocusMgr.childHasKeyboardFocus(this) &&
- (gFocusMgr.getMouseCapture() == mScrollbar[VERTICAL] || gFocusMgr.getMouseCapture() == mScrollbar[HORIZONTAL]))
+ (mScrollbar[VERTICAL]->hasMouseCapture() || mScrollbar[HORIZONTAL]->hasMouseCapture()))
{
focusFirstItem();
}
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 35d5affa5d..98dddfb542 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -29,8 +29,11 @@
#include "llwindow.h"
#include "llcontrol.h"
#include "llkeyboard.h"
+#include "llresizebar.h"
const S32 LIST_BORDER_PAD = 2; // white space inside the border and to the left of the scrollbar
+const S32 MIN_COLUMN_WIDTH = 20;
+const S32 LIST_SNAP_PADDING = 5;
// local structures & classes.
struct SortScrollListItem
@@ -254,7 +257,7 @@ LLScrollListItem::~LLScrollListItem()
std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
}
-BOOL LLScrollListItem::handleMouseDown(S32 x, S32 y, MASK mask)
+BOOL LLScrollListItem::handleClick(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
@@ -355,14 +358,13 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
mPageLines(0),
mHeadingHeight(20),
mMaxSelectable(0),
- mHeadingFont(NULL),
mAllowMultipleSelection( allow_multiple_selection ),
mAllowKeyboardMovement(TRUE),
mCommitOnKeyboardMovement(TRUE),
mCommitOnSelectionChange(FALSE),
mSelectionChanged(FALSE),
mCanSelect(TRUE),
- mDisplayColumnButtons(FALSE),
+ mDisplayColumnHeaders(FALSE),
mCollapseEmptyColumns(FALSE),
mIsPopup(FALSE),
mMaxItemCount(INT_MAX),
@@ -377,21 +379,20 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
mFgUnselectedColor( LLUI::sColorsGroup->getColor("ScrollUnselectedColor") ),
mFgDisabledColor( LLUI::sColorsGroup->getColor("ScrollDisabledColor") ),
mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ),
+ mHighlightedItem(-1),
mBorderThickness( 2 ),
mOnDoubleClickCallback( NULL ),
mOnMaximumSelectCallback( NULL ),
mOnSortChangedCallback( NULL ),
- mHighlightedItem(-1),
+ mDrewSelected(FALSE),
mBorder(NULL),
- mDefaultColumn("SIMPLE"),
mSearchColumn(0),
+ mDefaultColumn("SIMPLE"),
mNumDynamicWidthColumns(0),
mTotalStaticColumnWidth(0),
- mSortColumn(0),
- mSortAscending(TRUE),
-
- mDrewSelected(FALSE)
+ mSortColumn(-1),
+ mSortAscending(TRUE)
{
mItemListRect.setOriginAndSize(
mBorderThickness + LIST_BORDER_PAD,
@@ -478,6 +479,7 @@ void LLScrollListCtrl::clearRows()
mScrollLines = 0;
mLastSelected = NULL;
+ updateMaxContentWidth(NULL);
}
@@ -527,7 +529,6 @@ S32 LLScrollListCtrl::getFirstSelectedIndex()
return -1;
}
-
LLScrollListItem* LLScrollListCtrl::getFirstData() const
{
if (mItemList.size() == 0)
@@ -537,6 +538,15 @@ LLScrollListItem* LLScrollListCtrl::getFirstData() const
return mItemList[0];
}
+LLScrollListItem* LLScrollListCtrl::getLastData() const
+{
+ if (mItemList.size() == 0)
+ {
+ return NULL;
+ }
+ return mItemList[mItemList.size() - 1];
+}
+
std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const
{
std::vector<LLScrollListItem*> ret;
@@ -554,7 +564,7 @@ void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
{
LLUICtrl::reshape( width, height, called_from_parent );
- S32 heading_size = (mDisplayColumnButtons ? mHeadingHeight : 0);
+ S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
mItemListRect.setOriginAndSize(
mBorderThickness + LIST_BORDER_PAD,
@@ -567,10 +577,8 @@ void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
mScrollbar->setPageSize( mPageLines );
updateColumns();
- updateColumnButtons();
}
-
// Attempt to size the control to show all items.
// Do not make larger than width or height.
void LLScrollListCtrl::arrange(S32 max_width, S32 max_height)
@@ -623,14 +631,56 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
updateLineHeight();
mPageLines = mLineHeight ? mItemListRect.getHeight() / mLineHeight : 0;
- mScrollbar->setVisible(mPageLines < getItemCount());
+ BOOL scrollbar_visible = mPageLines < getItemCount();
+
+ if (scrollbar_visible != mScrollbar->getVisible())
+ {
+ mScrollbar->setVisible(mPageLines < getItemCount());
+ updateColumns();
+ }
mScrollbar->setPageSize( mPageLines );
mScrollbar->setDocSize( getItemCount() );
+
+ updateMaxContentWidth(item);
}
+
return not_too_big;
}
+void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
+{
+ const S32 HEADING_TEXT_PADDING = 30;
+ const S32 COLUMN_TEXT_PADDING = 20;
+
+ std::map<LLString, LLScrollListColumn>::iterator column_itor;
+ for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
+ {
+ LLScrollListColumn* column = &column_itor->second;
+
+ if (!added_item)
+ {
+ // update on all items
+ column->mMaxContentWidth = column->mHeader ? LLFontGL::sSansSerifSmall->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0;
+ item_list::iterator iter;
+ for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ {
+ LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex);
+ if (!cellp) continue;
+
+ column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+ }
+ }
+ else
+ {
+ LLScrollListCell* cellp = added_item->getColumn(column->mIndex);
+ if (!cellp) continue;
+
+ column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+ }
+ }
+}
+
// Line height is the max height of all the cells in all the items.
void LLScrollListCtrl::updateLineHeight()
@@ -659,60 +709,82 @@ void LLScrollListCtrl::updateColumns()
for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
{
LLScrollListColumn *column = &column_itor->second;
+ S32 new_width = column->mWidth;
if (column->mRelWidth >= 0)
{
- column->mWidth = (S32)llround(column->mRelWidth*mItemListRect.getWidth());
+ new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth());
}
else if (column->mDynamicWidth)
{
- column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
-
+ new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
+ }
+
+ if (new_width != column->mWidth)
+ {
+ column->mWidth = new_width;
}
mColumnsIndexed[column_itor->second.mIndex] = column;
}
-}
-void LLScrollListCtrl::updateColumnButtons()
-{
- std::map<LLString, LLScrollListColumn>::iterator column_itor;
- for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
+ item_list::iterator iter;
+ for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{
- LLScrollListColumn* column = &column_itor->second;
- LLButton *button = column->mButton;
-
- if (button)
+ LLScrollListItem *itemp = *iter;
+ S32 num_cols = itemp->getNumColumns();
+ S32 i = 0;
+ for (LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
{
- mColumnsIndexed[column->mIndex] = column;
+ if (i >= (S32)mColumnsIndexed.size()) break;
+
+ cell->setWidth(mColumnsIndexed[i]->mWidth);
+ }
+ }
+ // update headers
+ std::vector<LLScrollListColumn*>::iterator column_ordered_it;
+ S32 left = mItemListRect.mLeft;
+ LLColumnHeader* last_header = NULL;
+ for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it)
+ {
+ if ((*column_ordered_it)->mWidth <= 0)
+ {
+ // skip hidden columns
+ }
+ LLScrollListColumn* column = *column_ordered_it;
+
+ if (column->mHeader)
+ {
+ last_header = column->mHeader;
S32 top = mItemListRect.mTop;
- S32 left = mItemListRect.mLeft;
- {
- std::map<LLString, LLScrollListColumn>::iterator itor;
- for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
- {
- if (itor->second.mIndex < column->mIndex &&
- itor->second.mWidth > 0)
- {
- left += itor->second.mWidth + mColumnPadding;
- }
- }
- }
- S32 right = left+column->mWidth;
- if (column->mIndex != (S32)mColumns.size()-1)
+ S32 right = left + column->mWidth;
+
+ if (column->mIndex != (S32)mColumnsIndexed.size()-1)
{
right += mColumnPadding;
}
- LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
- button->setRect(temp_rect);
- button->setFont(mHeadingFont);
- button->setVisible(mDisplayColumnButtons);
+ right = llmax(left, llmin(mItemListRect.getWidth(), right));
+
+ S32 header_width = right - left;
+
+ last_header->reshape(header_width, mHeadingHeight);
+ last_header->translate(left - last_header->getRect().mLeft, top - last_header->getRect().mBottom);
+ last_header->setVisible(mDisplayColumnHeaders && header_width > 0);
+ left = right;
}
}
+
+ // expand last column header we encountered to full list width
+ if (last_header)
+ {
+ S32 header_strip_width = mItemListRect.getWidth() + (mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE);
+ S32 new_width = llmax(0, mItemListRect.mLeft + header_strip_width - last_header->getRect().mLeft);
+ last_header->reshape(new_width, last_header->getRect().getHeight());
+ }
}
void LLScrollListCtrl::setDisplayHeading(BOOL display)
{
- mDisplayColumnButtons = display;
+ mDisplayColumnHeaders = display;
updateColumns();
@@ -726,15 +798,7 @@ void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
reshape(mRect.getWidth(), mRect.getHeight());
// Resize
- mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight());
-
- updateColumnButtons();
-}
-
-void LLScrollListCtrl::setHeadingFont(const LLFontGL* heading_font)
-{
- mHeadingFont = heading_font;
- updateColumnButtons();
+ mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
}
void LLScrollListCtrl::setCollapseEmptyColumns(BOOL collapse)
@@ -854,6 +918,7 @@ void LLScrollListCtrl::deleteSingleItem(S32 target_index)
}
delete itemp;
mItemList.erase(mItemList.begin() + target_index);
+ updateMaxContentWidth(NULL);
}
void LLScrollListCtrl::deleteSelectedItems()
@@ -873,6 +938,7 @@ void LLScrollListCtrl::deleteSelectedItems()
}
}
mLastSelected = NULL;
+ updateMaxContentWidth(NULL);
}
void LLScrollListCtrl::highlightNthItem(S32 target_index)
@@ -880,6 +946,7 @@ void LLScrollListCtrl::highlightNthItem(S32 target_index)
if (mHighlightedItem != target_index)
{
mHighlightedItem = target_index;
+ llinfos << "Highlighting item " << target_index << llendl;
}
}
@@ -1467,109 +1534,154 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
return handled;
}
-
-BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
+BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
- BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+ if (!mCanSelect) return FALSE;
- // set keyboard focus first, in case click action wants to move focus elsewhere
- setFocus(TRUE);
+ BOOL selection_changed = FALSE;
- if( !handled && mCanSelect)
+ LLScrollListItem* hit_item = hitItem(x, y);
+ if( hit_item )
{
- LLScrollListItem* hit_item = hitItem(x, y);
- if( hit_item )
+ if( mAllowMultipleSelection )
{
- if( mAllowMultipleSelection )
+ if (mask & MASK_SHIFT)
{
- if (mask & MASK_SHIFT)
+ if (mLastSelected == NULL)
{
- if (mLastSelected == NULL)
- {
- selectItem(hit_item);
- }
- else
+ selectItem(hit_item);
+ }
+ else
+ {
+ // Select everthing between mLastSelected and hit_item
+ bool selecting = false;
+ item_list::iterator itor;
+ // If we multiselect backwards, we'll stomp on mLastSelected,
+ // meaning that we never stop selecting until hitting max or
+ // the end of the list.
+ LLScrollListItem* lastSelected = mLastSelected;
+ for (itor = mItemList.begin(); itor != mItemList.end(); ++itor)
{
- // Select everthing between mLastSelected and hit_item
- bool selecting = false;
- item_list::iterator itor;
- // If we multiselect backwards, we'll stomp on mLastSelected,
- // meaning that we never stop selecting until hitting max or
- // the end of the list.
- LLScrollListItem* lastSelected = mLastSelected;
- for (itor = mItemList.begin(); itor != mItemList.end(); ++itor)
+ if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)
{
- if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable)
- {
- if(mOnMaximumSelectCallback)
- {
- mOnMaximumSelectCallback(mCallbackUserData);
- }
- break;
- }
- LLScrollListItem *item = *itor;
- if (item == hit_item || item == lastSelected)
- {
- selectItem(item, FALSE);
- selecting = !selecting;
- }
- if (selecting)
+ if(mOnMaximumSelectCallback)
{
- selectItem(item, FALSE);
+ mOnMaximumSelectCallback(mCallbackUserData);
}
+ break;
+ }
+ LLScrollListItem *item = *itor;
+ if (item == hit_item || item == lastSelected)
+ {
+ selectItem(item, FALSE);
+ selecting = !selecting;
+ }
+ if (selecting)
+ {
+ selectItem(item, FALSE);
}
}
}
- else if (mask & MASK_CONTROL)
+ }
+ else if (mask & MASK_CONTROL)
+ {
+ if (hit_item->getSelected())
{
- if (hit_item->getSelected())
+ deselectItem(hit_item);
+ }
+ else
+ {
+ if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
{
- deselectItem(hit_item);
+ selectItem(hit_item, FALSE);
}
else
{
- if(!(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable))
+ if(mOnMaximumSelectCallback)
{
- selectItem(hit_item, FALSE);
- }
- else
- {
- if(mOnMaximumSelectCallback)
- {
- mOnMaximumSelectCallback(mCallbackUserData);
- }
+ mOnMaximumSelectCallback(mCallbackUserData);
}
}
}
- else
- {
- deselectAllItems(TRUE);
- selectItem(hit_item);
- }
}
else
{
+ deselectAllItems(TRUE);
selectItem(hit_item);
}
-
- hit_item->handleMouseDown(x - mBorderThickness - LIST_BORDER_PAD,
- 1, mask);
- // always commit on mousedown
- onCommit();
- mSelectionChanged = FALSE;
-
- // clear search string on mouse operations
- mSearchString.clear();
}
else
{
- mLastSelected = NULL;
+ selectItem(hit_item);
}
+
+ hit_item->handleClick(x - mBorderThickness - LIST_BORDER_PAD,
+ 1, mask);
+
+ selection_changed = mSelectionChanged;
+ if (mCommitOnSelectionChange)
+ {
+ commitIfChanged();
+ }
+
+ // clear search string on mouse operations
+ mSearchString.clear();
+ }
+ else
+ {
+ //mLastSelected = NULL;
+ //deselectAllItems(TRUE);
+ }
+
+ return selection_changed;
+}
+
+
+BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+
+ if( !handled )
+ {
+ // set keyboard focus first, in case click action wants to move focus elsewhere
+ setFocus(TRUE);
+
+ // clear selection changed flag so because user is starting a selection operation
+ mSelectionChanged = FALSE;
+
+ gFocusMgr.setMouseCapture(this);
+ selectItemAt(x, y, mask);
}
return TRUE;
}
+BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ if (hasMouseCapture())
+ {
+ if(mask == MASK_NONE)
+ {
+ selectItemAt(x, y, mask);
+ }
+ }
+
+ if (hasMouseCapture())
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ }
+
+ // always commit when mouse operation is completed inside list
+ // this only needs to be done for lists that don't commit on selection change
+ if (!mCommitOnSelectionChange && pointInView(x,y))
+ {
+ mSelectionChanged = FALSE;
+ onCommit();
+ }
+
+ return LLUICtrl::handleMouseUp(x, y, mask);
+}
+
BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
{
//BOOL handled = FALSE;
@@ -1628,31 +1740,35 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
{
BOOL handled = FALSE;
- if(getVisible())
+ if (hasMouseCapture())
{
- if (mCanSelect)
+ if(mask == MASK_NONE)
{
- LLScrollListItem* item = hitItem(x, y);
- if (item)
- {
- highlightNthItem(getItemIndex(item));
- }
- else
- {
- highlightNthItem(-1);
- }
+ selectItemAt(x, y, mask);
}
-
- handled = LLView::handleHover( x, y, mask );
-
- if( !handled )
+ }
+ else if (mCanSelect)
+ {
+ LLScrollListItem* item = hitItem(x, y);
+ if (item)
+ {
+ highlightNthItem(getItemIndex(item));
+ }
+ else
{
- // Opaque
- getWindow()->setCursor(UI_CURSOR_ARROW);
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
- handled = TRUE;
+ highlightNthItem(-1);
}
}
+
+ handled = LLUICtrl::handleHover( x, y, mask );
+
+ //if( !handled )
+ //{
+ // // Opaque
+ // getWindow()->setCursor(UI_CURSOR_ARROW);
+ // lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
+ // handled = TRUE;
+ //}
return handled;
}
@@ -1954,7 +2070,7 @@ void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp)
void LLScrollListCtrl::commitIfChanged()
{
- if (mSelectionChanged)
+ if (mSelectionChanged && !hasMouseCapture())
{
mSelectionChanged = FALSE;
onCommit();
@@ -1973,9 +2089,18 @@ void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void
// First column is column 0
void LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
{
- mSortColumn = column;
- mSortAscending = ascending;
- std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
+ if (mSortColumn != column)
+ {
+ mSortColumn = column;
+ std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
+ }
+
+ // just reverse the list if changing sort order
+ if(mSortAscending != ascending)
+ {
+ std::reverse(mItemList.begin(), mItemList.end());
+ mSortAscending = ascending;
+ }
}
void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
@@ -2047,7 +2172,7 @@ LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const
node->createChild("draw_border", TRUE)->setBoolValue((mBorder != NULL));
- node->createChild("draw_heading", TRUE)->setBoolValue(mDisplayColumnButtons);
+ node->createChild("draw_heading", TRUE)->setBoolValue(mDisplayColumnHeaders);
node->createChild("background_visible", TRUE)->setBoolValue(mBackgroundVisible);
@@ -2196,13 +2321,6 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
node->getAttributeS32("heading_height", heading_height);
scroll_list->setHeadingHeight(heading_height);
}
- if (node->hasAttribute("heading_font"))
- {
- LLString heading_font("");
- node->getAttributeString("heading_font", heading_font);
- LLFontGL* gl_font = LLFontGL::fontFromName(heading_font.c_str());
- scroll_list->setHeadingFont(gl_font);
- }
scroll_list->setCollapseEmptyColumns(collapse_empty_columns);
scroll_list->setScrollListParameters(node);
@@ -2408,7 +2526,7 @@ BOOL LLScrollListCtrl::canDeselect()
void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
{
LLString name = column["name"].asString();
- if (mColumns.size() == 0)
+ if (mColumns.empty())
{
mDefaultColumn = 0;
}
@@ -2451,30 +2569,28 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
right += mColumnPadding;
}
LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
- new_column->mButton = new LLSquareButton(button_name, temp_rect, "", mHeadingFont, "", onClickColumn, NULL);
+ new_column->mHeader = new LLColumnHeader(button_name, temp_rect, new_column);
if(column["image"].asString() != "")
{
- //new_column->mButton->setScaleImage(false);
- new_column->mButton->setImageSelected(column["image"].asString());
- new_column->mButton->setImageUnselected(column["image"].asString());
+ //new_column->mHeader->setScaleImage(false);
+ new_column->mHeader->setImage(column["image"].asString());
}
else
{
- new_column->mButton->setLabelSelected(new_column->mLabel);
- new_column->mButton->setLabelUnselected(new_column->mLabel);
+ new_column->mHeader->setLabel(new_column->mLabel);
+ //new_column->mHeader->setLabel(new_column->mLabel);
}
//RN: although it might be useful to change sort order with the keyboard,
// mixing tab stops on child items along with the parent item is not supported yet
- new_column->mButton->setTabStop(FALSE);
- addChild(new_column->mButton);
- new_column->mButton->setVisible(mDisplayColumnButtons);
+ new_column->mHeader->setTabStop(FALSE);
+ addChild(new_column->mHeader);
+ new_column->mHeader->setVisible(mDisplayColumnHeaders);
// Move scroll to front
removeChild(mScrollbar);
addChild(mScrollbar);
-
- new_column->mButton->setCallbackUserData(new_column);
+
}
}
updateColumns();
@@ -2517,7 +2633,7 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
std::string LLScrollListCtrl::getSortColumnName()
{
- LLScrollListColumn* column = mColumnsIndexed[mSortColumn];
+ LLScrollListColumn* column = mSortColumn >= 0 ? mColumnsIndexed[mSortColumn] : NULL;
if (column) return column->mName;
else return "";
@@ -2528,11 +2644,11 @@ void LLScrollListCtrl::clearColumns()
std::map<LLString, LLScrollListColumn>::iterator itor;
for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
{
- LLButton *button = itor->second.mButton;
- if (button)
+ LLColumnHeader *header = itor->second.mHeader;
+ if (header)
{
- removeChild(button);
- delete button;
+ removeChild(header);
+ delete header;
}
}
mColumns.clear();
@@ -2544,14 +2660,22 @@ void LLScrollListCtrl::setColumnLabel(const LLString& column, const LLString& la
if (itor != mColumns.end())
{
itor->second.mLabel = label;
- if (itor->second.mButton)
+ if (itor->second.mHeader)
{
- itor->second.mButton->setLabelSelected(label);
- itor->second.mButton->setLabelUnselected(label);
+ itor->second.mHeader->setLabel(label);
}
}
}
+LLScrollListColumn* LLScrollListCtrl::getColumn(S32 index)
+{
+ if (index < 0 || index >= (S32)mColumnsIndexed.size())
+ {
+ return NULL;
+ }
+ return mColumnsIndexed[index];
+}
+
void LLScrollListCtrl::setColumnHeadings(LLSD headings)
{
mColumns.clear();
@@ -2629,6 +2753,10 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
else
{
new_item->setColumn(index, new LLScrollListText(value.asString(), font, width, font_style, font_alignment));
+ if (column_itor->second.mHeader && !value.asString().empty())
+ {
+ column_itor->second.mHeader->setHasResizableElement(TRUE);
+ }
}
}
@@ -2725,6 +2853,14 @@ void LLScrollListCtrl::setFocus(BOOL b)
}
LLUICtrl::setFocus(b);
}
+
+//virtual
+void LLScrollListCtrl::onFocusReceived()
+{
+ // forget latent selection changes when getting focus
+ mSelectionChanged = FALSE;
+}
+
//virtual
void LLScrollListCtrl::onFocusLost()
{
@@ -2735,5 +2871,433 @@ void LLScrollListCtrl::onFocusLost()
getParent()->onFocusLost();
}
}
+ if (hasMouseCapture())
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ }
+ LLUICtrl::onFocusLost();
+}
+
+LLColumnHeader::LLColumnHeader(const LLString& label, const LLRect &rect, LLScrollListColumn* column, const LLFontGL* fontp) :
+ LLComboBox(label, rect, label, NULL, NULL),
+ mColumn(column),
+ mOrigLabel(label),
+ mShowSortOptions(FALSE),
+ mHasResizableElement(FALSE)
+{
+ mListPosition = LLComboBox::ABOVE;
+ setCommitCallback(onSelectSort);
+ setCallbackUserData(this);
+ mButton->setTabStop(FALSE);
+ // require at least two frames between mouse down and mouse up event to capture intentional "hold" not just bad framerate
+ mButton->setHeldDownDelay(LLUI::sConfigGroup->getF32("ColumnHeaderDropDownDelay"), 2);
+ mButton->setHeldDownCallback(onHeldDown);
+ mButton->setClickedCallback(onClick);
+ mButton->setMouseDownCallback(onMouseDown);
+
+ mButton->setCallbackUserData(this);
+
+ mAscendingText = "[LOW]...[HIGH](Ascending)";
+ mDescendingText = "[HIGH]...[LOW](Descending)";
+
+ LLSD row;
+ row["columns"][0]["column"] = "label";
+ row["columns"][0]["value"] = mAscendingText.getString();
+ row["columns"][0]["font"] = "SANSSERIF_SMALL";
+ row["columns"][0]["width"] = 80;
+
+ row["columns"][1]["column"] = "arrow";
+ row["columns"][1]["type"] = "icon";
+ row["columns"][1]["value"] = LLUI::sAssetsGroup->getString("up_arrow.tga");
+ row["columns"][1]["width"] = 20;
+
+ mList->addElement(row);
+
+ row["columns"][0]["column"] = "label";
+ row["columns"][0]["type"] = "text";
+ row["columns"][0]["value"] = mDescendingText.getString();
+ row["columns"][0]["font"] = "SANSSERIF_SMALL";
+ row["columns"][0]["width"] = 80;
+
+ row["columns"][1]["column"] = "arrow";
+ row["columns"][1]["type"] = "icon";
+ row["columns"][1]["value"] = LLUI::sAssetsGroup->getString("down_arrow.tga");
+ row["columns"][1]["width"] = 20;
+
+ mList->addElement(row);
+
+ mList->reshape(llmax(mList->getRect().getWidth(), 110, mRect.getWidth()), mList->getRect().getHeight());
+
+ // resize handles on left and right
+ const S32 RESIZE_BAR_THICKNESS = 3;
+ mResizeBar = new LLResizeBar(
+ "resizebar",
+ LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
+ MIN_COLUMN_WIDTH, mRect.getHeight(), LLResizeBar::RIGHT );
+ addChild(mResizeBar);
+
+ mResizeBar->setEnabled(FALSE);
+}
+
+LLColumnHeader::~LLColumnHeader()
+{
+}
+
+void LLColumnHeader::draw()
+{
+ if( getVisible() )
+ {
+ mDrawArrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
+
+ BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
+ mArrowImage = is_ascending ? LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("up_arrow.tga")))
+ : LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("down_arrow.tga")));
+
+ //BOOL clip = mRect.mRight > mColumn->mParentCtrl->getItemListRect().getWidth();
+ //LLGLEnable scissor_test(clip ? GL_SCISSOR_TEST : GL_FALSE);
+
+ //LLRect column_header_local_rect(-mRect.mLeft, mRect.getHeight(), mColumn->mParentCtrl->getItemListRect().getWidth() - mRect.mLeft, 0);
+ //LLUI::setScissorRegionLocal(column_header_local_rect);
+
+ // Draw children
+ LLComboBox::draw();
+
+ if (mList->getVisible())
+ {
+ // sync sort order with list selection every frame
+ mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, getCurrentIndex() == 0);
+ }
+
+ }
+}
+
+BOOL LLColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ if (canResize() && mResizeBar->getRect().pointInRect(x, y))
+ {
+ // reshape column to max content width
+ LLRect column_rect = getRect();
+ column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
+ userSetShape(column_rect);
+ }
+ else
+ {
+ onClick(this);
+ }
+ return TRUE;
+}
+
+void LLColumnHeader::setImage(const LLString &image_name)
+{
+ if (mButton)
+ {
+ mButton->setImageSelected(image_name);
+ mButton->setImageUnselected(image_name);
+ }
+}
+
+//static
+void LLColumnHeader::onClick(void* user_data)
+{
+ LLColumnHeader* headerp = (LLColumnHeader*)user_data;
+ if (!headerp) return;
+
+ LLScrollListColumn* column = headerp->mColumn;
+ if (!column) return;
+
+ if (headerp->mList->getVisible())
+ {
+ headerp->hideList();
+ }
+
+ LLScrollListCtrl::onClickColumn(column);
+
+ // propage new sort order to sort order list
+ headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1);
+}
+
+//static
+void LLColumnHeader::onMouseDown(void* user_data)
+{
+ // for now, do nothing but block the normal showList() behavior
+ return;
+}
+
+//static
+void LLColumnHeader::onHeldDown(void* user_data)
+{
+ LLColumnHeader* headerp = (LLColumnHeader*)user_data;
+ headerp->showList();
+}
+
+void LLColumnHeader::showList()
+{
+ if (mShowSortOptions)
+ {
+ //LLSD item_val = mColumn->mParentCtrl->getFirstData()->getValue();
+ mOrigLabel = mButton->getLabelSelected();
+
+ // move sort column over to this column and do initial sort
+ mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, mColumn->mParentCtrl->getSortAscending());
+
+ LLString low_item_text;
+ LLString high_item_text;
+
+ LLScrollListItem* itemp = mColumn->mParentCtrl->getFirstData();
+ if (itemp)
+ {
+ LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
+ if (cell && cell->isText())
+ {
+ if (mColumn->mParentCtrl->getSortAscending())
+ {
+ low_item_text = cell->getText();
+ }
+ else
+ {
+ high_item_text = cell->getText();
+ }
+ }
+ }
+
+ itemp = mColumn->mParentCtrl->getLastData();
+ if (itemp)
+ {
+ LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
+ if (cell && cell->isText())
+ {
+ if (mColumn->mParentCtrl->getSortAscending())
+ {
+ high_item_text = cell->getText();
+ }
+ else
+ {
+ low_item_text = cell->getText();
+ }
+ }
+ }
+
+ LLString::truncate(low_item_text, 3);
+ LLString::truncate(high_item_text, 3);
+
+ LLString ascending_string;
+ LLString descending_string;
+
+ if (low_item_text.empty() || high_item_text.empty())
+ {
+ ascending_string = "Ascending";
+ descending_string = "Descending";
+ }
+ else
+ {
+ mAscendingText.setArg("[LOW]", low_item_text);
+ mAscendingText.setArg("[HIGH]", high_item_text);
+ mDescendingText.setArg("[LOW]", low_item_text);
+ mDescendingText.setArg("[HIGH]", high_item_text);
+ ascending_string = mAscendingText.getString();
+ descending_string = mDescendingText.getString();
+ }
+
+ S32 text_width = LLFontGL::sSansSerifSmall->getWidth(ascending_string);
+ text_width = llmax(text_width, LLFontGL::sSansSerifSmall->getWidth(descending_string)) + 10;
+ text_width = llmax(text_width, mRect.getWidth() - 30);
+
+ mList->getColumn(0)->mWidth = text_width;
+ ((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string);
+ ((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string);
+
+ mList->reshape(llmax(text_width + 30, 110, mRect.getWidth()), mList->getRect().getHeight());
+
+ LLComboBox::showList();
+ }
}
+//static
+void LLColumnHeader::onSelectSort(LLUICtrl* ctrl, void* user_data)
+{
+ LLColumnHeader* headerp = (LLColumnHeader*)user_data;
+ if (!headerp) return;
+
+ LLScrollListColumn* column = headerp->mColumn;
+ if (!column) return;
+ LLScrollListCtrl *parent = column->mParentCtrl;
+ if (!parent) return;
+
+ if (headerp->getCurrentIndex() == 0)
+ {
+ // ascending
+ parent->sortByColumn(column->mSortingColumn, TRUE);
+ }
+ else
+ {
+ // descending
+ parent->sortByColumn(column->mSortingColumn, FALSE);
+ }
+
+ // restore original column header
+ headerp->setLabel(headerp->mOrigLabel);
+}
+
+LLView* LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
+{
+ // this logic assumes dragging on right
+ llassert(snap_edge == SNAP_RIGHT);
+
+ // use higher snap threshold for column headers
+ threshold = llmin(threshold, 15);
+
+ LLRect snap_rect = getSnapRect();
+
+ S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth();
+
+ // x coord growing means column growing, so same signs mean we're going in right direction
+ if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
+ {
+ new_edge_val = snap_rect.mRight + snap_delta;
+ }
+ else
+ {
+ LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1);
+ while (next_column)
+ {
+ if (next_column->mHeader)
+ {
+ snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight;
+ if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 )
+ {
+ new_edge_val = snap_rect.mRight + snap_delta;
+ }
+ break;
+ }
+ next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1);
+ }
+ }
+
+ return this;
+}
+
+void LLColumnHeader::userSetShape(const LLRect& new_rect)
+{
+ S32 new_width = new_rect.getWidth();
+ S32 delta_width = new_width - (mRect.getWidth() + mColumn->mParentCtrl->getColumnPadding());
+
+ if (delta_width != 0)
+ {
+ S32 remaining_width = delta_width;
+ S32 col;
+ for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
+ {
+ LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
+ if (!columnp) break;
+
+ if (columnp->mHeader && columnp->mHeader->canResize())
+ {
+ // how many pixels in width can this column afford to give up?
+ S32 resize_buffer_amt = llmax(0, columnp->mWidth - MIN_COLUMN_WIDTH);
+
+ // user shrinking column, need to add width to other columns
+ if (delta_width < 0)
+ {
+ if (!columnp->mDynamicWidth && columnp->mWidth > 0)
+ {
+ // statically sized column, give all remaining width to this column
+ columnp->mWidth -= remaining_width;
+ if (columnp->mRelWidth > 0.f)
+ {
+ columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
+ }
+ }
+ break;
+ }
+ else
+ {
+ // user growing column, need to take width from other columns
+ remaining_width -= resize_buffer_amt;
+
+ if (!columnp->mDynamicWidth && columnp->mWidth > 0)
+ {
+ columnp->mWidth -= llmin(columnp->mWidth - MIN_COLUMN_WIDTH, delta_width);
+ if (columnp->mRelWidth > 0.f)
+ {
+ columnp->mRelWidth = (F32)columnp->mWidth / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
+ }
+ }
+
+ if (remaining_width <= 0)
+ {
+ // width sucked up from neighboring columns, done
+ break;
+ }
+ }
+ }
+ }
+
+ // clamp resize amount to maximum that can be absorbed by other columns
+ if (delta_width > 0)
+ {
+ delta_width -= llmax(remaining_width, 0);
+ }
+
+ // propagate constrained delta_width to new width for this column
+ new_width = mRect.getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
+
+ // use requested width
+ mColumn->mWidth = new_width;
+
+ // update proportional spacing
+ if (mColumn->mRelWidth > 0.f)
+ {
+ mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
+ }
+
+ // tell scroll list to layout columns again
+ mColumn->mParentCtrl->updateColumns();
+ }
+}
+
+void LLColumnHeader::setHasResizableElement(BOOL resizable)
+{
+ // for now, dynamically spaced columns can't be resized
+ if (mColumn->mDynamicWidth) return;
+
+ if (resizable != mHasResizableElement)
+ {
+ mHasResizableElement = resizable;
+
+ S32 num_resizable_columns = 0;
+ S32 col;
+ for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
+ {
+ LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
+ if (columnp->mHeader && columnp->mHeader->canResize())
+ {
+ num_resizable_columns++;
+ }
+ }
+
+ S32 num_resizers_enabled = 0;
+
+ // now enable/disable resize handles on resizable columns if we have at least two
+ for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
+ {
+ LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
+ if (!columnp->mHeader) continue;
+ BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
+ columnp->mHeader->enableResizeBar(enable);
+ if (enable)
+ {
+ num_resizers_enabled++;
+ }
+ }
+ }
+}
+
+void LLColumnHeader::enableResizeBar(BOOL enable)
+{
+ mResizeBar->setEnabled(enable);
+}
+
+BOOL LLColumnHeader::canResize()
+{
+ return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
+}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 9c16e4dff9..99218ab3c4 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -23,9 +23,12 @@
#include "llviewborder.h"
#include "llframetimer.h"
#include "llcheckboxctrl.h"
+#include "llcombobox.h"
class LLScrollbar;
class LLScrollListCtrl;
+class LLColumnHeader;
+class LLResizeBar;
class LLScrollListCell
{
@@ -39,6 +42,7 @@ public:
virtual const BOOL getVisible() const { return TRUE; }
virtual void setWidth(S32 width) = 0;
virtual void highlightText(S32 offset, S32 num_chars) {}
+ virtual BOOL isText() = 0;
virtual BOOL handleClick() { return FALSE; }
virtual void setEnabled(BOOL enable) { }
@@ -58,6 +62,7 @@ public:
virtual const BOOL getVisible() const { return mVisible; }
virtual void highlightText(S32 offset, S32 num_chars) {mHighlightOffset = offset; mHighlightCount = num_chars;}
void setText(const LLString& text);
+ virtual BOOL isText() { return TRUE; }
private:
LLUIString mText;
@@ -86,6 +91,7 @@ public:
virtual const LLString& getText() const { return mImageUUID; }
virtual const LLString& getTextLower() const { return mImageUUID; }
virtual void setWidth(S32 width) { mWidth = width; }
+ virtual BOOL isText() { return FALSE; }
private:
LLPointer<LLImageGL> mIcon;
@@ -107,6 +113,7 @@ public:
virtual void setEnabled(BOOL enable) { if (mCheckBox) mCheckBox->setEnabled(enable); }
LLCheckBoxCtrl* getCheckBox() { return mCheckBox; }
+ virtual BOOL isText() { return FALSE; }
private:
LLCheckBoxCtrl* mCheckBox;
@@ -117,14 +124,37 @@ class LLScrollListColumn
{
public:
// Default constructor
- LLScrollListColumn() : mName(""), mSortingColumn(""), mLabel(""), mWidth(-1), mRelWidth(-1.0), mDynamicWidth(FALSE), mIndex(-1), mParentCtrl(NULL), mButton(NULL), mFontAlignment(LLFontGL::LEFT)
+ LLScrollListColumn() :
+ mName(""),
+ mSortingColumn(""),
+ mLabel(""),
+ mWidth(-1),
+ mRelWidth(-1.0),
+ mDynamicWidth(FALSE),
+ mMaxContentWidth(0),
+ mIndex(-1),
+ mParentCtrl(NULL),
+ mHeader(NULL),
+ mFontAlignment(LLFontGL::LEFT)
{ }
- LLScrollListColumn(LLString name, LLString label, S32 width, F32 relwidth)
- : mName(name), mSortingColumn(name), mLabel(label), mWidth(width), mRelWidth(relwidth), mDynamicWidth(FALSE), mIndex(-1), mParentCtrl(NULL), mButton(NULL) { }
+ LLScrollListColumn(LLString name, LLString label, S32 width, F32 relwidth) :
+ mName(name),
+ mSortingColumn(name),
+ mLabel(label),
+ mWidth(width),
+ mRelWidth(relwidth),
+ mDynamicWidth(FALSE),
+ mMaxContentWidth(0),
+ mIndex(-1),
+ mParentCtrl(NULL),
+ mHeader(NULL)
+ { }
LLScrollListColumn(const LLSD &sd)
{
+ mMaxContentWidth = 0;
+
mName = sd.get("name").asString();
mSortingColumn = mName;
if (sd.has("sort"))
@@ -160,7 +190,7 @@ public:
mIndex = -1;
mParentCtrl = NULL;
- mButton = NULL;
+ mHeader = NULL;
}
LLString mName;
@@ -169,12 +199,47 @@ public:
S32 mWidth;
F32 mRelWidth;
BOOL mDynamicWidth;
+ S32 mMaxContentWidth;
S32 mIndex;
LLScrollListCtrl* mParentCtrl;
- LLButton* mButton;
+ LLColumnHeader* mHeader;
LLFontGL::HAlign mFontAlignment;
};
+class LLColumnHeader : public LLComboBox
+{
+public:
+ LLColumnHeader(const LLString& label, const LLRect &rect, LLScrollListColumn* column, const LLFontGL *font = NULL);
+ ~LLColumnHeader();
+
+ /*virtual*/ void draw();
+ /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+ /*virtual*/ void showList();
+ /*virtual*/ LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding);
+ /*virtual*/ void userSetShape(const LLRect& new_rect);
+
+ void setImage(const LLString &image_name);
+ LLScrollListColumn* getColumn() { return mColumn; }
+ void setHasResizableElement(BOOL resizable);
+ BOOL canResize();
+ void enableResizeBar(BOOL enable);
+ LLString getLabel() { return mOrigLabel; }
+
+ static void onSelectSort(LLUICtrl* ctrl, void* user_data);
+ static void onClick(void* user_data);
+ static void onMouseDown(void* user_data);
+ static void onHeldDown(void* user_data);
+
+protected:
+ LLScrollListColumn* mColumn;
+ LLResizeBar* mResizeBar;
+ LLString mOrigLabel;
+ LLUIString mAscendingText;
+ LLUIString mDescendingText;
+ BOOL mShowSortOptions;
+ BOOL mHasResizableElement;
+};
+
class LLScrollListItem
{
public:
@@ -216,7 +281,7 @@ public:
LLScrollListCell *getColumn(const S32 i) const { if (i < (S32)mColumns.size()) { return mColumns[i]; } return NULL; }
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual BOOL handleClick(S32 x, S32 y, MASK mask);
LLString getContentsCSV();
@@ -263,6 +328,10 @@ public:
virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM);
virtual void clearColumns();
virtual void setColumnLabel(const LLString& column, const LLString& label);
+
+ virtual LLScrollListColumn* getColumn(S32 index);
+ virtual S32 getNumColumns() const { return mColumnsIndexed.size(); }
+
// Adds a single element, from an array of:
// "columns" => [ "column" => column name, "value" => value, "type" => type, "font" => font, "font-style" => style ], "id" => uuid
// Creates missing columns automatically.
@@ -301,7 +370,8 @@ public:
BOOL selectFirstItem();
BOOL selectNthItem( S32 index );
-
+ BOOL selectItemAt(S32 x, S32 y, MASK mask);
+
void deleteSingleItem( S32 index ) ;
void deleteSelectedItems();
void deselectAllItems(BOOL no_commit_on_change = FALSE); // by default, go ahead and commit on selection change
@@ -338,23 +408,6 @@ public:
LLScrollListItem* addStringUUIDItem(const LLString& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE, S32 column_width = 0);
LLUUID getStringUUIDSelectedItem();
- // "Full" interface: use this when you're creating a list that has one or more of the following:
- // * contains icons
- // * contains multiple columns
- // * allows multiple selection
- // * has items that are not guarenteed to have unique names
- // * has additional per-item data (e.g. a UUID or void* userdata)
- //
- // To add items using this approach, create new LLScrollListItems and LLScrollListCells. Add the
- // cells (column entries) to each item, and add the item to the LLScrollListCtrl.
- //
- // The LLScrollListCtrl owns its items and is responsible for deleting them
- // (except in the case that the addItem() call fails, in which case it is up
- // to the caller to delete the item)
-
- // returns FALSE if item faile to be added to list, does NOT delete 'item'
- // TomY TODO - Deprecate this API and remove it
- BOOL addItem( LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM );
LLScrollListItem* getFirstSelected() const;
virtual S32 getFirstSelectedIndex();
std::vector<LLScrollListItem*> getAllSelected() const;
@@ -363,6 +416,7 @@ public:
// iterate over all items
LLScrollListItem* getFirstData() const;
+ LLScrollListItem* getLastData() const;
std::vector<LLScrollListItem*> getAllData() const;
void setAllowMultipleSelection(BOOL mult ) { mAllowMultipleSelection = mult; }
@@ -379,6 +433,7 @@ public:
void setBackgroundVisible(BOOL b) { mBackgroundVisible = b; }
void setDrawStripes(BOOL b) { mDrawStripes = b; }
void setColumnPadding(const S32 c) { mColumnPadding = c; }
+ S32 getColumnPadding() { return mColumnPadding; }
void setCommitOnKeyboardMovement(BOOL b) { mCommitOnKeyboardMovement = b; }
void setCommitOnSelectionChange(BOOL b) { mCommitOnSelectionChange = b; }
void setAllowKeyboardMovement(BOOL b) { mAllowKeyboardMovement = b; }
@@ -398,6 +453,7 @@ public:
// Overridden from LLView
virtual void draw();
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+ virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
@@ -405,6 +461,7 @@ public:
virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
virtual void setEnabled(BOOL enabled);
virtual void setFocus( BOOL b );
+ virtual void onFocusReceived();
virtual void onFocusLost();
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
@@ -412,17 +469,18 @@ public:
virtual LLRect getRequiredRect();
static BOOL rowPreceeds(LLScrollListItem *new_row, LLScrollListItem *test_row);
+ LLRect getItemListRect() { return mItemListRect; }
+
// Used "internally" by the scroll bar.
static void onScrollChange( S32 new_pos, LLScrollbar* src, void* userdata );
static void onClickColumn(void *userdata);
void updateColumns();
- void updateColumnButtons();
+ void updateMaxContentWidth(LLScrollListItem* changed_item);
void setDisplayHeading(BOOL display);
void setHeadingHeight(S32 heading_height);
- void setHeadingFont(const LLFontGL* heading_font);
void setCollapseEmptyColumns(BOOL collapse);
void setIsPopup(BOOL is_popup) { mIsPopup = is_popup; }
@@ -454,6 +512,22 @@ public:
S32 selectMultiple( LLDynamicArray<LLUUID> ids );
protected:
+ // "Full" interface: use this when you're creating a list that has one or more of the following:
+ // * contains icons
+ // * contains multiple columns
+ // * allows multiple selection
+ // * has items that are not guarenteed to have unique names
+ // * has additional per-item data (e.g. a UUID or void* userdata)
+ //
+ // To add items using this approach, create new LLScrollListItems and LLScrollListCells. Add the
+ // cells (column entries) to each item, and add the item to the LLScrollListCtrl.
+ //
+ // The LLScrollListCtrl owns its items and is responsible for deleting them
+ // (except in the case that the addItem() call fails, in which case it is up
+ // to the caller to delete the item)
+
+ // returns FALSE if item faile to be added to list, does NOT delete 'item'
+ BOOL addItem( LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM );
void selectPrevItem(BOOL extend_selection);
void selectNextItem(BOOL extend_selection);
void drawItems();
@@ -473,7 +547,6 @@ protected:
S32 mPageLines; // max number of lines is it possible to see on the screen given mRect and mLineHeight
S32 mHeadingHeight; // the height of the column header buttons, if visible
U32 mMaxSelectable;
- const LLFontGL* mHeadingFont; // the font to use for column head buttons, if visible
LLScrollbar* mScrollbar;
BOOL mAllowMultipleSelection;
BOOL mAllowKeyboardMovement;
@@ -481,7 +554,7 @@ protected:
BOOL mCommitOnSelectionChange;
BOOL mSelectionChanged;
BOOL mCanSelect;
- BOOL mDisplayColumnButtons;
+ BOOL mDisplayColumnHeaders;
BOOL mCollapseEmptyColumns;
BOOL mIsPopup;
@@ -525,8 +598,8 @@ protected:
S32 mNumDynamicWidthColumns;
S32 mTotalStaticColumnWidth;
- U32 mSortColumn;
- BOOL mSortAscending;
+ S32 mSortColumn;
+ BOOL mSortAscending;
std::map<LLString, LLScrollListColumn> mColumns;
std::vector<LLScrollListColumn*> mColumnsIndexed;
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index 2a1c2f7845..3a01013943 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -98,7 +98,7 @@ F32 LLSlider::getValueF32() const
BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
{
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
S32 left_edge = THUMB_WIDTH/2;
S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
@@ -125,9 +125,9 @@ BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
if( mMouseUpCallback )
{
@@ -175,7 +175,7 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
// Start dragging the thumb
// No handler needed for focus lost since this class has no state that depends on it.
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
mDragStartThumbRect = mThumbRect;
}
make_ui_sound("UISndClick");
@@ -242,12 +242,12 @@ void LLSlider::draw()
if (!thumb_imagep)
{
gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE);
- if (gFocusMgr.getMouseCapture() == this)
+ if (hasMouseCapture())
{
gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE);
}
}
- else if( gFocusMgr.getMouseCapture() == this )
+ else if( hasMouseCapture() )
{
gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(),
thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 3079726434..b3c49e81f1 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -186,7 +186,7 @@ void LLSliderCtrl::clear()
BOOL LLSliderCtrl::isMouseHeldDown()
{
- return gFocusMgr.getMouseCapture() == mSlider;
+ return mSlider->hasMouseCapture();
}
void LLSliderCtrl::updateText()
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 4c1700175b..fbd8335e6c 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -316,8 +316,8 @@ void LLSpinCtrl::setTentative(BOOL b)
BOOL LLSpinCtrl::isMouseHeldDown()
{
return
- gFocusMgr.getMouseCapture() == mDownBtn ||
- gFocusMgr.getMouseCapture() == mUpBtn;
+ mDownBtn->hasMouseCapture()
+ || mUpBtn->hasMouseCapture();
}
void LLSpinCtrl::onCommit()
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 1ba991f916..c412d77922 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -983,7 +983,7 @@ void LLTabContainer::updateMaxScrollPos()
void LLTabContainer::commitHoveredButton(S32 x, S32 y)
{
- if (gFocusMgr.getMouseCapture() == this)
+ if (hasMouseCapture())
{
for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
{
@@ -1244,7 +1244,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
if( tab_rect.pointInRect( x, y ) )
{
LLButton* tab_button = mTabList[getCurrentPanelIndex()]->mButton;
- gFocusMgr.setMouseCapture(this, NULL);
+ gFocusMgr.setMouseCapture(this);
gFocusMgr.setKeyboardFocus(tab_button, NULL);
}
}
@@ -1307,7 +1307,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
commitHoveredButton(x, y);
LLPanel* cur_panel = getCurrentPanel();
- if (gFocusMgr.getMouseCapture() == this)
+ if (hasMouseCapture())
{
if (cur_panel)
{
@@ -1318,7 +1318,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
mTabList[getCurrentPanelIndex()]->mButton->setFocus(TRUE);
}
}
- gFocusMgr.setMouseCapture(NULL, NULL);
+ gFocusMgr.setMouseCapture(NULL);
}
return handled;
}
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 0cd2e98514..f6f7067540 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -94,7 +94,7 @@ BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
handled = TRUE;
// Route future Mouse messages here preemptively. (Release on mouse up.)
- gFocusMgr.setMouseCapture( this, NULL );
+ gFocusMgr.setMouseCapture( this );
if (mSoundFlags & MOUSE_DOWN)
{
@@ -115,12 +115,12 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask)
// HACK: Only do this if there actually is a click callback, so that
// overly large text boxes in the older UI won't start eating clicks.
if (mClickedCallback
- && this == gFocusMgr.getMouseCapture())
+ && hasMouseCapture())
{
handled = TRUE;
// Release the mouse
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
if (mSoundFlags & MOUSE_UP)
{
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index de34aabb1f..366b1956c4 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -1182,7 +1182,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
setCursorAtLocalPos( x, y, TRUE );
startSelection();
}
- gFocusMgr.setMouseCapture( this, &LLTextEditor::onMouseCaptureLost );
+ gFocusMgr.setMouseCapture( this );
}
handled = TRUE;
@@ -1208,7 +1208,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
mHoverSegment = NULL;
if( getVisible() )
{
- if(gFocusMgr.getMouseCapture() == this )
+ if(hasMouseCapture() )
{
if( mIsSelecting )
{
@@ -1341,9 +1341,9 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
// Delay cursor flashing
mKeystrokeTimer.reset();
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
- gFocusMgr.setMouseCapture( NULL, NULL );
+ gFocusMgr.setMouseCapture( NULL );
handled = TRUE;
}
@@ -2454,6 +2454,8 @@ void LLTextEditor::onFocusLost()
// Make sure cursor is shown again
getWindow()->showCursorFromMouseMove();
+
+ LLUICtrl::onFocusLost();
}
void LLTextEditor::setEnabled(BOOL enabled)
@@ -3734,11 +3736,9 @@ S32 LLTextEditor::getSegmentIdxAtOffset(S32 offset)
}
}
-//static
-void LLTextEditor::onMouseCaptureLost( LLMouseHandler* old_captor )
+void LLTextEditor::onMouseCaptureLost()
{
- LLTextEditor* self = (LLTextEditor*) old_captor;
- self->endSelection();
+ endSelection();
}
void LLTextEditor::setOnScrollEndCallback(void (*callback)(void*), void* userdata)
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index ce85e35fe3..21db32b33f 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -75,6 +75,8 @@ public:
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type, void *cargo_data,
EAcceptance *accept, LLString& tooltip_msg);
+ virtual void onMouseCaptureLost();
+
// view overrides
virtual void reshape(S32 width, S32 height, BOOL called_from_parent);
@@ -190,7 +192,6 @@ public:
void setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; }
// Callbacks
- static void onMouseCaptureLost( LLMouseHandler* old_captor );
static void setLinkColor(LLColor4 color) { mLinkColor = color; }
static void setURLCallbacks( void (*callback1) (const char* url),
BOOL (*callback2) (LLString url) )
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index e8e3f271a0..f32266faa8 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1723,6 +1723,10 @@ LLString LLUI::locateSkin(const LLString& filename)
if (!gDirUtilp->fileExists(found_file))
{
LLString localization(sConfigGroup->getString("Language"));
+ if(localization == "default")
+ {
+ localization = sConfigGroup->getString("SystemLanguage");
+ }
LLString local_skin = "xui" + slash + localization + slash + filename;
found_file = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, local_skin);
}
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 0d9791c660..abf796fde0 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -26,6 +26,7 @@ const U32 MAX_STRING_LENGTH = 10;
LLUICtrl::LLUICtrl() :
mCommitCallback(NULL),
+ mFocusLostCallback(NULL),
mFocusReceivedCallback(NULL),
mFocusChangedCallback(NULL),
mValidateCallback(NULL),
@@ -44,6 +45,7 @@ LLUICtrl::LLUICtrl(const LLString& name, const LLRect& rect, BOOL mouse_opaque,
// of buttons in the UI. JC 7/20/2002
LLView( name, rect, mouse_opaque, reshape ),
mCommitCallback( on_commit_callback) ,
+ mFocusLostCallback( NULL ),
mFocusReceivedCallback( NULL ),
mFocusChangedCallback( NULL ),
mValidateCallback( NULL ),
@@ -57,6 +59,12 @@ LLUICtrl::LLUICtrl(const LLString& name, const LLRect& rect, BOOL mouse_opaque,
LLUICtrl::~LLUICtrl()
{
gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
+
+ if( gFocusMgr.getTopCtrl() == this )
+ {
+ llwarns << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << llendl;
+ gFocusMgr.removeTopCtrlWithoutCallback( this );
+ }
}
void LLUICtrl::onCommit()
@@ -151,6 +159,11 @@ void LLUICtrl::onFocusReceived()
void LLUICtrl::onFocusLost()
{
+ if( mFocusLostCallback )
+ {
+ mFocusLostCallback( this, mCallbackUserData );
+ }
+
if( mFocusChangedCallback )
{
mFocusChangedCallback( this, mCallbackUserData );
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 1418151201..1c2ac677df 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -104,6 +104,7 @@ public:
virtual void setMaxValue(LLSD max_value);
// In general, only LLPanel uses these.
+ void setFocusLostCallback(void (*cb)(LLUICtrl* caller, void* user_data)) { mFocusLostCallback = cb; }
void setFocusReceivedCallback( void (*cb)(LLUICtrl*, void*) ) { mFocusReceivedCallback = cb; }
void setFocusChangedCallback( void (*cb)(LLUICtrl*, void*) ) { mFocusChangedCallback = cb; }
@@ -135,6 +136,7 @@ protected:
protected:
void (*mCommitCallback)( LLUICtrl* ctrl, void* userdata );
+ void (*mFocusLostCallback)( LLUICtrl* caller, void* userdata );
void (*mFocusReceivedCallback)( LLUICtrl* ctrl, void* userdata );
void (*mFocusChangedCallback)( LLUICtrl* ctrl, void* userdata );
BOOL (*mValidateCallback)( LLUICtrl* ctrl, void* userdata );
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 21278455da..6410208189 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -222,6 +222,10 @@ void LLUICtrlFactory::setupPaths()
if (LLUI::sConfigGroup)
{
language = LLUI::sConfigGroup->getString("Language");
+ if(language == "default")
+ {
+ language = LLUI::sConfigGroup->getString("SystemLanguage");
+ }
}
path_val_ui.setArg("[Language]", language);
LLString fullpath = app_dir + path_val_ui.getString();
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 02a99b00cd..da5c77fc94 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -155,18 +155,12 @@ LLView::~LLView()
gFocusMgr.removeKeyboardFocusWithoutCallback( this );
}
- if( gFocusMgr.getMouseCapture() == this )
+ if( hasMouseCapture() )
{
llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl;
gFocusMgr.removeMouseCaptureWithoutCallback( this );
}
- if( gFocusMgr.getTopView() == this )
- {
- llwarns << "View holding top view deleted: " << getName() << ". Top view removed." << llendl;
- gFocusMgr.removeTopViewWithoutCallback( this );
- }
-
sViewHandleMap.erase(mViewHandle);
deleteAllChildren();
@@ -733,9 +727,9 @@ void LLView::setEnabled(BOOL enabled)
// virtual
void LLView::setVisible(BOOL visible)
{
- if( !visible && (gFocusMgr.getTopView() == this) )
+ if( !visible && (gFocusMgr.getTopCtrl() == this) )
{
- gFocusMgr.setTopView( NULL, NULL );
+ gFocusMgr.setTopCtrl( NULL );
}
if ( mVisible != visible )
@@ -1034,7 +1028,14 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
return handled_view;
}
+void LLView::onMouseCaptureLost()
+{
+}
+BOOL LLView::hasMouseCapture()
+{
+ return gFocusMgr.getMouseCapture() == this;
+}
BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
{
@@ -1591,6 +1592,13 @@ const LLRect LLView::getLocalRect() const
return local_rect;
}
+const LLRect LLView::getLocalSnapRect() const
+{
+ LLRect local_snap_rect = getSnapRect();
+ local_snap_rect.translate(-mRect.mLeft, -mRect.mBottom);
+ return local_snap_rect;
+}
+
void LLView::updateRect()
{
if (mSpanChildren && mChildList.size())
@@ -2087,6 +2095,12 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()
}
+void LLView::userSetShape(const LLRect& new_rect)
+{
+ reshape(new_rect.getWidth(), new_rect.getHeight());
+ translate(new_rect.mLeft - mRect.mLeft, new_rect.mBottom - mRect.mBottom);
+}
+
LLView* LLView::findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir,
LLView::ESnapType snap_type, S32 threshold, S32 padding)
{
@@ -2108,8 +2122,7 @@ LLView* LLView::findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir,
BOOL snapped_x = FALSE;
BOOL snapped_y = FALSE;
- LLRect parent_local_snap_rect = mParentView->getSnapRect();
- parent_local_snap_rect.translate(-mParentView->getRect().mLeft, -mParentView->getRect().mBottom);
+ LLRect parent_local_snap_rect = mParentView->getLocalSnapRect();
if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS)
{
@@ -2284,8 +2297,7 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna
BOOL snapped_x = FALSE;
BOOL snapped_y = FALSE;
- LLRect parent_local_snap_rect = mParentView->getSnapRect();
- parent_local_snap_rect.translate(-mParentView->getRect().mLeft, -mParentView->getRect().mBottom);
+ LLRect parent_local_snap_rect = mParentView->getLocalSnapRect();
if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS)
{
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index b794c087b5..504558a132 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -294,6 +294,7 @@ public:
const LLRect getScreenRect() const;
const LLRect getLocalRect() const;
virtual const LLRect getSnapRect() const { return mRect; }
+ virtual const LLRect getLocalSnapRect() const;
virtual LLRect getRequiredRect(); // Get required size for this object. 0 for width/height means don't care.
virtual void updateRect(); // apply procedural updates to own rectangle
@@ -315,12 +316,13 @@ public:
// Default behavior is to use reshape flags to resize child views
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-
virtual void translate( S32 x, S32 y );
virtual void setOrigin( S32 x, S32 y ) { mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); }
BOOL translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside );
- LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0);
- LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0);
+
+ virtual void userSetShape(const LLRect& new_rect);
+ virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0);
+ virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0);
// Defaults to other_view->getVisible()
virtual BOOL canSnapTo(LLView* other_view);
@@ -345,6 +347,8 @@ public:
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
+ /*virtual*/ void onMouseCaptureLost();
+ /*virtual*/ BOOL hasMouseCapture();
// Default behavior is to pass the tooltip event to children,
// then display mToolTipMsg if no child handled it.