summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llbutton.cpp277
-rw-r--r--indra/llui/llbutton.h68
-rw-r--r--indra/llui/llcheckboxctrl.cpp19
-rw-r--r--indra/llui/llcombobox.cpp476
-rw-r--r--indra/llui/llcombobox.h53
-rw-r--r--indra/llui/lldraghandle.h1
-rw-r--r--indra/llui/llfloater.cpp32
-rw-r--r--indra/llui/llfocusmgr.cpp41
-rw-r--r--indra/llui/llfocusmgr.h9
-rw-r--r--indra/llui/lliconctrl.cpp16
-rw-r--r--indra/llui/lliconctrl.h2
-rw-r--r--indra/llui/lllineeditor.cpp12
-rw-r--r--indra/llui/lllineeditor.h2
-rw-r--r--indra/llui/llmenugl.cpp3
-rw-r--r--indra/llui/llmodaldialog.cpp2
-rw-r--r--indra/llui/llpanel.cpp215
-rw-r--r--indra/llui/llpanel.h9
-rw-r--r--indra/llui/llresizehandle.cpp2
-rw-r--r--indra/llui/llscrollbar.cpp44
-rw-r--r--indra/llui/llscrollbar.h3
-rw-r--r--indra/llui/llscrollcontainer.cpp38
-rw-r--r--indra/llui/llscrolllistctrl.cpp787
-rw-r--r--indra/llui/llscrolllistctrl.h109
-rw-r--r--indra/llui/llslider.cpp145
-rw-r--r--indra/llui/llslider.h7
-rw-r--r--indra/llui/llsliderctrl.cpp4
-rw-r--r--indra/llui/llsliderctrl.h2
-rw-r--r--indra/llui/llspinctrl.cpp6
-rw-r--r--indra/llui/llspinctrl.h2
-rw-r--r--indra/llui/llstyle.cpp2
-rw-r--r--indra/llui/lltabcontainer.cpp39
-rw-r--r--indra/llui/lltabcontainer.h3
-rw-r--r--indra/llui/lltextbox.cpp8
-rw-r--r--indra/llui/lltextbox.h2
-rw-r--r--indra/llui/lltexteditor.cpp92
-rw-r--r--indra/llui/lltexteditor.h13
-rw-r--r--indra/llui/llui.cpp429
-rw-r--r--indra/llui/llui.h82
-rw-r--r--indra/llui/lluictrl.cpp194
-rw-r--r--indra/llui/lluictrl.h55
-rw-r--r--indra/llui/lluictrlfactory.cpp7
-rw-r--r--indra/llui/llview.cpp436
-rw-r--r--indra/llui/llview.h32
-rw-r--r--indra/llui/llviewborder.cpp2
-rw-r--r--indra/llui/llviewquery.cpp61
-rw-r--r--indra/llui/llviewquery.h32
46 files changed, 2369 insertions, 1506 deletions
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 26ce473e08..ce3a4b64c7 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -59,9 +59,6 @@ S32 BTN_HEIGHT = 0;
S32 BTN_GRID = 12;
S32 BORDER_SIZE = 1;
-// static
-LLFrameTimer LLButton::sFlashingTimer;
-
LLButton::LLButton( const LLString& name, const LLRect& rect, const LLString& control_name, void (*click_callback)(void*), void *callback_data)
: LLUICtrl(name, rect, TRUE, NULL, NULL),
mClickedCallback( click_callback ),
@@ -79,6 +76,7 @@ LLButton::LLButton( const LLString& name, const LLRect& rect, const LLString& co
mImageDisabled( NULL ),
mImageDisabledSelected( NULL ),
mToggleState( FALSE ),
+ mIsToggle( FALSE ),
mScaleImage( TRUE ),
mDropShadowedText( TRUE ),
mBorderEnabled( FALSE ),
@@ -86,8 +84,6 @@ LLButton::LLButton( const LLString& name, const LLRect& rect, const LLString& co
mHAlign( LLFontGL::HCENTER ),
mLeftHPad( LLBUTTON_H_PAD ),
mRightHPad( LLBUTTON_H_PAD ),
- mFixedWidth( 16 ),
- mFixedHeight( 16 ),
mHoverGlowStrength(0.15f),
mCurGlowStrength(0.f),
mNeedsHighlight(FALSE),
@@ -134,6 +130,7 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
mImageDisabled( NULL ),
mImageDisabledSelected( NULL ),
mToggleState( FALSE ),
+ mIsToggle( FALSE ),
mScaleImage( TRUE ),
mDropShadowedText( TRUE ),
mBorderEnabled( FALSE ),
@@ -141,8 +138,6 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
mHAlign( LLFontGL::HCENTER ),
mLeftHPad( LLBUTTON_H_PAD ),
mRightHPad( LLBUTTON_H_PAD ),
- mFixedWidth( 16 ),
- mFixedHeight( 16 ),
mHoverGlowStrength(0.25f),
mCurGlowStrength(0.f),
mNeedsHighlight(FALSE),
@@ -158,15 +153,11 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
if( unselected_image_name != "" )
{
+ // user-specified image - don't use fixed borders unless requested
setImageUnselected(unselected_image_name);
setImageDisabled(unselected_image_name);
mDisabledImageColor.mV[VALPHA] = 0.5f;
- mImageDisabled = mImageUnselected;
- mDisabledImageColor.mV[VALPHA] = 0.5f;
- // user-specified image - don't use fixed borders unless requested
- mFixedWidth = 0;
- mFixedHeight = 0;
mScaleImage = FALSE;
}
else
@@ -177,13 +168,11 @@ LLButton::LLButton(const LLString& name, const LLRect& rect,
if( selected_image_name != "" )
{
+ // user-specified image - don't use fixed borders unless requested
setImageSelected(selected_image_name);
setImageDisabledSelected(selected_image_name);
mDisabledImageColor.mV[VALPHA] = 0.5f;
- // user-specified image - don't use fixed borders unless requested
- mFixedWidth = 0;
- mFixedHeight = 0;
mScaleImage = FALSE;
}
else
@@ -273,6 +262,12 @@ void LLButton::onCommit()
make_ui_sound("UISndClickRelease");
}
+ if (mIsToggle)
+ {
+ toggleState();
+ }
+
+ // do this last, as it can result in destroying this button
if (mClickedCallback)
{
(*mClickedCallback)( mCallbackUserData );
@@ -286,6 +281,11 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
BOOL handled = FALSE;
if( getVisible() && mEnabled && !called_from_parent && ' ' == uni_char && !gKeyboard->getKeyRepeated(' '))
{
+ if (mIsToggle)
+ {
+ toggleState();
+ }
+
if (mClickedCallback)
{
(*mClickedCallback)( mCallbackUserData );
@@ -302,11 +302,17 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent )
{
if( mCommitOnReturn && KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
{
+ if (mIsToggle)
+ {
+ toggleState();
+ }
+
+ handled = TRUE;
+
if (mClickedCallback)
{
(*mClickedCallback)( mCallbackUserData );
}
- handled = TRUE;
}
}
return handled;
@@ -354,6 +360,9 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
(*mMouseUpCallback)(mCallbackUserData);
}
+ mMouseDownTimer.stop();
+ mMouseDownTimer.reset();
+
// 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))
@@ -363,6 +372,11 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
make_ui_sound("UISndClickRelease");
}
+ if (mIsToggle)
+ {
+ toggleState();
+ }
+
if (mClickedCallback)
{
(*mClickedCallback)( mCallbackUserData );
@@ -422,8 +436,10 @@ void LLButton::draw()
BOOL flash = FALSE;
if( mFlashing )
{
- F32 elapsed = LLButton::sFlashingTimer.getElapsedTimeF32();
- flash = S32(elapsed * 2) & 1;
+ F32 elapsed = mFlashingTimer.getElapsedTimeF32();
+ S32 flash_count = S32(elapsed * LLUI::sConfigGroup->getF32("ButtonFlashRate") * 2.f);
+ // flash on or off?
+ flash = (flash_count % 2 == 0) || flash_count > (F32)LLUI::sConfigGroup->getS32("ButtonFlashCount");
}
BOOL pressed_by_keyboard = FALSE;
@@ -443,24 +459,14 @@ 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 || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y));
-
- BOOL display_state = FALSE;
- if( pressed )
- {
- mImagep = mImageSelected;
- // show the resulting state after releasing the mouse button while it is down
- display_state = mToggleState ? FALSE : TRUE;
- }
- else
- {
- display_state = mToggleState || flash;
- }
+ BOOL pressed = pressed_by_keyboard
+ || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y))
+ || mToggleState;
BOOL use_glow_effect = FALSE;
- if ( mNeedsHighlight )
+ if ( mNeedsHighlight || flash )
{
- if (display_state)
+ if (pressed)
{
if (mImageHoverSelected)
{
@@ -485,7 +491,7 @@ void LLButton::draw()
}
}
}
- else if ( display_state )
+ else if ( pressed )
{
mImagep = mImageSelected;
}
@@ -499,11 +505,11 @@ void LLButton::draw()
// enabled and tentative
// or
// disabled but checked
- if (!mImageDisabledSelected.isNull() && ( (mEnabled && mTentative) || (!mEnabled && display_state ) ) )
+ if (!mImageDisabledSelected.isNull() && ( (mEnabled && mTentative) || (!mEnabled && pressed ) ) )
{
mImagep = mImageDisabledSelected;
}
- else if (!mImageDisabled.isNull() && !mEnabled && !display_state)
+ else if (!mImageDisabled.isNull() && !mEnabled && !pressed)
{
mImagep = mImageDisabled;
}
@@ -516,33 +522,34 @@ void LLButton::draw()
// Figure out appropriate color for the text
LLColor4 label_color;
+ // label changes when button state changes, not when pressed
if ( mEnabled )
{
- if ( !display_state )
+ if ( mToggleState )
{
- label_color = mUnselectedLabelColor;
+ label_color = mSelectedLabelColor;
}
else
{
- label_color = mSelectedLabelColor;
+ label_color = mUnselectedLabelColor;
}
}
else
{
- if ( !display_state )
+ if ( mToggleState )
{
- label_color = mDisabledLabelColor;
+ label_color = mDisabledSelectedLabelColor;
}
else
{
- label_color = mDisabledSelectedLabelColor;
+ label_color = mDisabledLabelColor;
}
}
// Unselected label assignments
LLWString label;
- if( display_state )
+ if( mToggleState )
{
if( mEnabled || mDisabledSelectedLabel.empty() )
{
@@ -591,24 +598,22 @@ void LLButton::draw()
// Otherwise draw basic rectangular button.
if( mImagep.notNull() && !mScaleImage)
{
- gl_draw_image( 0, 0, mImagep, mEnabled ? mImageColor : mDisabledImageColor );
+ mImagep->draw(0, 0, mEnabled ? mImageColor : mDisabledImageColor );
if (mCurGlowStrength > 0.01f)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- gl_draw_scaled_image_with_border(0, 0, 0, 0, mImagep->getWidth(), mImagep->getHeight(), mImagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
+ mImagep->drawSolid(0, 0, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
else
if ( mImagep.notNull() && mScaleImage)
{
- gl_draw_scaled_image_with_border(0, 0, mFixedWidth, mFixedHeight, mRect.getWidth(), mRect.getHeight(),
- mImagep, mEnabled ? mImageColor : mDisabledImageColor );
+ mImagep->draw(0, 0, mRect.getWidth(), mRect.getHeight(), mEnabled ? mImageColor : mDisabledImageColor );
if (mCurGlowStrength > 0.01f)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- gl_draw_scaled_image_with_border(0, 0, mFixedWidth, mFixedHeight, mRect.getWidth(), mRect.getHeight(),
- mImagep, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength), TRUE);
+ mImagep->drawSolid(0, 0, mRect.getWidth(), mRect.getHeight(), LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -620,13 +625,17 @@ void LLButton::draw()
gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE);
}
+ // let overlay image and text play well together
+ S32 text_left = mLeftHPad;
+ S32 text_right = mRect.getWidth() - mRightHPad;
+ S32 text_width = mRect.getWidth() - mLeftHPad - mRightHPad;
+
// draw overlay image
if (mImageOverlay.notNull())
{
- const S32 IMG_PAD = 5;
// get max width and height (discard level 0)
- S32 overlay_width = mImageOverlay->getWidth(0);
- S32 overlay_height = mImageOverlay->getHeight(0);
+ S32 overlay_width = mImageOverlay->getWidth();
+ S32 overlay_height = mImageOverlay->getHeight();
F32 scale_factor = llmin((F32)mRect.getWidth() / (F32)overlay_width, (F32)mRect.getHeight() / (F32)overlay_height, 1.f);
overlay_width = llround((F32)overlay_width * scale_factor);
@@ -635,34 +644,49 @@ void LLButton::draw()
S32 center_x = getLocalRect().getCenterX();
S32 center_y = getLocalRect().getCenterY();
+ //FUGLY HACK FOR "DEPRESSED" BUTTONS
+ if (pressed)
+ {
+ center_y--;
+ center_x++;
+ }
+
+ // fade out overlay images on disabled buttons
+ LLColor4 overlay_color = mImageOverlayColor;
+ if (!getEnabled())
+ {
+ overlay_color.mV[VALPHA] = 0.5f;
+ }
+
switch(mImageOverlayAlignment)
{
case LLFontGL::LEFT:
- gl_draw_scaled_image(
- IMG_PAD,
+ text_left += overlay_width + 1;
+ text_width -= overlay_width + 1;
+ mImageOverlay->draw(
+ mLeftHPad,
center_y - (overlay_height / 2),
overlay_width,
overlay_height,
- mImageOverlay,
- mImageOverlayColor);
+ overlay_color);
break;
case LLFontGL::HCENTER:
- gl_draw_scaled_image(
+ mImageOverlay->draw(
center_x - (overlay_width / 2),
center_y - (overlay_height / 2),
overlay_width,
overlay_height,
- mImageOverlay,
- mImageOverlayColor);
+ overlay_color);
break;
case LLFontGL::RIGHT:
- gl_draw_scaled_image(
- mRect.getWidth() - IMG_PAD - overlay_width,
+ text_right -= overlay_width + 1;
+ text_width -= overlay_width + 1;
+ mImageOverlay->draw(
+ mRect.getWidth() - mRightHPad - overlay_width,
center_y - (overlay_height / 2),
overlay_width,
overlay_height,
- mImageOverlay,
- mImageOverlayColor);
+ overlay_color);
break;
default:
// draw nothing
@@ -673,28 +697,26 @@ void LLButton::draw()
// Draw label
if( !label.empty() )
{
- S32 drawable_width = mRect.getWidth() - mLeftHPad - mRightHPad;
-
LLWString::trim(label);
S32 x;
switch( mHAlign )
{
case LLFontGL::RIGHT:
- x = mRect.getWidth() - mRightHPad;
+ x = text_right;
break;
case LLFontGL::HCENTER:
x = mRect.getWidth() / 2;
break;
case LLFontGL::LEFT:
default:
- x = mLeftHPad;
+ x = text_left;
break;
}
S32 y_offset = 2 + (mRect.getHeight() - 20)/2;
- if (pressed || display_state)
+ if (pressed)
{
y_offset--;
x++;
@@ -704,7 +726,7 @@ void LLButton::draw()
label_color,
mHAlign, LLFontGL::BOTTOM,
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL,
- U32_MAX, drawable_width,
+ U32_MAX, text_width,
NULL, FALSE, FALSE);
}
@@ -733,13 +755,11 @@ void LLButton::drawBorder(const LLColor4& color, S32 size)
if (mScaleImage)
{
- gl_draw_scaled_image_with_border(left, bottom, mFixedWidth, mFixedHeight, right-left, top-bottom,
- mImagep, color, TRUE );
+ mImagep->drawSolid(left, bottom, right-left, top-bottom, color);
}
else
{
- gl_draw_scaled_image_with_border(left, bottom, 0, 0, mImagep->getWidth() + size * 2,
- mImagep->getHeight() + size * 2, mImagep, color, TRUE );
+ mImagep->drawSolid(left, bottom, mImagep->getWidth() + size * 2, mImagep->getHeight() + size * 2, color);
}
}
@@ -763,6 +783,22 @@ void LLButton::setToggleState(BOOL b)
}
}
+void LLButton::setFlashing( BOOL b )
+{
+ if (b != mFlashing)
+ {
+ mFlashing = b;
+ mFlashingTimer.reset();
+ }
+}
+
+
+BOOL LLButton::toggleState()
+{
+ setToggleState( !mToggleState );
+ return mToggleState;
+}
+
void LLButton::setValue(const LLSD& value )
{
mToggleState = value.asBoolean();
@@ -770,7 +806,7 @@ void LLButton::setValue(const LLSD& value )
LLSD LLButton::getValue() const
{
- return mToggleState;
+ return mToggleState == TRUE;
}
void LLButton::setLabel( const LLStringExplicit& label )
@@ -807,10 +843,9 @@ void LLButton::setDisabledSelectedLabel( const LLStringExplicit& label )
mDisabledSelectedLabel = label;
}
-void LLButton::setImageUnselectedID( const LLUUID &image_id )
-{
- mImageUnselectedName = "";
- mImageUnselected = LLUI::sImageProvider->getUIImageByID(image_id);
+void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
+{
+ mImageUnselected = image;
}
void LLButton::setImages( const LLString &image_name, const LLString &selected_name )
@@ -820,10 +855,9 @@ void LLButton::setImages( const LLString &image_name, const LLString &selected_n
}
-void LLButton::setImageSelectedID( const LLUUID &image_id )
+void LLButton::setImageSelected(LLPointer<LLUIImage> image)
{
- mImageSelectedName = "";
- mImageSelected = LLUI::sImageProvider->getUIImageByID(image_id);
+ mImageSelected = image;
}
void LLButton::setImageColor(const LLColor4& c)
@@ -831,19 +865,22 @@ void LLButton::setImageColor(const LLColor4& c)
mImageColor = c;
}
+void LLButton::setColor(const LLColor4& color)
+{
+ setImageColor(color);
+}
+
-void LLButton::setImageDisabledID( const LLUUID &image_id )
+void LLButton::setImageDisabled(LLPointer<LLUIImage> image)
{
- mImageDisabledName = "";
- mImageDisabled = LLUI::sImageProvider->getUIImageByID(image_id);
+ mImageDisabled = image;
mDisabledImageColor = mImageColor;
mDisabledImageColor.mV[VALPHA] *= 0.5f;
}
-void LLButton::setImageDisabledSelectedID( const LLUUID &image_id )
-{
- mImageDisabledSelectedName = "";
- mImageDisabledSelected = LLUI::sImageProvider->getUIImageByID(image_id);
+void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
+{
+ mImageDisabledSelected = image;
mDisabledImageColor = mImageColor;
mDisabledImageColor.mV[VALPHA] *= 0.5f;
}
@@ -855,11 +892,9 @@ void LLButton::setDisabledImages( const LLString &image_name, const LLString &se
mDisabledImageColor = c;
}
-
-void LLButton::setImageHoverSelectedID( const LLUUID& image_id )
+void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
{
- mImageHoverSelectedName = "";
- mImageHoverSelected = LLUI::sImageProvider->getUIImageByID(image_id);
+ mImageHoverSelected = image;
}
void LLButton::setDisabledImages( const LLString &image_name, const LLString &selected_name)
@@ -869,10 +904,9 @@ void LLButton::setDisabledImages( const LLString &image_name, const LLString &se
setDisabledImages( image_name, selected_name, clr );
}
-void LLButton::setImageHoverUnselectedID( const LLUUID& image_id )
+void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image)
{
- mImageHoverUnselectedName = "";
- mImageHoverUnselected = LLUI::sImageProvider->getUIImageByID(image_id);
+ mImageHoverUnselected = image;
}
void LLButton::setHoverImages( const LLString& image_name, const LLString& selected_name )
@@ -889,8 +923,7 @@ void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alig
}
else
{
- LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name);
- mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id);
+ mImageOverlay = LLUI::getUIImageByName(image_name);
mImageOverlayAlignment = alignment;
mImageOverlayColor = color;
}
@@ -904,34 +937,6 @@ void LLButton::onMouseCaptureLost()
}
//-------------------------------------------------------------------------
-// LLSquareButton
-//-------------------------------------------------------------------------
-LLSquareButton::LLSquareButton(const LLString& name, const LLRect& rect,
- const LLString& label,
- const LLFontGL *font,
- const LLString& control_name,
- void (*click_callback)(void*),
- void *callback_data,
- const LLString& selected_label )
-: LLButton(name, rect, "","",
- control_name,
- click_callback, callback_data,
- font,
- label,
- (selected_label.empty() ? label : selected_label) )
-{
- setImageUnselected("square_btn_32x128.tga");
- // mImageUnselected = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_32x128.tga")));
- setImageSelected("square_btn_selected_32x128.tga");
- // mImageSelectedImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_selected_32x128.tga")));
- setImageDisabled("square_btn_32x128.tga");
- //mDisabledImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_32x128.tga")));
- setImageDisabledSelected("square_btn_selected_32x128.tga");
- //mDisabledSelectedImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("square_btn_selected_32x128.tga")));
- mImageColor = LLUI::sColorsGroup->getColor("ButtonColor");
-}
-
-//-------------------------------------------------------------------------
// Utilities
//-------------------------------------------------------------------------
S32 round_up(S32 grid, S32 value)
@@ -951,37 +956,37 @@ S32 round_up(S32 grid, S32 value)
void LLButton::setImageUnselected(const LLString &image_name)
{
- setImageUnselectedID(LLUI::findAssetUUIDByName(image_name));
+ setImageUnselected(LLUI::getUIImageByName(image_name));
mImageUnselectedName = image_name;
}
void LLButton::setImageSelected(const LLString &image_name)
{
- setImageSelectedID(LLUI::findAssetUUIDByName(image_name));
+ setImageSelected(LLUI::getUIImageByName(image_name));
mImageSelectedName = image_name;
}
void LLButton::setImageHoverSelected(const LLString &image_name)
{
- setImageHoverSelectedID(LLUI::findAssetUUIDByName(image_name));
+ setImageHoverSelected(LLUI::getUIImageByName(image_name));
mImageHoverSelectedName = image_name;
}
void LLButton::setImageHoverUnselected(const LLString &image_name)
{
- setImageHoverUnselectedID(LLUI::findAssetUUIDByName(image_name));
+ setImageHoverUnselected(LLUI::getUIImageByName(image_name));
mImageHoverUnselectedName = image_name;
}
void LLButton::setImageDisabled(const LLString &image_name)
{
- setImageDisabledID(LLUI::findAssetUUIDByName(image_name));
+ setImageDisabled(LLUI::getUIImageByName(image_name));
mImageDisabledName = image_name;
}
void LLButton::setImageDisabledSelected(const LLString &image_name)
{
- setImageDisabledSelectedID(LLUI::findAssetUUIDByName(image_name));
+ setImageDisabledSelected(LLUI::getUIImageByName(image_name));
mImageDisabledSelectedName = image_name;
}
@@ -1009,8 +1014,6 @@ LLXMLNodePtr LLButton::getXML(bool save_children) const
node->createChild("label_selected", TRUE)->setStringValue(getLabelSelected());
node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont));
node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
- node->createChild("border_width", TRUE)->setIntValue(mFixedWidth);
- node->createChild("border_height", TRUE)->setIntValue(mFixedHeight);
addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,"image_unselected");
addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,"image_selected");
@@ -1092,8 +1095,12 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
label,
label_selected);
- node->getAttributeS32("border_width", button->mFixedWidth);
- node->getAttributeS32("border_height", button->mFixedHeight);
+ node->getAttributeS32("pad_right", button->mRightHPad);
+ node->getAttributeS32("pad_left", button->mLeftHPad);
+
+ BOOL is_toggle = button->getIsToggle();
+ node->getAttributeBOOL("toggle", is_toggle);
+ button->setIsToggle(is_toggle);
if(image_hover_selected != LLString::null) button->setImageHoverSelected(image_hover_selected);
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 5f7d917b4e..0e140a45a6 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -114,11 +114,13 @@ public:
F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); }
- BOOL toggleState() { setToggleState( !mToggleState ); return mToggleState; }
+ BOOL getIsToggle() const { return mIsToggle; }
+ void setIsToggle(BOOL is_toggle) { mIsToggle = is_toggle; }
+ BOOL toggleState();
BOOL getToggleState() const { return mToggleState; }
void setToggleState(BOOL b);
- void setFlashing( BOOL b ) { mFlashing = b; }
+ void setFlashing( BOOL b );
BOOL getFlashing() const { return mFlashing; }
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
@@ -128,14 +130,11 @@ public:
const LLString getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); }
const LLString getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); }
-
- // HACK to allow images to be freed when the caller knows he's done with it.
- LLImageGL* getImageUnselected() const { return mImageUnselected; }
-
void setImageColor(const LLString& color_control);
- void setImages(const LLString &image_name, const LLString &selected_name);
void setImageColor(const LLColor4& c);
-
+ virtual void setColor(const LLColor4& c);
+
+ void setImages(const LLString &image_name, const LLString &selected_name);
void setDisabledImages(const LLString &image_name, const LLString &selected_name);
void setDisabledImages(const LLString &image_name, const LLString &selected_name, const LLColor4& c);
@@ -146,7 +145,7 @@ public:
void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; }
void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
- LLPointer<LLImageGL> getImageOverlay() { return mImageOverlay; }
+ LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; }
virtual void setValue(const LLSD& value );
@@ -170,16 +169,8 @@ public:
static void onHeldDown(void *userdata); // to be called by gIdleCallbacks
- void setFixedBorder(S32 width, S32 height) { mFixedWidth = width; mFixedHeight = height; }
void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
-private:
- void setImageUnselectedID(const LLUUID &image_id);
- void setImageSelectedID(const LLUUID &image_id);
- void setImageHoverSelectedID(const LLUUID &image_id);
- void setImageHoverUnselectedID(const LLUUID &image_id);
- void setImageDisabledID(const LLUUID &image_id);
- void setImageDisabledSelectedID(const LLUUID &image_id);
public:
void setImageUnselected(const LLString &image_name);
void setImageSelected(const LLString &image_name);
@@ -187,6 +178,14 @@ public:
void setImageHoverUnselected(const LLString &image_name);
void setImageDisabled(const LLString &image_name);
void setImageDisabledSelected(const LLString &image_name);
+
+ void setImageUnselected(LLPointer<LLUIImage> image);
+ void setImageSelected(LLPointer<LLUIImage> image);
+ void setImageHoverSelected(LLPointer<LLUIImage> image);
+ void setImageHoverUnselected(LLPointer<LLUIImage> image);
+ void setImageDisabled(LLPointer<LLUIImage> image);
+ void setImageDisabledSelected(LLPointer<LLUIImage> image);
+
void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
BOOL getCommitOnReturn() { return mCommitOnReturn; }
@@ -209,27 +208,27 @@ protected:
F32 mHeldDownDelay; // seconds, after which held-down callbacks get called
S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called
- LLPointer<LLImageGL> mImageOverlay;
+ LLPointer<LLUIImage> mImageOverlay;
LLFontGL::HAlign mImageOverlayAlignment;
LLColor4 mImageOverlayColor;
- LLPointer<LLImageGL> mImageUnselected;
+ LLPointer<LLUIImage> mImageUnselected;
LLUIString mUnselectedLabel;
LLColor4 mUnselectedLabelColor;
- LLPointer<LLImageGL> mImageSelected;
+ LLPointer<LLUIImage> mImageSelected;
LLUIString mSelectedLabel;
LLColor4 mSelectedLabelColor;
- LLPointer<LLImageGL> mImageHoverSelected;
+ LLPointer<LLUIImage> mImageHoverSelected;
- LLPointer<LLImageGL> mImageHoverUnselected;
+ LLPointer<LLUIImage> mImageHoverUnselected;
- LLPointer<LLImageGL> mImageDisabled;
+ LLPointer<LLUIImage> mImageDisabled;
LLUIString mDisabledLabel;
LLColor4 mDisabledLabelColor;
- LLPointer<LLImageGL> mImageDisabledSelected;
+ LLPointer<LLUIImage> mImageDisabledSelected;
LLUIString mDisabledSelectedLabel;
LLColor4 mDisabledSelectedLabelColor;
@@ -254,6 +253,7 @@ protected:
LLColor4 mImageColor;
LLColor4 mDisabledImageColor;
+ BOOL mIsToggle;
BOOL mToggleState;
BOOL mScaleImage;
@@ -267,9 +267,6 @@ protected:
S32 mLeftHPad;
S32 mRightHPad;
- S32 mFixedWidth;
- S32 mFixedHeight;
-
F32 mHoverGlowStrength;
F32 mCurGlowStrength;
@@ -278,22 +275,9 @@ protected:
LLString mHelpURL;
- LLPointer<LLImageGL> mImagep;
-
- static LLFrameTimer sFlashingTimer;
-};
+ LLPointer<LLUIImage> mImagep;
-class LLSquareButton
-: public LLButton
-{
-public:
- LLSquareButton(const LLString& name, const LLRect& rect,
- const LLString& label,
- const LLFontGL *font = NULL,
- const LLString& control_name = LLString(),
- void (*click_callback)(void*) = NULL,
- void *callback_data = NULL,
- const LLString& selected_label = LLString::null );
+ LLFrameTimer mFlashingTimer;
};
// Helpful functions
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 504b342003..b0a7e9d27f 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -75,7 +75,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLString& name, const LLRect& rect,
}
// must be big enough to hold all children
- setSpanChildren(TRUE);
+ setUseBoundingRect(TRUE);
mKeyboardFocusOnClick = TRUE;
@@ -130,6 +130,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLString& name, const LLRect& rect,
mButton->setDisabledImages( inactive_false_id, inactive_true_id );
mButton->setHoverGlowStrength(0.35f);
}
+ mButton->setIsToggle(TRUE);
mButton->setToggleState( initial_value );
mButton->setFollowsLeft();
mButton->setFollowsBottom();
@@ -150,16 +151,11 @@ void LLCheckBoxCtrl::onButtonPress( void *userdata )
if (self->mRadioStyle)
{
- if (!self->getValue())
- {
- self->setValue(TRUE);
- }
- }
- else
- {
- self->toggle();
+ self->setValue(TRUE);
}
+
self->setControlValue(self->getValue());
+ // HACK: because buttons don't normally commit
self->onCommit();
if (self->mKeyboardFocusOnClick)
@@ -232,14 +228,13 @@ void LLCheckBoxCtrl::draw()
//virtual
void LLCheckBoxCtrl::setValue(const LLSD& value )
{
- mSetValue = value.asBoolean();
- mButton->setToggleState( mSetValue );
+ mButton->setValue( value );
}
//virtual
LLSD LLCheckBoxCtrl::getValue() const
{
- return mButton->getToggleState();
+ return mButton->getValue();
}
void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label )
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 5f76cfc94b..6063fc155a 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -55,17 +55,16 @@
// Globals
S32 LLCOMBOBOX_HEIGHT = 0;
S32 LLCOMBOBOX_WIDTH = 0;
-
+S32 MAX_COMBO_WIDTH = 500;
+
LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label,
void (*commit_callback)(LLUICtrl*,void*),
void *callback_userdata
)
: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata,
FOLLOWS_LEFT | FOLLOWS_TOP),
- mDrawArrow(TRUE),
mTextEntry(NULL),
mArrowImage(NULL),
- mArrowImageWidth(8),
mAllowTextEntry(FALSE),
mMaxChars(20),
mTextEntryTentative(TRUE),
@@ -73,55 +72,43 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
mPrearrangeCallback( NULL ),
mTextEntryCallback( NULL )
{
- // For now, all comboboxes don't take keyboard focus when clicked.
- // This might change if it is part of a modal dialog.
- // mKeyboardFocusOnClick = FALSE;
-
- // 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 TopCtrl. When keyboard focus is cleared all
- // controls (including this one) know that they are no longer editing.
- mKeyboardFocusOnClick = TRUE;
-
- LLRect r;
- r.setOriginAndSize(0, 0, rect.getWidth(), rect.getHeight());
-
// Always use text box
// Text label button
- mButton = new LLSquareButton("comboxbox button",
- r, label, NULL, LLString::null,
+ mButton = new LLButton("comboxbox button",
+ LLRect(), label, NULL, LLString::null,
NULL, this);
+ mButton->setImageUnselected("square_btn_32x128.tga");
+ mButton->setImageSelected("square_btn_selected_32x128.tga");
+ mButton->setImageDisabled("square_btn_32x128.tga");
+ mButton->setImageDisabledSelected("square_btn_selected_32x128.tga");
+ mButton->setScaleImage(TRUE);
+
mButton->setMouseDownCallback(onButtonDown);
mButton->setFont(LLFontGL::sSansSerifSmall);
mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
mButton->setHAlign( LLFontGL::LEFT );
-
- const S32 ARROW_WIDTH = 16;
- mButton->setRightHPad( ARROW_WIDTH );
+ mButton->setRightHPad(2);
addChild(mButton);
- // Default size, will be set by arrange() call in button callback.
- S32 list_width = mRect.getWidth() + SCROLLBAR_SIZE;
- r.setOriginAndSize(0, 16, list_width, 220);
-
// disallow multiple selection
mList = new LLScrollListCtrl(
- "ComboBox", r,
+ "ComboBox", LLRect(),
&LLComboBox::onItemSelected, this, FALSE);
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);
mBorder = new LLViewBorder( "combo border", border_rect );
addChild( mBorder );
- mBorder->setFollows(FOLLOWS_LEFT|FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
+ mBorder->setFollowsAll();
LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") );
- mArrowImage = LLUI::sImageProvider->getUIImageByID(arrow_image_id);
- mArrowImageWidth = llmax(8,mArrowImage->getWidth(0)); // In case image hasn't loaded yet
+ mArrowImage = LLUI::sImageProvider->getImageByID(arrow_image_id);
+ mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT);
+
+ updateLayout();
}
@@ -155,7 +142,7 @@ LLXMLNodePtr LLComboBox::getXML(bool save_children) const
LLSD value = item->getValue();
item_node->createChild("value", TRUE)->setStringValue(value.asString());
item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
- item_node->setStringValue(cell->getText());
+ item_node->setStringValue(cell->getValue().asString());
}
}
@@ -272,34 +259,42 @@ void LLComboBox::resetDirty()
// add item "name" to menu
-void LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
+LLScrollListItem* LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
{
- mList->addSimpleItem(name, pos, enabled);
+ LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled);
mList->selectFirstItem();
+ return item;
}
// add item "name" with a unique id to menu
-void LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
{
- mList->addSimpleItem(name, LLSD(id), pos, enabled);
+ LLScrollListItem* item = mList->addSimpleItem(name, LLSD(id), pos, enabled);
mList->selectFirstItem();
+ return item;
}
// add item "name" with attached userdata
-void LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
{
LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled);
item->setUserdata( userdata );
mList->selectFirstItem();
+ return item;
}
// add item "name" with attached generic data
-void LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
{
- mList->addSimpleItem(name, value, pos, enabled);
+ LLScrollListItem* item = mList->addSimpleItem(name, value, pos, enabled);
mList->selectFirstItem();
+ return item;
}
+LLScrollListItem* LLComboBox::addSeparator(EAddPosition pos)
+{
+ return mList->addSeparator(pos);
+}
void LLComboBox::sortByName()
{
@@ -335,9 +330,9 @@ void LLComboBox::setValue(const LLSD& value)
}
}
-const LLString& LLComboBox::getSimple() const
+const LLString LLComboBox::getSimple() const
{
- const LLString& res = mList->getSimpleSelectedItem();
+ const LLString res = mList->getSimpleSelectedItem();
if (res.empty() && mAllowTextEntry)
{
return mTextEntry->getText();
@@ -348,7 +343,7 @@ const LLString& LLComboBox::getSimple() const
}
}
-const LLString& LLComboBox::getSimpleSelectedItem(S32 column) const
+const LLString LLComboBox::getSimpleSelectedItem(S32 column) const
{
return mList->getSimpleSelectedItem(column);
}
@@ -373,7 +368,7 @@ LLSD LLComboBox::getValue() const
void LLComboBox::setLabel(const LLStringExplicit& name)
{
- if ( mAllowTextEntry )
+ if ( mTextEntry )
{
mTextEntry->setText(name);
if (mList->selectSimpleItem(name, FALSE))
@@ -385,7 +380,8 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
mTextEntry->setTentative(mTextEntryTentative);
}
}
- else
+
+ if (!mAllowTextEntry)
{
mButton->setLabelUnselected(name);
mButton->setLabelSelected(name);
@@ -433,16 +429,21 @@ void LLComboBox::onFocusLost()
LLUICtrl::onFocusLost();
}
+void LLComboBox::onLostTop()
+{
+ hideList();
+}
+
+
void LLComboBox::setButtonVisible(BOOL visible)
{
mButton->setVisible(visible);
- mDrawArrow = visible;
if (mTextEntry)
{
LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
if (visible)
{
- text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
+ text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth(0)) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
}
//mTextEntry->setRect(text_entry_rect);
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -457,22 +458,8 @@ void LLComboBox::draw()
mButton->setEnabled(mEnabled /*&& !mList->isEmpty()*/);
- // Draw children
+ // Draw children normally
LLUICtrl::draw();
-
- if (mDrawArrow)
- {
- // Paste the graphic on the right edge
- if (!mArrowImage.isNull())
- {
- 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_scaled_image( left, 0, arrow_width, arrow_height, mArrowImage, LLColor4::white);
- }
- }
}
}
@@ -497,6 +484,67 @@ S32 LLComboBox::getCurrentIndex() const
}
+void LLComboBox::updateLayout()
+{
+ LLRect rect = getLocalRect();
+ if (mAllowTextEntry)
+ {
+ S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
+ mButton->setRect(LLRect( mRect.getWidth() - llmax(8,mArrowImage->getWidth(0)) - 2 * shadow_size,
+ rect.mTop, rect.mRight, rect.mBottom));
+ mButton->setTabStop(FALSE);
+
+ if (!mTextEntry)
+ {
+ LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
+ text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth(0)) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
+ // clear label on button
+ LLString cur_label = mButton->getLabelSelected();
+ mTextEntry = new LLLineEditor("combo_text_entry",
+ text_entry_rect,
+ "",
+ LLFontGL::sSansSerifSmall,
+ mMaxChars,
+ onTextCommit,
+ onTextEntry,
+ NULL,
+ this,
+ NULL, // prevalidate func
+ LLViewBorder::BEVEL_NONE,
+ LLViewBorder::STYLE_LINE,
+ 0); // no border
+ mTextEntry->setSelectAllonFocusReceived(TRUE);
+ mTextEntry->setHandleEditKeysDirectly(TRUE);
+ mTextEntry->setCommitOnFocusLost(FALSE);
+ mTextEntry->setText(cur_label);
+ mTextEntry->setIgnoreTab(TRUE);
+ mTextEntry->setFollowsAll();
+ addChild(mTextEntry);
+ }
+ else
+ {
+ mTextEntry->setVisible(TRUE);
+ mTextEntry->setMaxTextLength(mMaxChars);
+ }
+
+ // clear label on button
+ setLabel(LLString::null);
+
+ mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
+ }
+ else if (!mAllowTextEntry)
+ {
+ mButton->setRect(rect);
+ mButton->setTabStop(TRUE);
+
+ if (mTextEntry)
+ {
+ mTextEntry->setVisible(FALSE);
+ }
+ mButton->setFollowsAll();
+ }
+}
+
void* LLComboBox::getCurrentUserdata()
{
LLScrollListItem* item = mList->getFirstSelected();
@@ -514,7 +562,7 @@ void LLComboBox::showList()
LLCoordWindow window_size;
getWindow()->getSize(&window_size);
//HACK: shouldn't have to know about scale here
- mList->arrange( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
+ mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
// Make sure that we can see the whole list
LLRect root_view_local;
@@ -523,7 +571,9 @@ void LLComboBox::showList()
LLRect rect = mList->getRect();
- S32 list_width = mRect.getWidth() + SCROLLBAR_SIZE;
+ S32 min_width = mRect.getWidth();
+ S32 max_width = llmax(min_width, MAX_COMBO_WIDTH);
+ S32 list_width = llclamp(mList->getMaxContentWidth(), min_width, max_width);
if (mListPosition == BELOW)
{
@@ -583,12 +633,6 @@ void LLComboBox::showList()
mList->translate(0, -y);
}
- // 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
@@ -604,24 +648,29 @@ void LLComboBox::showList()
mButton->setToggleState(TRUE);
mList->setVisible(TRUE);
- gFocusMgr.setTopCtrl(mList);
+ setUseBoundingRect(TRUE);
+ gFocusMgr.setTopCtrl(this);
}
void LLComboBox::hideList()
{
+ //*HACK: store the original value explicitly somewhere, not just in label
+ LLString orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected();
+
+ // assert selection in list
+ mList->selectSimpleItem(orig_selection, FALSE);
+
mButton->setToggleState(FALSE);
mList->setVisible(FALSE);
mList->highlightNthItem(-1);
- if( gFocusMgr.getTopCtrl() == mList )
+ setUseBoundingRect(FALSE);
+ if( gFocusMgr.getTopCtrl() == this )
{
gFocusMgr.setTopCtrl(NULL);
}
-
- //mList->setFocus(FALSE);
}
-
//------------------------------------------------------------------
// static functions
//------------------------------------------------------------------
@@ -650,21 +699,20 @@ void LLComboBox::onButtonDown(void *userdata)
self->showList();
}
- if (self->mKeyboardFocusOnClick && !self->hasFocus())
+ self->setFocus( TRUE );
+
+ // pass mouse capture on to list if button is depressed
+ if (self->mButton->hasMouseCapture())
{
- self->setFocus( TRUE );
+ gFocusMgr.setMouseCapture(self->mList);
}
}
else
{
- // hide and release keyboard focus
self->hideList();
-
- self->onCommit();
}
-}
-
+}
// static
void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
@@ -672,7 +720,7 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
// Note: item is the LLScrollListCtrl
LLComboBox *self = (LLComboBox *) userdata;
- const LLString& name = self->mList->getSimpleSelectedItem();
+ const LLString name = self->mList->getSimpleSelectedItem();
S32 cur_id = self->getCurrentIndex();
if (cur_id != -1)
@@ -681,40 +729,24 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
if (self->mAllowTextEntry)
{
- gFocusMgr.setKeyboardFocus(self->mTextEntry, NULL);
+ gFocusMgr.setKeyboardFocus(self->mTextEntry);
self->mTextEntry->selectAll();
}
}
else
{
// invalid selection, just restore existing value
- self->mList->selectSimpleItem(self->mButton->getLabelSelected());
+ LLString orig_selection = self->mAllowTextEntry ? self->mTextEntry->getText() : self->mButton->getLabelSelected();
+
+ self->mList->selectSimpleItem(orig_selection);
}
self->onCommit();
self->hideList();
}
-// static
-void LLComboBox::onListFocusChanged(LLUICtrl* list, void* user_data)
-{
- LLComboBox *self = (LLComboBox *) list->getParent();
- // user not manipulating list or clicking on drop down button
- if (!self->mList->hasFocus() && !self->mButton->hasMouseCapture())
- {
- //*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)
@@ -726,23 +758,19 @@ BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_
tool_tip = mToolTipMsg;
}
- if( getVisible() && pointInView( x, y ) )
+ if( !tool_tip.empty() )
{
- if( !tool_tip.empty() )
- {
- msg = tool_tip;
-
- // Convert rect local to screen coordinates
- localPointToScreen(
- 0, 0,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- localPointToScreen(
- mRect.getWidth(), mRect.getHeight(),
- &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
- }
- return TRUE;
+ msg = tool_tip;
+
+ // Convert rect local to screen coordinates
+ localPointToScreen(
+ 0, 0,
+ &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+ localPointToScreen(
+ mRect.getWidth(), mRect.getHeight(),
+ &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
}
- return FALSE;
+ return TRUE;
}
BOOL LLComboBox::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
@@ -793,63 +821,11 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent
void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
{
- LLRect rect( 0, mRect.getHeight(), mRect.getWidth(), 0);
- if (allow && !mAllowTextEntry)
- {
- S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
- mButton->setRect(LLRect( mRect.getWidth() - mArrowImageWidth - 2 * shadow_size,
- rect.mTop, rect.mRight, rect.mBottom));
- mButton->setTabStop(FALSE);
-
- // clear label on button
- LLString cur_label = mButton->getLabelSelected();
- setLabel(LLString::null);
- if (!mTextEntry)
- {
- LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
- text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
- mTextEntry = new LLLineEditor("combo_text_entry",
- text_entry_rect,
- "",
- LLFontGL::sSansSerifSmall,
- max_chars,
- onTextCommit,
- onTextEntry,
- NULL,
- this,
- NULL, // prevalidate func
- LLViewBorder::BEVEL_NONE,
- LLViewBorder::STYLE_LINE,
- 0); // no border
- mTextEntry->setSelectAllonFocusReceived(TRUE);
- mTextEntry->setHandleEditKeysDirectly(TRUE);
- mTextEntry->setCommitOnFocusLost(FALSE);
- mTextEntry->setText(cur_label);
- mTextEntry->setIgnoreTab(TRUE);
- mTextEntry->setFollowsAll();
- addChild(mTextEntry);
- mMaxChars = max_chars;
- }
- else
- {
- mTextEntry->setVisible(TRUE);
- }
-
- mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
- }
- else if (!allow && mAllowTextEntry)
- {
- mButton->setRect(rect);
- mButton->setTabStop(TRUE);
-
- if (mTextEntry)
- {
- mTextEntry->setVisible(FALSE);
- }
- mButton->setFollowsAll();
- }
mAllowTextEntry = allow;
- mTextEntryTentative = set_tentative;
+ mTextEntryTentative = set_tentative;
+ mMaxChars = max_chars;
+
+ updateLayout();
}
void LLComboBox::setTextEntry(const LLStringExplicit& text)
@@ -993,6 +969,10 @@ void LLComboBox::setFocus(BOOL b)
if (b)
{
mList->clearSearchString();
+ if (mList->getVisible())
+ {
+ mList->setFocus(TRUE);
+ }
}
}
@@ -1097,3 +1077,155 @@ BOOL LLComboBox::operateOnAll(EOperation op)
}
return FALSE;
}
+
+
+
+//
+// LLFlyoutButton
+//
+
+const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
+
+LLFlyoutButton::LLFlyoutButton(
+ const LLString& name,
+ const LLRect &rect,
+ const LLString& label,
+ void (*commit_callback)(LLUICtrl*, void*) ,
+ void *callback_userdata)
+: LLComboBox(name, rect, LLString::null, commit_callback, callback_userdata),
+ mToggleState(FALSE),
+ mActionButton(NULL)
+{
+ // Always use text box
+ // Text label button
+ mActionButton = new LLButton("flyout_button_main",
+ LLRect(), label, NULL, LLString::null,
+ NULL, this);
+ mActionButton->setScaleImage(TRUE);
+
+ mActionButton->setClickedCallback(onActionButtonClick);
+ mActionButton->setFollowsAll();
+ mActionButton->setHAlign( LLFontGL::HCENTER );
+ mActionButton->setLabel(label);
+ addChild(mActionButton);
+
+ mActionButtonImage = LLUI::getUIImageByName("flyout_btn_left.tga");
+ mExpanderButtonImage = LLUI::getUIImageByName("flyout_btn_right.tga");
+ mActionButtonImageSelected = LLUI::getUIImageByName("flyout_btn_left_selected.tga");
+ mExpanderButtonImageSelected = LLUI::getUIImageByName("flyout_btn_right_selected.tga");
+
+ mActionButton->setImageSelected(mActionButtonImageSelected);
+ mActionButton->setImageUnselected(mActionButtonImage);
+ mActionButton->setImageDisabled(LLPointer<LLUIImage>(NULL));
+ mActionButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
+
+ mButton->setImageSelected(mExpanderButtonImageSelected);
+ mButton->setImageUnselected(mExpanderButtonImage);
+ mButton->setImageDisabled(LLPointer<LLUIImage>(NULL));
+ mButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
+ mButton->setRightHPad(6);
+
+ mBorder->setVisible(FALSE);
+
+ updateLayout();
+}
+
+//static
+LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+{
+ LLString name = "flyout_button";
+ node->getAttributeString("name", name);
+
+ LLString label("");
+ node->getAttributeString("label", label);
+
+ LLRect rect;
+ createRect(node, rect, parent, LLRect());
+
+ LLUICtrlCallback callback = NULL;
+
+ LLFlyoutButton* flyout_button = new LLFlyoutButton(name,
+ rect,
+ label,
+ callback,
+ NULL);
+
+ LLString list_position;
+ node->getAttributeString("list_position", list_position);
+ if (list_position == "below")
+ {
+ flyout_button->mListPosition = BELOW;
+ }
+ else if (list_position == "above")
+ {
+ flyout_button->mListPosition = ABOVE;
+ }
+
+
+ flyout_button->initFromXML(node, parent);
+
+ LLXMLNodePtr child;
+ for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+ {
+ if (child->hasName("flyout_button_item"))
+ {
+ LLString label = child->getTextContents();
+
+ LLString value = label;
+ child->getAttributeString("value", value);
+
+ flyout_button->add(label, LLSD(value) );
+ }
+ }
+
+ flyout_button->updateLayout();
+
+ return flyout_button;
+}
+
+void LLFlyoutButton::updateLayout()
+{
+ LLComboBox::updateLayout();
+
+ mButton->setOrigin(mRect.getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
+ mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, mRect.getHeight());
+ mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+ mButton->setTabStop(FALSE);
+ mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
+
+ mActionButton->setOrigin(0, 0);
+ mActionButton->reshape(mRect.getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, mRect.getHeight());
+}
+
+//static
+void LLFlyoutButton::onActionButtonClick(void *user_data)
+{
+ LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data;
+ // remember last list selection?
+ buttonp->mList->deselect();
+ buttonp->onCommit();
+}
+
+void LLFlyoutButton::draw()
+{
+ mActionButton->setToggleState(mToggleState);
+ mButton->setToggleState(mToggleState);
+
+ //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
+ // the label reflects the last selected item, for now we have to manually remove the label
+ mButton->setLabel(LLString::null);
+ LLComboBox::draw();
+}
+
+void LLFlyoutButton::setEnabled(BOOL enabled)
+{
+ mActionButton->setEnabled(enabled);
+ LLComboBox::setEnabled(enabled);
+}
+
+
+void LLFlyoutButton::setToggleState(BOOL state)
+{
+ mToggleState = state;
+}
+
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index ff17d2874f..6e77007aef 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -80,6 +80,7 @@ public:
virtual void draw();
virtual void onFocusLost();
+ virtual void onLostTop();
virtual void setEnabled(BOOL enabled);
@@ -107,10 +108,11 @@ public:
void setAllowTextEntry(BOOL allow, S32 max_chars = 50, BOOL make_tentative = TRUE);
void setTextEntry(const LLStringExplicit& text);
- void add(const LLString& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); // add item "name" to menu
- void add(const LLString& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
- void add(const LLString& name, void* userdata, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
- void add(const LLString& name, LLSD value, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+ LLScrollListItem* add(const LLString& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); // add item "name" to menu
+ LLScrollListItem* add(const LLString& name, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+ LLScrollListItem* add(const LLString& name, void* userdata, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+ LLScrollListItem* add(const LLString& name, LLSD value, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
+ LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM);
BOOL remove( S32 index ); // remove item by index, return TRUE if found and removed
void removeall() { clearRows(); }
@@ -119,9 +121,9 @@ public:
// Select current item by name using selectSimpleItem. Returns FALSE if not found.
BOOL setSimple(const LLStringExplicit& name);
// Get name of current item. Returns an empty string if not found.
- const LLString& getSimple() const;
+ const LLString getSimple() const;
// Get contents of column x of selected row
- const LLString& getSimpleSelectedItem(S32 column = 0) const;
+ const LLString getSimpleSelectedItem(S32 column = 0) const;
// Sets the label, which doesn't have to exist in the label.
// This is probably a UI abuse.
@@ -132,6 +134,8 @@ public:
BOOL setCurrentByIndex( S32 index );
S32 getCurrentIndex() const;
+ virtual void updateLayout();
+
//========================================================================
LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; };
LLCtrlListInterface* getListInterface() { return (LLCtrlListInterface*)this; };
@@ -172,7 +176,6 @@ public:
static void onButtonDown(void *userdata);
static void onItemSelected(LLUICtrl* item, void *userdata);
- static void onListFocusChanged(LLUICtrl* item, void *userdata);
static void onTextEntry(LLLineEditor* line_editor, void* user_data);
static void onTextCommit(LLUICtrl* caller, void* user_data);
@@ -183,12 +186,10 @@ public:
protected:
LLButton* mButton;
LLScrollListCtrl* mList;
+ S32 mButtonPadding;
LLViewBorder* mBorder;
- BOOL mKeyboardFocusOnClick;
- BOOL mDrawArrow;
LLLineEditor* mTextEntry;
LLPointer<LLImageGL> mArrowImage;
- S32 mArrowImageWidth;
BOOL mAllowTextEntry;
S32 mMaxChars;
BOOL mTextEntryTentative;
@@ -197,4 +198,36 @@ protected:
void (*mTextEntryCallback)(LLLineEditor*, void*);
};
+class LLFlyoutButton : public LLComboBox
+{
+public:
+ LLFlyoutButton(
+ const LLString& name,
+ const LLRect &rect,
+ const LLString& label,
+ void (*commit_callback)(LLUICtrl*, void*) = NULL,
+ void *callback_userdata = NULL);
+
+ virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_FLYOUT_BUTTON; }
+ virtual LLString getWidgetTag() const { return LL_FLYOUT_BUTTON_TAG; }
+
+ virtual void updateLayout();
+ virtual void draw();
+ virtual void setEnabled(BOOL enabled);
+
+ void setToggleState(BOOL state);
+
+ static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+ static void onActionButtonClick(void *userdata);
+ static void onSelectAction(LLUICtrl* ctrl, void *userdata);
+
+protected:
+ LLButton* mActionButton;
+ LLPointer<LLUIImage> mActionButtonImage;
+ LLPointer<LLUIImage> mExpanderButtonImage;
+ LLPointer<LLUIImage> mActionButtonImageSelected;
+ LLPointer<LLUIImage> mExpanderButtonImageSelected;
+ BOOL mToggleState;
+};
+
#endif
diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h
index 50d199fac5..cd3ce04718 100644
--- a/indra/llui/lldraghandle.h
+++ b/indra/llui/lldraghandle.h
@@ -54,7 +54,6 @@ public:
virtual void setTitle( const LLString& title ) = 0;
virtual const LLString& getTitle() const = 0;
- virtual void draw() = 0;
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) = 0;
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 6f1c281eb2..59741a799a 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -128,7 +128,11 @@ LLFloater::handle_map_t LLFloater::sFloaterMap;
LLFloaterView* gFloaterView = NULL;
-LLFloater::LLFloater()
+LLFloater::LLFloater() :
+ //FIXME: we should initialize *all* member variables here
+ mResizable(FALSE),
+ mDragOnLeft(FALSE)
+
{
// automatically take focus when opened
mAutoFocus = TRUE;
@@ -215,9 +219,14 @@ void LLFloater::init(const LLString& title,
}
mButtonScale = 1.f;
- LLPanel::deleteAllChildren();
+ BOOL need_border = mBorder != NULL;
+
+ // this will delete mBorder too
+ deleteAllChildren();
+ // make sure we don't have a pointer to an old, deleted border
+ mBorder = NULL;
//sjb: HACK! we had a border which was just deleted, so re-create it
- if (mBorder != NULL)
+ if (need_border)
{
addBorder();
}
@@ -609,7 +618,7 @@ void LLFloater::releaseFocus()
if( gFocusMgr.childHasKeyboardFocus( this ) )
{
- gFocusMgr.setKeyboardFocus(NULL, NULL);
+ gFocusMgr.setKeyboardFocus(NULL);
}
if( gFocusMgr.childHasMouseCapture( this ) )
@@ -1023,13 +1032,10 @@ void LLFloater::setHost(LLMultiFloater* host)
{
mButtonsEnabled[BUTTON_TEAR_OFF] = TRUE;
}
-
- mIsFocusRoot = FALSE;
}
else if (!mHostHandle.isDead() && !host)
{
mButtonScale = 1.f;
- mIsFocusRoot = TRUE;
//mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE;
}
updateButtons();
@@ -1257,6 +1263,7 @@ void LLFloater::show(LLFloater* floaterp)
{
if (floaterp)
{
+ gFocusMgr.triggerFocusFlash();
floaterp->open();
if (floaterp->getHost())
{
@@ -2594,9 +2601,9 @@ void LLMultiFloater::draw()
for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
{
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
- if (floaterp->getTitle() != mTabContainer->getPanelTitle(i))
+ if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i))
{
- mTabContainer->setPanelTitle(i, floaterp->getTitle());
+ mTabContainer->setPanelTitle(i, floaterp->getShortTitle());
}
}
LLFloater::draw();
@@ -2714,7 +2721,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
if ( select_added_floater )
{
- mTabContainer->selectLastTab();
+ mTabContainer->selectTabPanel(floaterp);
}
floaterp->setHost(this);
@@ -2959,8 +2966,9 @@ void LLMultiFloater::updateResizeLimits()
// make sure upper left corner doesn't move
translate(0, cur_height - mRect.getHeight());
- // Try to keep whole view onscreen, don't allow partial offscreen.
- gFloaterView->adjustToFitScreen(this, FALSE);
+ // make sure this window is visible on screen when it has been modified
+ // (tab added, etc)
+ gFloaterView->adjustToFitScreen(this, TRUE);
}
}
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 6358ccbdd7..e3337eb588 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -42,11 +42,10 @@ LLFocusMgr gFocusMgr;
LLFocusMgr::LLFocusMgr()
:
mLockedView( NULL ),
- mKeyboardLockedFocusLostCallback( NULL ),
mMouseCaptor( NULL ),
mKeyboardFocus( NULL ),
+ mLastKeyboardFocus( NULL ),
mDefaultKeyboardFocus( NULL ),
- mKeyboardFocusLostCallback( NULL ),
mTopCtrl( NULL ),
mFocusWeight(0.f),
mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true
@@ -75,12 +74,11 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
if (view == mLockedView)
{
mLockedView = NULL;
- mKeyboardLockedFocusLostCallback = NULL;
- setKeyboardFocus( NULL, NULL );
+ setKeyboardFocus( NULL );
}
else
{
- setKeyboardFocus( mLockedView, mKeyboardLockedFocusLostCallback );
+ setKeyboardFocus( mLockedView );
}
}
@@ -91,7 +89,7 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
}
-void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focus_lost, BOOL lock)
+void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock)
{
if (mLockedView &&
(new_focus == NULL ||
@@ -101,28 +99,27 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focu
// or one of its descendants
return;
}
- FocusLostCallback old_callback = mKeyboardFocusLostCallback;
- mKeyboardFocusLostCallback = on_focus_lost;
//llinfos << "Keyboard focus handled by " << (new_focus ? new_focus->getName() : "nothing") << llendl;
if( new_focus != mKeyboardFocus )
{
- LLUICtrl* old_focus = mKeyboardFocus;
+ mLastKeyboardFocus = mKeyboardFocus;
mKeyboardFocus = new_focus;
+ if( mLastKeyboardFocus )
+ {
+ mLastKeyboardFocus->onFocusLost();
+ }
+
// clear out any existing flash
if (new_focus)
{
mFocusWeight = 0.f;
+ new_focus->onFocusReceived();
}
mFocusTimer.reset();
- if( old_callback )
- {
- old_callback( old_focus );
- }
-
#ifdef _DEBUG
mKeyboardFocusName = new_focus ? new_focus->getName() : "none";
#endif
@@ -204,13 +201,11 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( LLView* focus )
if (focus == mLockedView)
{
mLockedView = NULL;
- mKeyboardLockedFocusLostCallback = NULL;
}
if( mKeyboardFocus == focus )
{
mKeyboardFocus = NULL;
- mKeyboardFocusLostCallback = NULL;
#ifdef _DEBUG
mKeyboardFocusName = "none";
#endif
@@ -293,13 +288,19 @@ BOOL LLFocusMgr::childIsTopCtrl( LLView* parent )
// set new_top = NULL to release top_view.
void LLFocusMgr::setTopCtrl( LLUICtrl* new_top )
{
- if( new_top != mTopCtrl )
+ LLUICtrl* old_top = mTopCtrl;
+ if( new_top != old_top )
{
mTopCtrl = new_top;
#ifdef _DEBUG
mTopCtrlName = new_top ? new_top->getName() : "none";
#endif
+
+ if (old_top)
+ {
+ old_top->onLostTop();
+ }
}
}
@@ -317,13 +318,11 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( LLUICtrl* top_view )
void LLFocusMgr::lockFocus()
{
mLockedView = mKeyboardFocus;
- mKeyboardLockedFocusLostCallback = mKeyboardFocusLostCallback;
}
void LLFocusMgr::unlockFocus()
{
mLockedView = NULL;
- mKeyboardLockedFocusLostCallback = NULL;
}
F32 LLFocusMgr::getFocusFlashAmt()
@@ -356,9 +355,9 @@ void LLFocusMgr::setAppHasFocus(BOOL focus)
}
// release focus from "top ctrl"s, which generally hides them
- if (!focus && mTopCtrl && mTopCtrl->hasFocus())
+ if (!focus && mTopCtrl)
{
- mTopCtrl->setFocus(FALSE);
+ setTopCtrl(NULL);
}
mAppHasFocus = focus;
}
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index 1c25153fbe..20dc21fc3a 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -44,8 +44,6 @@ class LLMouseHandler;
class LLFocusMgr
{
public:
- typedef void (*FocusLostCallback)(LLUICtrl*);
-
LLFocusMgr();
~LLFocusMgr();
@@ -56,11 +54,11 @@ public:
BOOL childHasMouseCapture( LLView* parent );
// Keyboard Focus
- void setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focus_lost, BOOL lock = FALSE); // new_focus = NULL to release the focus.
+ void setKeyboardFocus(LLUICtrl* new_focus, BOOL lock = FALSE); // new_focus = NULL to release the focus.
LLUICtrl* getKeyboardFocus() const { return mKeyboardFocus; }
+ LLUICtrl* getLastKeyboardFocus() const { return mLastKeyboardFocus; }
BOOL childHasKeyboardFocus( const LLView* parent ) const;
void removeKeyboardFocusWithoutCallback( LLView* focus );
- FocusLostCallback getFocusCallback() { return mKeyboardFocusLostCallback; }
F32 getFocusTime() const { return mFocusTimer.getElapsedTimeF32(); }
F32 getFocusFlashAmt();
LLColor4 getFocusColor();
@@ -90,15 +88,14 @@ public:
protected:
LLUICtrl* mLockedView;
- FocusLostCallback mKeyboardLockedFocusLostCallback;
// Mouse Captor
LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object
// Keyboard Focus
LLUICtrl* mKeyboardFocus; // Keyboard events are preemptively routed to this object
+ LLUICtrl* mLastKeyboardFocus; // who last had focus
LLUICtrl* mDefaultKeyboardFocus;
- FocusLostCallback mKeyboardFocusLostCallback; // The object to which keyboard events are routed is called before another object takes its place
// Top View
LLUICtrl* mTopCtrl;
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index 1e49210565..a063ebcd25 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -88,18 +88,11 @@ void LLIconCtrl::draw()
{
if( getVisible() )
{
- // Border
- BOOL has_image = !mImageID.isNull();
-
- if( has_image )
+ if( mImagep.notNull() )
{
- if( mImagep.notNull() )
- {
- gl_draw_scaled_image(0, 0,
- mRect.getWidth(), mRect.getHeight(),
- mImagep,
- mColor );
- }
+ mImagep->draw(0, 0,
+ mRect.getWidth(), mRect.getHeight(),
+ mColor );
}
LLUICtrl::draw();
@@ -154,6 +147,7 @@ LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *
LLUICtrlFactory::getAttributeColor(node,"color", color);
LLIconCtrl* icon = new LLIconCtrl(name, rect, image_id);
+
icon->setColor(color);
icon->initFromXML(node, parent);
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index b789269558..1e474d0935 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -73,7 +73,7 @@ protected:
LLColor4 mColor;
LLString mImageName;
LLUUID mImageID;
- LLPointer<LLImageGL> mImagep;
+ LLPointer<LLUIImage> mImagep;
};
#endif
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 3c7cd17b92..4297f5fef8 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -128,7 +128,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)(LLUICtrl* caller, void* user_data ),
+ void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data ),
void* userdata,
LLLinePrevalidateFunc prevalidate_func,
LLViewBorder::EBevel border_bevel,
@@ -351,10 +351,14 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
// Check to see if entire field is selected.
S32 len = mText.length();
- BOOL allSelected = (len > 0) && (( mSelectionStart == 0 && mSelectionEnd == len )
- || ( mSelectionStart == len && mSelectionEnd == 0 ));
+ BOOL all_selected = (len > 0)
+ && (( mSelectionStart == 0 && mSelectionEnd == len )
+ || ( mSelectionStart == len && mSelectionEnd == 0 ));
// Do safe truncation so we don't split multi-byte characters
+ // also consider entire string selected when mSelectAllonFocusReceived is set on an empty, focused line editor
+ all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived);
+
LLString truncated_utf8 = new_text;
if (truncated_utf8.size() > (U32)mMaxLengthBytes)
{
@@ -362,7 +366,7 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
}
mText.assign(truncated_utf8);
- if (allSelected)
+ if (all_selected)
{
// ...keep whole thing selected
selectAll();
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index a019353856..0739315c4d 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -77,7 +77,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)(LLUICtrl* caller, void* user_data) = NULL,
+ void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data) = NULL,
void* userdata = NULL,
LLLinePrevalidateFunc prevalidate_func = NULL,
LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_IN,
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 46f9f515d7..19a5085a25 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -4514,7 +4514,7 @@ BOOL LLMenuHolderGL::hideMenus()
}
//if (gFocusMgr.childHasKeyboardFocus(this))
//{
- // gFocusMgr.setKeyboardFocus(NULL, NULL);
+ // gFocusMgr.setKeyboardFocus(NULL);
//}
return menu_visible;
@@ -4599,6 +4599,7 @@ void LLTearOffMenu::onFocusReceived()
break;
}
}
+ LLFloater::onFocusReceived();
}
void LLTearOffMenu::onFocusLost()
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index b8b8bf9443..ca8020fe70 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -287,7 +287,7 @@ void LLModalDialog::onAppFocusLost()
if( gFocusMgr.childHasKeyboardFocus( instance ) )
{
- gFocusMgr.setKeyboardFocus( NULL, NULL );
+ gFocusMgr.setKeyboardFocus( NULL );
}
}
}
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 6d000f3e7f..294ce5df18 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -64,7 +64,6 @@ LLPanel::panel_map_t LLPanel::sPanelMap;
LLPanel::alert_queue_t LLPanel::sAlertQueue;
const S32 RESIZE_BAR_OVERLAP = 1;
-const S32 PANEL_STACK_GAP = RESIZE_BAR_HEIGHT;
void LLPanel::init()
{
@@ -88,6 +87,7 @@ LLPanel::LLPanel()
: mRectControl()
{
init();
+ setName("panel");
}
LLPanel::LLPanel(const LLString& name)
@@ -124,6 +124,7 @@ LLPanel::LLPanel(const LLString& name, const LLString& rect_control, BOOL border
void LLPanel::addBorder(LLViewBorder::EBevel border_bevel,
LLViewBorder::EStyle border_style, S32 border_thickness)
{
+ removeBorder();
mBorder = new LLViewBorder( "panel border",
LLRect(0, mRect.getHeight(), mRect.getWidth(), 0),
border_bevel, border_style, border_thickness );
@@ -361,12 +362,6 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
{
BOOL handled = FALSE;
- if( getVisible() && getEnabled() && gFocusMgr.childHasKeyboardFocus(this) && KEY_ESCAPE == key )
- {
- gFocusMgr.setKeyboardFocus(NULL, NULL);
- return TRUE;
- }
-
if( getVisible() && getEnabled() &&
gFocusMgr.childHasKeyboardFocus(this) && !called_from_parent )
{
@@ -472,7 +467,7 @@ void LLPanel::setFocus(BOOL b)
{
if( this == gFocusMgr.getKeyboardFocus() )
{
- gFocusMgr.setKeyboardFocus( NULL, NULL );
+ gFocusMgr.setKeyboardFocus( NULL );
}
else
{
@@ -595,7 +590,8 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
{
LLRect rect;
createRect(node, rect, parent, LLRect());
- panelp = new LLPanel(name, rect);
+ // create a new panel without a border, by default
+ panelp = new LLPanel(name, rect, FALSE);
panelp->initPanelXML(node, parent, factory);
// preserve panel's width and height, but override the location
const LLRect& panelrect = panelp->getRect();
@@ -608,12 +604,13 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
{
panelp->initPanelXML(node, parent, factory);
}
+
return panelp;
}
BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
{
- LLString name("panel");
+ LLString name = getName();
node->getAttributeString("name", name);
setName(name);
@@ -628,13 +625,15 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
if (!xml_filename.empty())
{
- // Preserve postion of embedded panel but allow panel to dictate width/height
- LLRect rect(getRect());
didPost = factory->buildPanel(this, xml_filename, NULL);
- S32 w = getRect().getWidth();
- S32 h = getRect().getHeight();
- rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
- setRect(rect);
+
+ LLRect new_rect = getRect();
+ // override rectangle with embedding parameters as provided
+ createRect(node, new_rect, parent);
+ setOrigin(new_rect.mLeft, new_rect.mBottom);
+ reshape(new_rect.getWidth(), new_rect.getHeight());
+ // optionally override follows flags from including nodes
+ parseFollowsFlags(node);
}
else
{
@@ -678,7 +677,7 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
initFromXML(node, parent);
/////// Border attributes ///////
- BOOL border = FALSE;
+ BOOL border = mBorder != NULL;
node->getAttributeBOOL("border", border);
if (border)
{
@@ -706,24 +705,24 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
}
/////// Background attributes ///////
- BOOL background_visible = FALSE;
+ BOOL background_visible = mBgVisible;
node->getAttributeBOOL("background_visible", background_visible);
setBackgroundVisible(background_visible);
- BOOL background_opaque = FALSE;
+ BOOL background_opaque = mBgOpaque;
node->getAttributeBOOL("background_opaque", background_opaque);
setBackgroundOpaque(background_opaque);
LLColor4 color;
- color = LLUI::sColorsGroup->getColor( "FocusBackgroundColor" );
+ color = mBgColorOpaque;
LLUICtrlFactory::getAttributeColor(node,"bg_opaque_color", color);
setBackgroundColor(color);
- color = LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" );
+ color = mBgColorAlpha;
LLUICtrlFactory::getAttributeColor(node,"bg_alpha_color", color);
setTransparentColor(color);
- LLString label;
+ LLString label = getLabel();
node->getAttributeString("label", label);
setLabel(label);
}
@@ -853,12 +852,12 @@ BOOL LLPanel::childHasFocus(const LLString& id)
}
-void LLPanel::childSetFocusChangedCallback(const LLString& id, void (*cb)(LLUICtrl*, void*))
+void LLPanel::childSetFocusChangedCallback(const LLString& id, void (*cb)(LLFocusableElement*, void*), void* user_data)
{
LLUICtrl* child = (LLUICtrl*)getChildByName(id, true);
if (child)
{
- child->setFocusChangedCallback(cb);
+ child->setFocusChangedCallback(cb, user_data);
}
}
@@ -1165,11 +1164,12 @@ void LLPanel::storeRectControl()
//
struct LLLayoutStack::LLEmbeddedPanel
{
- LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize) :
+ LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) :
mPanel(panelp),
mMinWidth(min_width),
mMinHeight(min_height),
mAutoResize(auto_resize),
+ mUserResize(user_resize),
mOrientation(orientation),
mVisibleAmt(1.f) // default to fully visible
{
@@ -1205,6 +1205,7 @@ struct LLLayoutStack::LLEmbeddedPanel
S32 mMinWidth;
S32 mMinHeight;
BOOL mAutoResize;
+ BOOL mUserResize;
LLResizeBar* mResizeBar;
eLayoutOrientation mOrientation;
F32 mVisibleAmt;
@@ -1213,7 +1214,8 @@ struct LLLayoutStack::LLEmbeddedPanel
LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) :
mOrientation(orientation),
mMinWidth(0),
- mMinHeight(0)
+ mMinHeight(0),
+ mPanelSpacing(RESIZE_BAR_HEIGHT)
{
}
@@ -1226,24 +1228,26 @@ void LLLayoutStack::draw()
{
updateLayout();
{
- // clip if outside nominal bounds
- LLLocalClipRect clip(getLocalRect(), mRect.getWidth() > mMinWidth || mRect.getHeight() > mMinHeight);
e_panel_list_t::iterator panel_it;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
+ // clip to layout rectangle, not bounding rectangle
LLRect clip_rect = (*panel_it)->mPanel->getRect();
// scale clipping rectangle by visible amount
if (mOrientation == HORIZONTAL)
{
- clip_rect.mRight = clip_rect.mLeft + llround(clip_rect.getWidth() * (*panel_it)->mVisibleAmt);
+ clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->mVisibleAmt);
}
else
{
- clip_rect.mBottom = clip_rect.mTop - llround(clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
+ clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
}
- LLLocalClipRect clip(clip_rect, (*panel_it)->mVisibleAmt < 1.f);
+
+ LLPanel* panelp = (*panel_it)->mPanel;
+
+ LLLocalClipRect clip(clip_rect);
// only force drawing invisible children if visible amount is non-zero
- drawChild((*panel_it)->mPanel, 0, 0, (*panel_it)->mVisibleAmt > 0.f);
+ drawChild(panelp, 0, 0, !clip_rect.isNull());
}
}
}
@@ -1258,17 +1262,13 @@ void LLLayoutStack::removeCtrl(LLUICtrl* ctrl)
delete embedded_panelp;
}
+ // need to update resizebars
+
calcMinExtents();
LLView::removeCtrl(ctrl);
}
-void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
- LLView::reshape(width, height, called_from_parent);
- //updateLayout();
-}
-
LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
{
LLXMLNodePtr node = LLView::getXML();
@@ -1298,6 +1298,14 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
+ node->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
+ // don't allow negative spacing values
+ layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
+
+ LLString name("stack");
+ node->getAttributeString("name", name);
+
+ layout_stackp->setName(name);
layout_stackp->initFromXML(node, parent);
LLXMLNodePtr child;
@@ -1308,16 +1316,18 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
S32 min_width = 0;
S32 min_height = 0;
BOOL auto_resize = TRUE;
+ BOOL user_resize = TRUE;
child->getAttributeS32("min_width", min_width);
child->getAttributeS32("min_height", min_height);
child->getAttributeBOOL("auto_resize", auto_resize);
+ child->getAttributeBOOL("user_resize", user_resize);
LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
if (panelp)
{
panelp->setFollowsNone();
- layout_stackp->addPanel(panelp, min_width, min_height, auto_resize);
+ layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
}
}
}
@@ -1335,11 +1345,36 @@ S32 LLLayoutStack::getMinHeight()
return mMinHeight;
}
-void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index)
+S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
{
- LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize);
+ // if we are spanning our children (crude upward propagation of size)
+ // then don't enforce our size on our children
+ if (mOrientation == HORIZONTAL)
+ {
+ cur_height = llmax(mMinHeight, mRect.getHeight());
+ }
+
+ return cur_height;
+}
+
+S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
+{
+ // if we are spanning our children (crude upward propagation of size)
+ // then don't enforce our size on our children
+ if (mOrientation == VERTICAL)
+ {
+ cur_width = llmax(mMinWidth, mRect.getWidth());
+ }
+
+ return cur_width;
+}
+
+void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index)
+{
+ LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
+
addChild(panel);
addChild(embedded_panel->mResizeBar);
@@ -1347,29 +1382,15 @@ void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL
// with a bit of overlap
for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
{
- e_panel_list_t::iterator next_it = panel_it;
- ++next_it;
-
LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
sendChildToFront(resize_barp);
- // last resize bar is disabled, since its not between any two panels
- if ( next_it == mPanels.end() )
- {
- resize_barp->setEnabled(FALSE);
- }
- else
- {
- resize_barp->setEnabled(TRUE);
- }
}
- //updateLayout();
}
void LLLayoutStack::removePanel(LLPanel* panel)
{
removeChild(panel);
- //updateLayout();
}
void LLLayoutStack::updateLayout(BOOL force_resize)
@@ -1377,11 +1398,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
calcMinExtents();
// calculate current extents
- S32 cur_width = 0;
- S32 cur_height = 0;
+ S32 total_width = 0;
+ S32 total_height = 0;
const F32 ANIM_OPEN_TIME = 0.02f;
- const F32 ANIM_CLOSE_TIME = 0.02f;
+ const F32 ANIM_CLOSE_TIME = 0.03f;
e_panel_list_t::iterator panel_it;
for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
@@ -1403,23 +1424,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
(*panel_it)->mVisibleAmt = 0.f;
}
}
+
if (mOrientation == HORIZONTAL)
{
- // all panels get expanded to max of all the minimum dimensions
- cur_height = llmax(mMinHeight, panelp->getRect().getHeight());
- cur_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt);
- if (panel_it != mPanels.end())
+ total_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt);
+ // want n-1 panel gaps for n panels
+ if (panel_it != mPanels.begin())
{
- cur_width += PANEL_STACK_GAP;
+ total_width += mPanelSpacing;
}
}
else //VERTICAL
{
- cur_width = llmax(mMinWidth, panelp->getRect().getWidth());
- cur_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt);
- if (panel_it != mPanels.end())
+ total_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt);
+ if (panel_it != mPanels.begin())
{
- cur_height += PANEL_STACK_GAP;
+ total_height += mPanelSpacing;
}
}
}
@@ -1465,11 +1485,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
S32 pixels_to_distribute;
if (mOrientation == HORIZONTAL)
{
- pixels_to_distribute = mRect.getWidth() - cur_width;
+ pixels_to_distribute = mRect.getWidth() - total_width;
}
else //VERTICAL
{
- pixels_to_distribute = mRect.getHeight() - cur_height;
+ pixels_to_distribute = mRect.getHeight() - total_height;
}
S32 cur_x = 0;
@@ -1482,7 +1502,7 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
S32 cur_width = panelp->getRect().getWidth();
S32 cur_height = panelp->getRect().getHeight();
S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
- S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
+ S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
S32 delta_size = 0;
@@ -1502,11 +1522,11 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
// grow all elements equally
delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
}
- new_width = llmax((*panel_it)->mMinWidth, panelp->getRect().getWidth() + delta_size);
+ new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
}
else
{
- new_width = llmax(mMinWidth, mRect.getWidth());
+ new_width = getDefaultWidth(new_width);
}
if (mOrientation == VERTICAL)
@@ -1520,22 +1540,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
{
delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
}
- new_height = llmax((*panel_it)->mMinHeight, panelp->getRect().getHeight() + delta_size);
+ new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
}
else
{
- new_height = llmax(mMinHeight, mRect.getHeight());
+ new_height = getDefaultHeight(new_height);
}
}
- else // don't resize
+ else
{
if (mOrientation == HORIZONTAL)
{
- new_height = llmax(mMinHeight, mRect.getHeight());
+ new_height = getDefaultHeight(new_height);
}
else // VERTICAL
{
- new_width = llmax(mMinWidth, mRect.getWidth());
+ new_width = getDefaultWidth(new_width);
}
}
@@ -1550,22 +1570,22 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
if (mOrientation == HORIZONTAL)
{
resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
- resize_bar_rect.mRight = panel_rect.mRight + PANEL_STACK_GAP + RESIZE_BAR_OVERLAP;
+ resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + RESIZE_BAR_OVERLAP;
}
else
{
resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
- resize_bar_rect.mBottom = panel_rect.mBottom - PANEL_STACK_GAP - RESIZE_BAR_OVERLAP;
+ resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - RESIZE_BAR_OVERLAP;
}
(*panel_it)->mResizeBar->setRect(resize_bar_rect);
if (mOrientation == HORIZONTAL)
{
- cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP;
+ cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + mPanelSpacing;
}
else //VERTICAL
{
- cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP;
+ cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + mPanelSpacing;
}
}
@@ -1577,29 +1597,38 @@ void LLLayoutStack::updateLayout(BOOL force_resize)
if (mOrientation == HORIZONTAL)
{
- (*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinWidth, (*panel_it)->mMinWidth + shrink_headroom_total);
+ (*panel_it)->mResizeBar->setResizeLimits(
+ (*panel_it)->mMinWidth,
+ (*panel_it)->mMinWidth + shrink_headroom_total);
}
else //VERTICAL
{
- (*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinHeight, (*panel_it)->mMinHeight + shrink_headroom_total);
+ (*panel_it)->mResizeBar->setResizeLimits(
+ (*panel_it)->mMinHeight,
+ (*panel_it)->mMinHeight + shrink_headroom_total);
}
- // hide resize bars for invisible panels
- (*panel_it)->mResizeBar->setVisible(panelp->getVisible());
- if (panelp->getVisible())
+
+ // toggle resize bars based on panel visibility, resizability, etc
+ BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
+ (*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
+
+ if (resize_bar_enabled)
{
last_resize_bar = (*panel_it)->mResizeBar;
}
}
// hide last resize bar as there is nothing past it
+ // resize bars need to be in between two resizable panels
if (last_resize_bar)
{
last_resize_bar->setVisible(FALSE);
}
// not enough room to fit existing contents
- if (!force_resize &&
- ((cur_y != -PANEL_STACK_GAP) || (cur_x != mRect.getWidth() + PANEL_STACK_GAP)))
+ if (!force_resize
+ && ((cur_y != -mPanelSpacing)
+ || (cur_x != mRect.getWidth() + mPanelSpacing)))
{
// do another layout pass with all stacked elements contributing
// even those that don't usually resize
@@ -1631,20 +1660,22 @@ void LLLayoutStack::calcMinExtents()
{
if (mOrientation == HORIZONTAL)
{
- mMinHeight = llmax(mMinHeight, (*panel_it)->mMinHeight);
+ mMinHeight = llmax( mMinHeight,
+ (*panel_it)->mMinHeight);
mMinWidth += (*panel_it)->mMinWidth;
if (panel_it != mPanels.begin())
{
- mMinWidth += PANEL_STACK_GAP;
+ mMinWidth += mPanelSpacing;
}
}
else //VERTICAL
{
- mMinWidth = llmax(mMinWidth, (*panel_it)->mMinWidth);
+ mMinWidth = llmax( mMinWidth,
+ (*panel_it)->mMinWidth);
mMinHeight += (*panel_it)->mMinHeight;
if (panel_it != mPanels.begin())
{
- mMinHeight += PANEL_STACK_GAP;
+ mMinHeight += mPanelSpacing;
}
}
}
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 78aa7cfc21..88b4ecb76b 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -173,7 +173,7 @@ public:
// LLUICtrl
void childSetFocus(const LLString& id, BOOL focus = TRUE);
BOOL childHasFocus(const LLString& id);
- void childSetFocusChangedCallback(const LLString& id, void (*cb)(LLUICtrl*, void*));
+ void childSetFocusChangedCallback(const LLString& id, void (*cb)(LLFocusableElement*, void*), void* user_data = NULL);
void childSetCommitCallback(const LLString& id, void (*cb)(LLUICtrl*, void*), void* userdata = NULL );
void childSetDoubleClickCallback(const LLString& id, void (*cb)(void*), void* userdata = NULL );
@@ -277,9 +277,9 @@ public:
virtual ~LLLayoutStack();
/*virtual*/ void draw();
- /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
/*virtual*/ void removeCtrl(LLUICtrl* ctrl);
+
virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_LAYOUT_STACK; }
virtual LLString getWidgetTag() const { return LL_LAYOUT_STACK_TAG; }
@@ -288,7 +288,7 @@ public:
S32 getMinWidth();
S32 getMinHeight();
- void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index = S32_MAX);
+ void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index = S32_MAX);
void removePanel(LLPanel* panel);
void updateLayout(BOOL force_resize = FALSE);
@@ -299,6 +299,8 @@ protected:
void calcMinExtents();
S32 getMinStackSize();
S32 getCurStackSize();
+ S32 getDefaultHeight(S32 cur_height);
+ S32 getDefaultWidth(S32 cur_width);
protected:
eLayoutOrientation mOrientation;
@@ -308,6 +310,7 @@ protected:
S32 mMinWidth;
S32 mMinHeight;
+ S32 mPanelSpacing;
};
#endif
diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp
index 17b76def71..120323e7d1 100644
--- a/indra/llui/llresizehandle.cpp
+++ b/indra/llui/llresizehandle.cpp
@@ -60,7 +60,7 @@ LLResizeHandle::LLResizeHandle( const LLString& name, const LLRect& rect, S32 mi
if( RIGHT_BOTTOM == mCorner)
{
LLUUID image_id(LLUI::sConfigGroup->getString("UIImgResizeBottomRightUUID"));
- mImage = LLUI::sImageProvider->getUIImageByID(image_id);
+ mImage = LLUI::sImageProvider->getImageByID(image_id);
}
switch( mCorner )
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 99908a6bc0..b106bb570d 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -159,30 +159,50 @@ void LLScrollbar::setDocParams( S32 size, S32 pos )
void LLScrollbar::setDocPos(S32 pos)
{
- mDocPos = llclamp( pos, 0, getDocPosMax() );
- mDocChanged = TRUE;
+ if (pos != mDocPos)
+ {
+ mDocPos = llclamp( pos, 0, getDocPosMax() );
+ mDocChanged = TRUE;
- updateThumbRect();
+ updateThumbRect();
+ }
}
void LLScrollbar::setDocSize(S32 size)
{
- mDocSize = size;
- mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
- mDocChanged = TRUE;
+ if (size != mDocSize)
+ {
+ mDocSize = size;
+ mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
+ mDocChanged = TRUE;
- updateThumbRect();
+ updateThumbRect();
+ }
}
void LLScrollbar::setPageSize( S32 page_size )
{
- mPageSize = page_size;
- mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
- mDocChanged = TRUE;
+ if (page_size != mPageSize)
+ {
+ mPageSize = page_size;
+ mDocPos = llclamp( mDocPos, 0, getDocPosMax() );
+ mDocChanged = TRUE;
- updateThumbRect();
+ updateThumbRect();
+ }
+}
+
+BOOL LLScrollbar::isAtBeginning()
+{
+ return mDocPos == 0;
+}
+
+BOOL LLScrollbar::isAtEnd()
+{
+ return mDocPos == getDocPosMax();
}
+
void LLScrollbar::updateThumbRect()
{
// llassert( 0 <= mDocSize );
@@ -479,7 +499,7 @@ void LLScrollbar::draw()
// Draw background and thumb.
LLUUID rounded_rect_image_id;
rounded_rect_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
- LLImageGL* rounded_rect_imagep = LLUI::sImageProvider->getUIImageByID(rounded_rect_image_id);
+ LLImageGL* rounded_rect_imagep = LLUI::sImageProvider->getImageByID(rounded_rect_image_id);
if (!rounded_rect_imagep)
{
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index 353935cfb8..50aa3cafe9 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -88,6 +88,9 @@ public:
void setDocPos( S32 pos );
S32 getDocPos() { return mDocPos; }
+ BOOL isAtBeginning();
+ BOOL isAtEnd();
+
// How many "lines" of the "document" is can appear on a page.
void setPageSize( S32 page_size );
S32 getPageSize() { return mPageSize; }
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index 8b5d009b95..34a29cef51 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -394,33 +394,29 @@ BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect)
{
- if( getVisible() && pointInView(x,y) )
+ S32 local_x, local_y;
+ for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
{
- S32 local_x, local_y;
- for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
+ local_x = x - mScrollbar[i]->getRect().mLeft;
+ local_y = y - mScrollbar[i]->getRect().mBottom;
+ if( mScrollbar[i]->handleToolTip(local_x, local_y, msg, sticky_rect) )
{
- local_x = x - mScrollbar[i]->getRect().mLeft;
- local_y = y - mScrollbar[i]->getRect().mBottom;
- if( mScrollbar[i]->handleToolTip(local_x, local_y, msg, sticky_rect) )
- {
- return TRUE;
- }
+ return TRUE;
}
- // Handle 'child' view.
- if( mScrolledView )
+ }
+ // Handle 'child' view.
+ if( mScrolledView )
+ {
+ local_x = x - mScrolledView->getRect().mLeft;
+ local_y = y - mScrolledView->getRect().mBottom;
+ if( mScrolledView->handleToolTip(local_x, local_y, msg, sticky_rect) )
{
- local_x = x - mScrolledView->getRect().mLeft;
- local_y = y - mScrolledView->getRect().mBottom;
- if( mScrolledView->handleToolTip(local_x, local_y, msg, sticky_rect) )
- {
- return TRUE;
- }
+ return TRUE;
}
-
- // Opaque
- return TRUE;
}
- return FALSE;
+
+ // Opaque
+ return TRUE;
}
void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar )
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 96a739418f..0c81b2da08 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -61,43 +61,55 @@ const S32 LIST_SNAP_PADDING = 5;
// local structures & classes.
struct SortScrollListItem
{
- SortScrollListItem(const S32 sort_col, BOOL sort_ascending)
- {
- mSortCol = sort_col;
- mSortAscending = sort_ascending;
- }
+ SortScrollListItem(const std::vector<std::pair<S32, BOOL> >& sort_orders)
+ : mSortOrders(sort_orders)
+ {}
bool operator()(const LLScrollListItem* i1, const LLScrollListItem* i2)
{
- const LLScrollListCell *cell1;
- const LLScrollListCell *cell2;
-
- cell1 = i1->getColumn(mSortCol);
- cell2 = i2->getColumn(mSortCol);
+ if ( mSortOrders.empty() ) return true;
+
+ const LLScrollListCell *cell1 = NULL;
+ const LLScrollListCell *cell2 = NULL;
- S32 order = 1;
- if (!mSortAscending)
+ sort_order_t::const_reverse_iterator end_it = mSortOrders.rend();
+ sort_order_t::const_reverse_iterator it;
+
+ // sort over all columns in order specified by mSortOrders
+ S32 sort_result = 0;
+ for (it = mSortOrders.rbegin(); it != end_it; ++it)
{
- order = -1;
- }
+ S32 col_idx = it->first;
+ BOOL sort_ascending = it->second;
- BOOL retval = FALSE;
+ cell1 = i1->getColumn(col_idx);
+ cell2 = i2->getColumn(col_idx);
+ // ascending or descending sort for this column?
+ S32 order = 1;
+ if (!sort_ascending)
+ {
+ order = -1;
+ }
- if (cell1 && cell2)
- {
- retval = ((order * LLString::compareDict(cell1->getText(), cell2->getText())) < 0);
+ if (cell1 && cell2)
+ {
+ sort_result = (order * LLString::compareDict(cell1->getValue().asString(), cell2->getValue().asString()));
+ if (sort_result != 0)
+ {
+ // we have a sort order!
+ break;
+ }
+ }
}
- return (retval ? TRUE : FALSE);
+ return sort_result < 0;
}
-protected:
- S32 mSortCol;
- S32 mSortAscending;
+ typedef std::vector<std::pair<S32, BOOL> > sort_order_t;
+ const sort_order_t& mSortOrders;
};
-
//
// LLScrollListIcon
//
@@ -120,6 +132,14 @@ LLScrollListIcon::~LLScrollListIcon()
{
}
+void LLScrollListIcon::setValue(LLSD value)
+{
+ mImageUUID = value.asUUID();
+ // don't use default image specified by LLUUID::null, use no image in that case
+ mIcon = mImageUUID.isNull() ? NULL : LLUI::sImageProvider->getImageByID(value.asUUID());
+}
+
+
void LLScrollListIcon::setColor(const LLColor4& color)
{
mColor = color;
@@ -127,7 +147,10 @@ void LLScrollListIcon::setColor(const LLColor4& color)
void LLScrollListIcon::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
{
- gl_draw_image(0, 0, mIcon, mColor);
+ if (mIcon)
+ {
+ gl_draw_image(0, 0, mIcon, mColor);
+ }
}
//
@@ -158,15 +181,15 @@ LLScrollListCheck::~LLScrollListCheck()
void LLScrollListCheck::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
{
mCheckBox->draw();
-
}
BOOL LLScrollListCheck::handleClick()
{
- if ( mCheckBox->getEnabled() )
+ if (mCheckBox->getEnabled())
{
- LLCheckBoxCtrl::onButtonPress(mCheckBox);
+ mCheckBox->toggle();
}
+ // don't change selection when clicking on embedded checkbox
return TRUE;
}
@@ -213,7 +236,7 @@ LLScrollListText::LLScrollListText( const LLString& text, const LLFontGL* font,
// initialize rounded rect image
if (!mRoundedRectImage)
{
- mRoundedRectImage = LLUI::sImageProvider->getUIImageByID(LLUUID(LLUI::sAssetsGroup->getString("rounded_square.tga")));
+ mRoundedRectImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("rounded_square.tga")));
}
}
@@ -223,6 +246,12 @@ LLScrollListText::~LLScrollListText()
delete mColor;
}
+S32 LLScrollListText::getContentWidth() const
+{
+ return mFont->getWidth(mText.getString());
+}
+
+
void LLScrollListText::setColor(const LLColor4& color)
{
if (!mColor)
@@ -314,31 +343,6 @@ LLScrollListItem::~LLScrollListItem()
std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
}
-BOOL LLScrollListItem::handleClick(S32 x, S32 y, MASK mask)
-{
- BOOL handled = FALSE;
-
- S32 left = 0;
- S32 right = 0;
- S32 width = 0;
-
- std::vector<LLScrollListCell *>::iterator iter = mColumns.begin();
- std::vector<LLScrollListCell *>::iterator end = mColumns.end();
- for ( ; iter != end; ++iter)
- {
- width = (*iter)->getWidth();
- right += width;
- if (left <= x && x < right )
- {
- handled = (*iter)->handleClick();
- break;
- }
-
- left += width;
- }
- return handled;
-}
-
void LLScrollListItem::setNumColumns(S32 columns)
{
S32 prev_columns = mColumns.size();
@@ -375,7 +379,7 @@ LLString LLScrollListItem::getContentsCSV()
S32 count = getNumColumns();
for (S32 i=0; i<count; ++i)
{
- ret += getColumn(i)->getText();
+ ret += getColumn(i)->getValue().asString();
if (i < count-1)
{
ret += ", ";
@@ -387,16 +391,7 @@ LLString LLScrollListItem::getContentsCSV()
void LLScrollListItem::setEnabled(BOOL b)
{
- if (b != mEnabled)
- {
- std::vector<LLScrollListCell *>::iterator iter = mColumns.begin();
- std::vector<LLScrollListCell *>::iterator end = mColumns.end();
- for ( ; iter != end; ++iter)
- {
- (*iter)->setEnabled(b);
- }
- mEnabled = b;
- }
+ mEnabled = b;
}
//---------------------------------------------------------------------------
@@ -424,9 +419,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
mCanSelect(TRUE),
mDisplayColumnHeaders(FALSE),
mCollapseEmptyColumns(FALSE),
- mIsPopup(FALSE),
mMaxItemCount(INT_MAX),
- //mItemCount(0),
+ mMaxContentWidth(0),
mBackgroundVisible( TRUE ),
mDrawStripes(TRUE),
mBgWriteableColor( LLUI::sColorsGroup->getColor( "ScrollBgWriteableColor" ) ),
@@ -443,12 +437,13 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
mOnSortChangedCallback( NULL ),
mHighlightedItem(-1),
mBorder(NULL),
- mDefaultColumn("SIMPLE"),
+ mDefaultColumnName("SIMPLE"),
mSearchColumn(0),
mNumDynamicWidthColumns(0),
mTotalStaticColumnWidth(0),
- mSortColumn(-1),
mSortAscending(TRUE),
+ mSecondarySortColumn(-1),
+ mSecondarySortAscending(TRUE),
mSorted(TRUE),
mDirty(FALSE),
mOriginalSelection(-1),
@@ -457,7 +452,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
mItemListRect.setOriginAndSize(
mBorderThickness + LIST_BORDER_PAD,
mBorderThickness + LIST_BORDER_PAD,
- mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE,
+ mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ),
mRect.getHeight() - 2*( mBorderThickness + LIST_BORDER_PAD ) );
updateLineHeight();
@@ -481,7 +476,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
mScrollbar->setFollowsTop();
mScrollbar->setFollowsBottom();
mScrollbar->setEnabled( TRUE );
- mScrollbar->setVisible( TRUE );
+ // scrollbar is visible only when needed
+ mScrollbar->setVisible(FALSE);
addChild(mScrollbar);
// Border
@@ -539,7 +535,8 @@ void LLScrollListCtrl::clearRows()
mScrollLines = 0;
mLastSelected = NULL;
- updateMaxContentWidth(NULL);
+ calcMaxContentWidth(NULL);
+ updateLayout();
mDirty = FALSE;
}
@@ -620,38 +617,64 @@ std::vector<LLScrollListItem*> LLScrollListCtrl::getAllData() const
return ret;
}
+// returns first matching item
+LLScrollListItem* LLScrollListCtrl::getItem(const LLSD& sd) const
+{
+ LLString string_val = sd.asString();
+
+ item_list::const_iterator iter;
+ for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ {
+ LLScrollListItem* item = *iter;
+ // assumes string representation is good enough for comparison
+ if (item->getValue().asString() == string_val)
+ {
+ return item;
+ }
+ }
+ return NULL;
+}
+
void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
{
- S32 old_height = mRect.getHeight();
LLUICtrl::reshape( width, height, called_from_parent );
- S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
+ updateLayout();
+}
+void LLScrollListCtrl::updateLayout()
+{
+ // reserve room for column headers, if needed
+ S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
mItemListRect.setOriginAndSize(
mBorderThickness + LIST_BORDER_PAD,
mBorderThickness + LIST_BORDER_PAD,
- mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE,
+ mRect.getWidth() - 2*( mBorderThickness + LIST_BORDER_PAD ),
mRect.getHeight() - 2*( mBorderThickness + LIST_BORDER_PAD ) - heading_size );
+ // how many lines of content in a single "page"
mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0;
- if(old_height < height && getScrollPos() == mScrollbar->getDocPosMax())
+ BOOL scrollbar_visible = getItemCount() > mPageLines;
+ if (scrollbar_visible)
{
- setScrollPos(mScrollbar->getDocPosMax());
+ // provide space on the right for scrollbar
+ mItemListRect.mRight = mRect.getWidth() - ( mBorderThickness + LIST_BORDER_PAD ) - SCROLLBAR_SIZE;
}
- mScrollbar->setVisible(mPageLines < getItemCount());
+
+ mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
mScrollbar->setPageSize( mPageLines );
-
+ mScrollbar->setDocSize( getItemCount() );
+ mScrollbar->setVisible(scrollbar_visible);
+
updateColumns();
}
// 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)
+void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height)
{
- S32 height = mLineHeight * (getItemCount() + 1);
- height = llmin( height, max_height );
-
+ S32 height = llmin( getRequiredRect().getHeight(), max_height );
S32 width = mRect.getWidth();
reshape( width, height );
@@ -660,7 +683,10 @@ void LLScrollListCtrl::arrange(S32 max_width, S32 max_height)
LLRect LLScrollListCtrl::getRequiredRect()
{
- S32 height = mLineHeight * (getItemCount() + 1);
+ S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
+ S32 height = (mLineHeight * getItemCount())
+ + (2 * ( mBorderThickness + LIST_BORDER_PAD ))
+ + heading_size;
S32 width = mRect.getWidth();
return LLRect(0, height, width, 0);
@@ -680,15 +706,22 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
break;
case ADD_SORTED:
- if (mSortColumn == -1)
{
- mSortColumn = 0;
- mSortAscending = TRUE;
- }
- mItemList.push_back(item);
- std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
- break;
-
+ // sort by column 0, in ascending order
+ std::vector<sort_column_t> single_sort_column;
+ single_sort_column.push_back(std::make_pair(0, TRUE));
+
+ mItemList.push_back(item);
+ std::stable_sort(
+ mItemList.begin(),
+ mItemList.end(),
+ SortScrollListItem(single_sort_column));
+
+ // ADD_SORTED just sorts by first column...
+ // this might not match user sort criteria, so flag list as being in unsorted state
+ setSorted(FALSE);
+ break;
+ }
case ADD_BOTTOM:
mItemList.push_back(item);
setSorted(FALSE);
@@ -702,33 +735,31 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos )
}
updateLineHeightInsert(item);
- mPageLines = mLineHeight ? mItemListRect.getHeight() / mLineHeight : 0;
- BOOL scrollbar_visible = mPageLines < getItemCount();
-
- if (scrollbar_visible != mScrollbar->getVisible())
- {
- mScrollbar->setVisible(mPageLines < getItemCount());
- updateColumns();
- }
- mScrollbar->setPageSize( mPageLines );
-
- mScrollbar->setDocSize( getItemCount() );
+ calcMaxContentWidth(item);
- updateMaxContentWidth(item);
+ updateLayout();
}
return not_too_big;
}
-void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
+void LLScrollListCtrl::calcMaxContentWidth(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)
+ if (added_item == NULL)
+ {
+ mMaxContentWidth = 0;
+ }
+
+ S32 item_content_width = 0;
+
+ ordered_columns_t::iterator column_itor;
+ for (column_itor = mColumnsIndexed.begin(); column_itor != mColumnsIndexed.end(); ++column_itor)
{
- LLScrollListColumn* column = &column_itor->second;
+ LLScrollListColumn* column = *column_itor;
+ if (!column) continue;
if (!added_item)
{
@@ -740,7 +771,7 @@ void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex);
if (!cellp) continue;
- column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+ column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
}
}
else
@@ -748,9 +779,13 @@ void LLScrollListCtrl::updateMaxContentWidth(LLScrollListItem* added_item)
LLScrollListCell* cellp = added_item->getColumn(column->mIndex);
if (!cellp) continue;
- column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getText()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
+ column->mMaxContentWidth = llmax(LLFontGL::sSansSerifSmall->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
}
+
+ item_content_width += column->mMaxContentWidth;
}
+
+ mMaxContentWidth = llmax(mMaxContentWidth, item_content_width);
}
const S32 SCROLL_LIST_ROW_PAD = 2;
@@ -789,7 +824,6 @@ void LLScrollListCtrl::updateColumns()
mColumnsIndexed.resize(mColumns.size());
std::map<LLString, LLScrollListColumn>::iterator column_itor;
- bool first_dynamic = true;
for (column_itor = mColumns.begin(); column_itor != mColumns.end(); ++column_itor)
{
LLScrollListColumn *column = &column_itor->second;
@@ -801,11 +835,6 @@ void LLScrollListCtrl::updateColumns()
else if (column->mDynamicWidth)
{
new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
- if(first_dynamic)
- {
- first_dynamic = false;
- new_width += (mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE);
- }
}
if (new_width != column->mWidth)
@@ -854,43 +883,38 @@ void LLScrollListCtrl::updateColumns()
}
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->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);
+ S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft);
last_header->reshape(new_width, last_header->getRect().getHeight());
last_header->setVisible(mDisplayColumnHeaders && new_width > 0);
}
-
}
void LLScrollListCtrl::setDisplayHeading(BOOL display)
{
mDisplayColumnHeaders = display;
- updateColumns();
-
- setHeadingHeight(mHeadingHeight);
+ updateLayout();
}
void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
{
mHeadingHeight = heading_height;
- reshape(mRect.getWidth(), mRect.getHeight());
+ updateLayout();
- // Resize
- mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
}
void LLScrollListCtrl::setCollapseEmptyColumns(BOOL collapse)
@@ -934,6 +958,8 @@ BOOL LLScrollListCtrl::selectFirstItem()
BOOL LLScrollListCtrl::selectNthItem( S32 target_index )
{
+ if (mItemList.empty()) return FALSE;
+
// Deselects all other items
BOOL success = FALSE;
S32 index = 0;
@@ -1012,7 +1038,32 @@ void LLScrollListCtrl::deleteSingleItem(S32 target_index)
}
delete itemp;
mItemList.erase(mItemList.begin() + target_index);
- updateMaxContentWidth(NULL);
+ calcMaxContentWidth(NULL);
+}
+
+//FIXME: refactor item deletion
+void LLScrollListCtrl::deleteItems(const LLSD& sd)
+{
+ item_list::iterator iter;
+ for (iter = mItemList.begin(); iter < mItemList.end(); )
+ {
+ LLScrollListItem* itemp = *iter;
+ if (itemp->getValue().asString() == sd.asString())
+ {
+ if (itemp == mLastSelected)
+ {
+ mLastSelected = NULL;
+ }
+ delete itemp;
+ mItemList.erase(iter++);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+
+ calcMaxContentWidth(NULL);
}
void LLScrollListCtrl::deleteSelectedItems()
@@ -1032,7 +1083,7 @@ void LLScrollListCtrl::deleteSelectedItems()
}
}
mLastSelected = NULL;
- updateMaxContentWidth(NULL);
+ calcMaxContentWidth(NULL);
}
void LLScrollListCtrl::highlightNthItem(S32 target_index)
@@ -1108,7 +1159,8 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
if (!getFirstSelected())
{
- selectFirstItem();
+ // select last item
+ selectNthItem(getItemCount() - 1);
}
else
{
@@ -1130,7 +1182,8 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
break;
}
- prev_item = cur_item;
+ // don't allow navigation to disabled elements
+ prev_item = cur_item->getEnabled() ? cur_item : prev_item;
}
}
@@ -1145,32 +1198,34 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
{
+ LLScrollListItem* next_item = NULL;
+
if (!getFirstSelected())
{
selectFirstItem();
}
else
{
- item_list::iterator iter;
- for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ item_list::reverse_iterator iter;
+ for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++)
{
- LLScrollListItem* item = *iter;
- if (item->getSelected())
+ LLScrollListItem* cur_item = *iter;
+
+ if (cur_item->getSelected())
{
- if (++iter != mItemList.end())
+ if (next_item)
{
- LLScrollListItem *next_item = *iter;
- if (next_item)
- {
- selectItem(next_item, !extend_selection);
- }
- else
- {
- reportInvalidInput();
- }
+ selectItem(next_item, !extend_selection);
+ }
+ else
+ {
+ reportInvalidInput();
}
break;
}
+
+ // don't allow navigation to disabled items
+ next_item = cur_item->getEnabled() ? cur_item : next_item;
}
}
@@ -1213,10 +1268,29 @@ LLScrollListItem* LLScrollListCtrl::addSimpleItem(const LLString& item_text, EAd
item->setEnabled(enabled);
item->addColumn( item_text, gResMgr->getRes( LLFONT_SANSSERIF_SMALL ) );
addItem( item, pos );
+
+ // create new column on demand for "simple" items
+ if (mColumns.empty())
+ {
+ LLSD new_column;
+ new_column["name"] = mDefaultColumnName;
+ new_column["label"] = "";
+ new_column["dynamicwidth"] = TRUE;
+ addColumn(new_column);
+ }
}
return item;
}
+LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos)
+{
+ LLSD item;
+ item["enabled"] = FALSE;
+ item["columns"][0]["type"] = "separator";
+ item["columns"][0]["column"] = mDefaultColumnName;
+
+ return addElement(item, pos);
+}
// Selects first enabled item of the given name.
// Returns false if item not found.
@@ -1242,7 +1316,7 @@ BOOL LLScrollListCtrl::selectSimpleItem(const LLString& label, BOOL case_sensiti
{
LLScrollListItem* item = *iter;
// Only select enabled items with matching names
- LLString item_text = item->getColumn(0)->getText();
+ LLString item_text = item->getColumn(0)->getValue().asString();
if (!case_sensitive)
{
LLString::toLower(item_text);
@@ -1288,7 +1362,7 @@ BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL ca
LLScrollListItem* item = *iter;
// Only select enabled items with matching names
LLScrollListCell* cellp = item->getColumn(mSearchColumn);
- BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getText()[0]) : FALSE;
+ BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
if (select)
{
selectItem(item);
@@ -1315,7 +1389,7 @@ BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL ca
{
continue;
}
- LLWString item_label = utf8str_to_wstring(cellp->getText());
+ LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
if (!case_sensitive)
{
LLWString::toLower(item_label);
@@ -1346,14 +1420,14 @@ BOOL LLScrollListCtrl::selectSimpleItemByPrefix(const LLWString& target, BOOL ca
return found;
}
-const LLString& LLScrollListCtrl::getSimpleSelectedItem(S32 column) const
+const LLString LLScrollListCtrl::getSimpleSelectedItem(S32 column) const
{
LLScrollListItem* item;
item = getFirstSelected();
if (item)
{
- return item->getColumn(column)->getText();
+ return item->getColumn(column)->getValue().asString();
}
return LLString::null;
@@ -1384,6 +1458,16 @@ LLScrollListItem* LLScrollListCtrl::addSimpleItem(const LLString& item_text, LLS
item->setEnabled(enabled);
item->addColumn(item_text, gResMgr->getRes(LLFONT_SANSSERIF_SMALL), column_width);
addItem( item, pos );
+
+ // create new column on demand
+ if (mColumns.empty())
+ {
+ LLSD new_column;
+ new_column["name"] = "default_column";
+ new_column["label"] = "";
+ new_column["dynamicwidth"] = TRUE;
+ addColumn(new_column);
+ }
}
return item;
}
@@ -1481,9 +1565,7 @@ void LLScrollListCtrl::drawItems()
LLGLSUIDefault gls_ui;
{
- LLRect clip_rect = mItemListRect;
- if(!mScrollbar->getVisible()) clip_rect.mRight += SCROLLBAR_SIZE;
- LLLocalClipRect clip(clip_rect);
+ LLLocalClipRect clip(mItemListRect);
S32 cur_x = x;
S32 cur_y = y;
@@ -1491,7 +1573,6 @@ void LLScrollListCtrl::drawItems()
mDrewSelected = FALSE;
S32 line = 0;
- LLColor4 color;
S32 max_columns = 0;
item_list::iterator iter;
@@ -1502,7 +1583,7 @@ void LLScrollListCtrl::drawItems()
item_rect.setOriginAndSize(
cur_x,
cur_y,
- mScrollbar->getVisible() ? mItemListRect.getWidth() : mItemListRect.getWidth() + SCROLLBAR_SIZE,
+ mScrollbar->getVisible() ? mItemListRect.getWidth() : mItemListRect.getWidth() + mScrollbar->getRect().getWidth(),
mLineHeight );
//llinfos << item_rect.getWidth() << llendl;
@@ -1514,37 +1595,43 @@ void LLScrollListCtrl::drawItems()
max_columns = llmax(max_columns, item->getNumColumns());
+ LLColor4 fg_color;
LLRect bg_rect = item_rect;
// pad background rectangle to separate it from contents
bg_rect.stretch(LIST_BORDER_PAD, 0);
+ LLColor4 bg_color(0.f, 0.f, 0.f, 0.f);
if( mScrollLines <= line && line < mScrollLines + num_page_lines )
{
if( item->getSelected() && mCanSelect)
{
// Draw background of selected item
- LLGLSNoTexture no_texture;
- glColor4fv(mBgSelectedColor.mV);
- gl_rect_2d( bg_rect );
-
- color = mFgSelectedColor;
+ bg_color = mBgSelectedColor;
+ fg_color = (item->getEnabled() ? mFgSelectedColor : mFgDisabledColor);
}
else if (mHighlightedItem == line && mCanSelect)
{
- LLGLSNoTexture no_texture;
- glColor4fv(mHighlightedColor.mV);
- gl_rect_2d( bg_rect );
- color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
+ bg_color = mHighlightedColor;
+ fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
}
else
{
- color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
if (mDrawStripes && (line%2 == 0) && (max_columns > 1))
{
- LLGLSNoTexture no_texture;
- glColor4fv(mBgStripeColor.mV);
- gl_rect_2d( bg_rect );
+ bg_color = mBgStripeColor;
}
+ fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
+ }
+
+ if (!item->getEnabled())
+ {
+ bg_color = mBgReadOnlyColor;
+ }
+ // draw background rect
+ {
+ LLGLSNoTexture no_texture;
+ glColor4fv(bg_color.mV);
+ gl_rect_2d( bg_rect );
}
S32 line_x = cur_x;
@@ -1553,7 +1640,6 @@ void LLScrollListCtrl::drawItems()
S32 cur_col = 0;
S32 dynamic_width = 0;
S32 dynamic_remainder = 0;
- bool first_dynamic = true;
if(mNumDynamicWidthColumns > 0)
{
dynamic_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
@@ -1563,15 +1649,9 @@ void LLScrollListCtrl::drawItems()
for (LLScrollListCell* cell = item->getColumn(0); cur_col < num_cols; cell = item->getColumn(++cur_col))
{
S32 cell_width = cell->getWidth();
-
if(mColumnsIndexed.size() > (U32)cur_col && mColumnsIndexed[cur_col] && mColumnsIndexed[cur_col]->mDynamicWidth)
{
cell_width = dynamic_width + (--dynamic_remainder ? 1 : 0);
- if(first_dynamic)
- {
- cell_width += mScrollbar->getVisible() ? 0 : SCROLLBAR_SIZE;
- first_dynamic = false;
- }
cell->setWidth(cell_width);
}
// Two ways a cell could be hidden
@@ -1585,7 +1665,7 @@ void LLScrollListCtrl::drawItems()
F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout");
highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f);
- cell->drawToWidth( space_left, color, highlight_color );
+ cell->drawToWidth( space_left, fg_color, highlight_color );
LLUI::popMatrix();
cur_x += cell_width + mColumnPadding;
@@ -1605,6 +1685,12 @@ void LLScrollListCtrl::draw()
{
if( getVisible() )
{
+ // if user specifies sort, make sure it is maintained
+ if (needsSorting() && !isSorted())
+ {
+ sortItems();
+ }
+
if (mNeedsScroll)
{
scrollToShowSelected();
@@ -1645,6 +1731,54 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
return handled;
}
+BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
+{
+ S32 column_index = getColumnIndexFromOffset(x);
+ LLScrollListColumn* columnp = getColumn(column_index);
+
+ if (columnp == NULL) return FALSE;
+
+ BOOL handled = FALSE;
+ // show tooltip for full name of hovered item if it has been truncated
+ LLScrollListItem* hit_item = hitItem(x, y);
+ if (hit_item)
+ {
+ LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
+ if (!hit_cell) return FALSE;
+ S32 cell_required_width = hit_cell->getContentWidth();
+ if (hit_cell
+ && hit_cell->isText()
+ && cell_required_width > columnp->mWidth)
+ {
+
+ S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
+ S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item));
+ LLRect cell_rect;
+ cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->mWidth, mLineHeight);
+ // Convert rect local to screen coordinates
+ localPointToScreen(
+ cell_rect.mLeft, cell_rect.mBottom,
+ &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+ localPointToScreen(
+ cell_rect.mRight, cell_rect.mTop,
+ &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+
+ msg = hit_cell->getValue().asString();
+ handled = TRUE;
+ }
+ }
+
+ // otherwise, look for a tooltip associated with this column
+ LLColumnHeader* headerp = columnp->mHeader;
+ if (headerp && !handled)
+ {
+ headerp->handleToolTip(x, y, msg, sticky_rect_screen);
+ handled = !msg.empty();
+ }
+
+ return handled;
+}
+
BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
if (!mCanSelect) return FALSE;
@@ -1652,6 +1786,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
BOOL selection_changed = FALSE;
LLScrollListItem* hit_item = hitItem(x, y);
+
if( hit_item )
{
if( mAllowMultipleSelection )
@@ -1686,6 +1821,11 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{
selectItem(item, FALSE);
selecting = !selecting;
+ if (hit_item == lastSelected)
+ {
+ // stop selecting now, since we just clicked on our last selected item
+ selecting = FALSE;
+ }
}
if (selecting)
{
@@ -1726,9 +1866,6 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
selectItem(hit_item);
}
- hit_item->handleClick(x - mBorderThickness - LIST_BORDER_PAD,
- 1, mask);
-
selection_changed = mSelectionChanged;
if (mCommitOnSelectionChange)
{
@@ -1750,19 +1887,17 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
{
- BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+ BOOL handled = 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
+ // clear selection changed flag because user is starting a selection operation
mSelectionChanged = FALSE;
- gFocusMgr.setMouseCapture(this);
- selectItemAt(x, y, mask);
- mNeedsScroll = TRUE;
+ handleClick(x, y, mask);
}
return TRUE;
@@ -1798,19 +1933,74 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
//BOOL handled = FALSE;
if(getVisible())
{
- // Offer the click to the children, even if we aren't enabled
- // so the scroll bars will work.
- if (NULL == LLView::childrenHandleDoubleClick(x, y, mask))
+ BOOL handled = handleClick(x, y, mask);
+
+ if (!handled)
{
- if( mCanSelect && mOnDoubleClickCallback )
+ // Offer the click to the children, even if we aren't enabled
+ // so the scroll bars will work.
+ if (NULL == LLView::childrenHandleDoubleClick(x, y, mask))
{
- mOnDoubleClickCallback( mCallbackUserData );
+ if( mCanSelect && mOnDoubleClickCallback )
+ {
+ mOnDoubleClickCallback( mCallbackUserData );
+ }
}
}
}
return TRUE;
}
+BOOL LLScrollListCtrl::handleClick(S32 x, S32 y, MASK mask)
+{
+ // which row was clicked on?
+ LLScrollListItem* hit_item = hitItem(x, y);
+ if (!hit_item) return FALSE;
+
+ // get appropriate cell from that row
+ S32 column_index = getColumnIndexFromOffset(x);
+ LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
+ if (!hit_cell) return FALSE;
+
+ // select item (thus deselecting any currently selected item)
+ // only if item is not already selected
+ if (!hit_item->getSelected())
+ {
+ selectItemAt(x, y, mask);
+ gFocusMgr.setMouseCapture(this);
+ mNeedsScroll = TRUE;
+ }
+
+ if (hit_cell->handleClick())
+ {
+ // propagate value of this cell to other selected items
+ // and commit the respective widgets
+ LLSD item_value = hit_cell->getValue();
+ for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); iter++)
+ {
+ LLScrollListItem* item = *iter;
+ if (item->getSelected())
+ {
+ LLScrollListCell* cellp = item->getColumn(column_index);
+ cellp->setValue(item_value);
+ cellp->onCommit();
+ }
+ }
+ //FIXME: find a better way to signal cell changes
+ onCommit();
+ return TRUE;
+ }
+ else
+ {
+ // treat this as a normal single item selection
+ selectItemAt(x, y, mask);
+ gFocusMgr.setMouseCapture(this);
+ mNeedsScroll = TRUE;
+ // do not stop click processing (click callback, etc)
+ return FALSE;
+ }
+}
+
LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
{
// Excludes disabled items.
@@ -1847,6 +2037,59 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
return hit_item;
}
+S32 LLScrollListCtrl::getColumnIndexFromOffset(S32 x)
+{
+ // which column did we hit?
+ S32 left = 0;
+ S32 right = 0;
+ S32 width = 0;
+ S32 column_index = 0;
+
+ ordered_columns_t::const_iterator iter = mColumnsIndexed.begin();
+ ordered_columns_t::const_iterator end = mColumnsIndexed.end();
+ for ( ; iter != end; ++iter)
+ {
+ width = (*iter)->mWidth + mColumnPadding;
+ right += width;
+ if (left <= x && x < right )
+ {
+ break;
+ }
+
+ // set left for next column as right of current column
+ left = right;
+ column_index++;
+ }
+
+ return llclamp(column_index, 0, getNumColumns() - 1);
+}
+
+
+S32 LLScrollListCtrl::getColumnOffsetFromIndex(S32 index)
+{
+ S32 column_offset = 0;
+ ordered_columns_t::const_iterator iter = mColumnsIndexed.begin();
+ ordered_columns_t::const_iterator end = mColumnsIndexed.end();
+ for ( ; iter != end; ++iter)
+ {
+ if (index-- <= 0)
+ {
+ return column_offset;
+ }
+ column_offset += (*iter)->mWidth + mColumnPadding;
+ }
+
+ // when running off the end, return the rightmost pixel
+ return mItemListRect.mRight;
+}
+
+S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index)
+{
+ S32 row_bottom = ((mItemListRect.mTop - (index - mScrollLines)) * mLineHeight)
+ - mLineHeight;
+ return row_bottom;
+}
+
BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
{
@@ -1860,7 +2103,8 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
mNeedsScroll = TRUE;
}
}
- else if (mCanSelect)
+ else
+ if (mCanSelect)
{
LLScrollListItem* item = hitItem(x, y);
if (item)
@@ -1875,13 +2119,6 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
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;
}
@@ -2082,7 +2319,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_
if (cellp)
{
// Only select enabled items with matching first characters
- LLWString item_label = utf8str_to_wstring(cellp->getText());
+ LLWString item_label = utf8str_to_wstring(cellp->getValue().asString());
if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
{
selectItem(item);
@@ -2176,7 +2413,7 @@ void LLScrollListCtrl::deselectItem(LLScrollListItem* itemp)
LLScrollListCell* cellp = itemp->getColumn(mSearchColumn);
if (cellp)
{
- cellp->highlightText(0, 0);
+ cellp->highlightText(0, 0);
}
mSelectionChanged = TRUE;
}
@@ -2202,38 +2439,52 @@ BOOL LLScrollListCtrl::isSorted()
return mSorted;
}
-// Called by scrollbar
-//static
-void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
+struct SameSortColumn
{
- LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
- self->mScrollLines = new_pos;
-}
+ SameSortColumn(S32 column) : mColumn(column) {}
+ S32 mColumn;
+ bool operator()(std::pair<S32, BOOL> sort_column) { return sort_column.first == mColumn; }
+};
-// First column is column 0
-void LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
+BOOL LLScrollListCtrl::setSort(S32 column, BOOL ascending)
{
- if (!mSorted || mSortColumn != column)
+ sort_column_t new_sort_column(column, ascending);
+
+ if (mSortColumns.empty())
{
- mSortColumn = column;
- std::sort(mItemList.begin(), mItemList.end(), SortScrollListItem(mSortColumn, mSortAscending));
- setSorted(TRUE);
+ mSortColumns.push_back(new_sort_column);
+ return TRUE;
}
+ else
+ {
+ // grab current sort column
+ sort_column_t cur_sort_column = mSortColumns.back();
+
+ // remove any existing sort criterion referencing this column
+ // and add the new one
+ remove_if(mSortColumns.begin(), mSortColumns.end(), SameSortColumn(column));
+ mSortColumns.push_back(new_sort_column);
- // just reverse the list if changing sort order
- if(mSortAscending != ascending)
- {
- std::reverse(mItemList.begin(), mItemList.end());
- mSortAscending = ascending;
+ // did the sort criteria change?
+ return (cur_sort_column != new_sort_column);
}
}
+// Called by scrollbar
+//static
+void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
+{
+ LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
+ self->mScrollLines = new_pos;
+}
+
+
void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
{
if (name.empty())
{
- sortByColumn(mSortColumn, mSortAscending);
+ sortItems();
return;
}
@@ -2244,6 +2495,26 @@ void LLScrollListCtrl::sortByColumn(LLString name, BOOL ascending)
}
}
+// First column is column 0
+void LLScrollListCtrl::sortByColumn(U32 column, BOOL ascending)
+{
+ if (setSort(column, ascending))
+ {
+ sortItems();
+ }
+}
+
+void LLScrollListCtrl::sortItems()
+{
+ // do stable sort to preserve any previous sorts
+ std::stable_sort(
+ mItemList.begin(),
+ mItemList.end(),
+ SortScrollListItem(mSortColumns));
+
+ setSorted(TRUE);
+}
+
S32 LLScrollListCtrl::getScrollPos()
{
return mScrollbar->getDocPos();
@@ -2465,7 +2736,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
LLSD columns;
S32 index = 0;
LLXMLNodePtr child;
- S32 total_static = 0, num_dynamic = 0;
+ S32 total_static = 0;
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
{
if (child->hasName("column"))
@@ -2491,8 +2762,10 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
S32 columnwidth = -1;
child->getAttributeS32("width", columnwidth);
+ LLString tooltip;
+ child->getAttributeString("tool_tip", tooltip);
+
if(!columndynamicwidth) total_static += columnwidth;
- else ++num_dynamic;
F32 columnrelwidth = 0.f;
child->getAttributeF32("relwidth", columnrelwidth);
@@ -2509,10 +2782,11 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
columns[index]["relwidth"] = columnrelwidth;
columns[index]["dynamicwidth"] = columndynamicwidth;
columns[index]["halign"] = (S32)h_align;
+ columns[index]["tool_tip"] = tooltip;
+
index++;
}
}
- scroll_list->setNumDynamicColumns(num_dynamic);
scroll_list->setTotalStaticColumnWidth(total_static);
scroll_list->setColumnHeadings(columns);
@@ -2665,7 +2939,7 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
LLString name = column["name"].asString();
if (mColumns.empty())
{
- mDefaultColumn = 0;
+ mDefaultColumnName = name;
}
// if no column name provided, just use ordinal as name
if (name.empty())
@@ -2691,6 +2965,7 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
}
else if(new_column->mDynamicWidth)
{
+ mNumDynamicWidthColumns++;
new_column->mWidth = (mItemListRect.getWidth() - mTotalStaticColumnWidth) / mNumDynamicWidthColumns;
}
S32 top = mItemListRect.mTop;
@@ -2724,17 +2999,16 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
new_column->mHeader->setLabel(new_column->mLabel);
//new_column->mHeader->setLabel(new_column->mLabel);
}
+
+ new_column->mHeader->setToolTip(column["tool_tip"].asString());
+
//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->mHeader->setTabStop(FALSE);
addChild(new_column->mHeader);
new_column->mHeader->setVisible(mDisplayColumnHeaders);
-
- // Move scroll to front
- removeChild(mScrollbar);
- addChild(mScrollbar);
-
+ sendChildToFront(mScrollbar);
}
}
updateColumns();
@@ -2753,18 +3027,18 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
bool ascending = column->mSortAscending;
- if (column->mSortingColumn != column->mName)
+ if (column->mSortingColumn != column->mName
+ && parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
{
- if (parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
- {
- LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
- column_index = info_redir.mIndex;
- }
+ LLScrollListColumn& info_redir = parent->mColumns[column->mSortingColumn];
+ column_index = info_redir.mIndex;
}
- if (column_index == parent->mSortColumn)
+ // if this column is the primary sort key, reverse the direction
+ sort_column_t cur_sort_column;
+ if (!parent->mSortColumns.empty() && parent->mSortColumns.back().first == column_index)
{
- ascending = !parent->mSortAscending;
+ ascending = !parent->mSortColumns.back().second;
}
parent->sortByColumn(column_index, ascending);
@@ -2777,12 +3051,17 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
std::string LLScrollListCtrl::getSortColumnName()
{
- LLScrollListColumn* column = mSortColumn >= 0 ? mColumnsIndexed[mSortColumn] : NULL;
+ LLScrollListColumn* column = mSortColumns.empty() ? NULL : mColumnsIndexed[mSortColumns.back().first];
if (column) return column->mName;
else return "";
}
+BOOL LLScrollListCtrl::needsSorting()
+{
+ return !mSortColumns.empty();
+}
+
void LLScrollListCtrl::clearColumns()
{
std::map<LLString, LLScrollListColumn>::iterator itor;
@@ -2796,6 +3075,7 @@ void LLScrollListCtrl::clearColumns()
}
}
mColumns.clear();
+ mSortColumns.clear();
}
void LLScrollListCtrl::setColumnLabel(const LLString& column, const LLString& label)
@@ -2851,11 +3131,6 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
{
LLString column = (*itor)["column"].asString();
- if (mColumns.size() == 0)
- {
- mDefaultColumn = 0;
- }
-
LLScrollListColumn* columnp = NULL;
// empty columns strings index by ordinal
@@ -2895,6 +3170,7 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
LLString type = (*itor)["type"].asString();
BOOL has_color = (*itor).has("color");
LLColor4 color = ((*itor)["color"]);
+ BOOL enabled = !(*itor).has("enabled") || (*itor)["enabled"].asBoolean() == true;
const LLFontGL *font = gResMgr->getRes(fontname);
if (!font)
@@ -2906,7 +3182,8 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
if (type == "icon")
{
LLUUID image_id = value.asUUID();
- LLImageGL* icon = LLUI::sImageProvider->getUIImageByID(image_id);
+ // don't use special image with UUID::null, just don't draw an image
+ LLImageGL* icon = image_id.isNull() ? NULL : LLUI::sImageProvider->getImageByID(image_id);
LLScrollListIcon* cell = new LLScrollListIcon(icon, width, image_id);
if (has_color)
{
@@ -2916,8 +3193,10 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
}
else if (type == "checkbox")
{
- LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(value.asString(),
- LLRect(0, 0, width, width), "label");
+ LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl("check",
+ LLRect(0, width, width, 0), " ");
+ ctrl->setEnabled(enabled);
+ ctrl->setValue(value);
LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width);
if (has_color)
{
@@ -3070,18 +3349,12 @@ void LLScrollListCtrl::onFocusReceived()
{
// forget latent selection changes when getting focus
mSelectionChanged = FALSE;
+ LLUICtrl::onFocusReceived();
}
//virtual
void LLScrollListCtrl::onFocusLost()
{
- if (mIsPopup)
- {
- if (getParent())
- {
- getParent()->onFocusLost();
- }
- }
if (hasMouseCapture())
{
gFocusMgr.setMouseCapture(NULL);
@@ -3133,11 +3406,11 @@ void LLColumnHeader::draw()
{
if( getVisible() )
{
- mDrawArrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
+ BOOL draw_arrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && 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")));
+ mButton->setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
+ mArrowImage = mButton->getImageOverlay()->getImage();
//BOOL clip = mRect.mRight > mColumn->mParentCtrl->getItemListRect().getWidth();
//LLGLEnable scissor_test(clip ? GL_SCISSOR_TEST : GL_FALSE);
@@ -3237,11 +3510,11 @@ void LLColumnHeader::showList()
{
if (mColumn->mParentCtrl->getSortAscending())
{
- low_item_text = cell->getText();
+ low_item_text = cell->getValue().asString();
}
else
{
- high_item_text = cell->getText();
+ high_item_text = cell->getValue().asString();
}
}
}
@@ -3254,11 +3527,11 @@ void LLColumnHeader::showList()
{
if (mColumn->mParentCtrl->getSortAscending())
{
- high_item_text = cell->getText();
+ high_item_text = cell->getValue().asString();
}
else
{
- low_item_text = cell->getText();
+ low_item_text = cell->getValue().asString();
}
}
}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index a98a411efa..001e10184b 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -59,14 +59,16 @@ public:
virtual ~LLScrollListCell() {};
virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const = 0; // truncate to given width, if possible
virtual S32 getWidth() const = 0;
+ virtual S32 getContentWidth() const { return 0; }
virtual S32 getHeight() const = 0;
- virtual const LLString& getText() const { return LLString::null; }
- virtual const LLString& getTextLower() const { return LLString::null; }
+ virtual const LLSD getValue() const { return LLString::null; }
+ virtual void setValue(LLSD value) { }
virtual BOOL getVisible() const { return TRUE; }
virtual void setWidth(S32 width) = 0;
virtual void highlightText(S32 offset, S32 num_chars) {}
virtual BOOL isText() = 0;
virtual void setColor(const LLColor4&) = 0;
+ virtual void onCommit() {};
virtual BOOL handleClick() { return FALSE; }
virtual void setEnabled(BOOL enable) { }
@@ -96,20 +98,24 @@ public:
virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const;
virtual S32 getWidth() const { return mWidth; }
+ virtual S32 getContentWidth() const;
virtual void setWidth(S32 width) { mWidth = width; }
virtual S32 getHeight() const { return llround(mFont->getLineHeight()); }
- virtual const LLString& getText() const { return mText.getString(); }
+ virtual const LLSD getValue() const { return LLSD(mText.getString()); }
virtual BOOL getVisible() const { return mVisible; }
virtual void highlightText(S32 offset, S32 num_chars) {mHighlightOffset = offset; mHighlightCount = num_chars;}
- void setText(const LLStringExplicit& text);
+
virtual void setColor(const LLColor4&);
virtual BOOL isText() { return TRUE; }
+ void setText(const LLStringExplicit& text);
+ void setFontStyle(const U8 font_style) { mFontStyle = font_style; }
+
private:
LLUIString mText;
const LLFontGL* mFont;
LLColor4* mColor;
- const U8 mFontStyle;
+ U8 mFontStyle;
LLFontGL::HAlign mFontAlignment;
S32 mWidth;
BOOL mVisible;
@@ -128,16 +134,16 @@ public:
/*virtual*/ ~LLScrollListIcon();
virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const;
virtual S32 getWidth() const { return mWidth; }
- virtual S32 getHeight() const { return mIcon->getHeight(); }
- virtual const LLString& getText() const { return mImageUUID; }
- virtual const LLString& getTextLower() const { return mImageUUID; }
+ virtual S32 getHeight() const { return mIcon ? mIcon->getHeight() : 0; }
+ virtual const LLSD getValue() const { return LLSD(mImageUUID); }
virtual void setWidth(S32 width) { mWidth = width; }
virtual void setColor(const LLColor4&);
virtual BOOL isText() { return FALSE; }
+ virtual void setValue(LLSD value);
private:
LLPointer<LLImageGL> mIcon;
- LLString mImageUUID;
+ LLUUID mImageUUID;
S32 mWidth;
LLColor4 mColor;
};
@@ -151,9 +157,12 @@ public:
virtual S32 getWidth() const { return mWidth; }
virtual S32 getHeight() const { return 0; }
virtual void setWidth(S32 width) { mWidth = width; }
+ virtual const LLSD getValue() const { return mCheckBox->getValue(); }
+ virtual void setValue(LLSD value) { mCheckBox->setValue(value); }
+ virtual void onCommit() { mCheckBox->onCommit(); }
virtual BOOL handleClick();
- virtual void setEnabled(BOOL enable) { if (mCheckBox) mCheckBox->setEnabled(enable); }
+ virtual void setEnabled(BOOL enable) { mCheckBox->setEnabled(enable); }
virtual void setColor(const LLColor4& color) {};
LLCheckBoxCtrl* getCheckBox() { return mCheckBox; }
@@ -266,6 +275,7 @@ public:
/*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);
@@ -333,8 +343,6 @@ public:
LLScrollListCell *getColumn(const S32 i) const { if (0 <= i && i < (S32)mColumns.size()) { return mColumns[i]; } return NULL; }
- virtual BOOL handleClick(S32 x, S32 y, MASK mask);
-
LLString getContentsCSV();
private:
@@ -370,9 +378,8 @@ public:
void deleteAllItems() { clearRows(); }
// Sets an array of column descriptors
- void setColumnHeadings(LLSD headings);
- // Numerical based sort by column function (used by LLComboBox)
- void sortByColumn(U32 column, BOOL ascending);
+ void setColumnHeadings(LLSD headings);
+ void sortByColumn(U32 column, BOOL ascending);
// LLCtrlListInterface functions
virtual S32 getItemCount() const;
@@ -421,18 +428,20 @@ public:
BOOL isSorted();
virtual BOOL isSelected(LLSD value);
-
+
+ BOOL handleClick(S32 x, S32 y, MASK mask);
BOOL selectFirstItem();
BOOL selectNthItem( S32 index );
BOOL selectItemAt(S32 x, S32 y, MASK mask);
- void deleteSingleItem( S32 index ) ;
+ void deleteSingleItem( S32 index );
+ void deleteItems(const LLSD& sd);
void deleteSelectedItems();
void deselectAllItems(BOOL no_commit_on_change = FALSE); // by default, go ahead and commit on selection change
void highlightNthItem( S32 index );
void setDoubleClickCallback( void (*cb)(void*) ) { mOnDoubleClickCallback = cb; }
- void setMaxiumumSelectCallback( void (*cb)(void*) ) { mOnMaximumSelectCallback = cb; }
+ void setMaximumSelectCallback( void (*cb)(void*) ) { mOnMaximumSelectCallback = cb; }
void setSortChangedCallback( void (*cb)(void*) ) { mOnSortChangedCallback = cb; }
void swapWithNext(S32 index);
@@ -449,11 +458,12 @@ public:
LLScrollListItem* addSimpleItem( const LLString& item_text, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE );
// Add an item with an associated LLSD
LLScrollListItem* addSimpleItem(const LLString& item_text, LLSD sd, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE, S32 column_width = 0 );
+ LLScrollListItem* addSeparator(EAddPosition pos);
BOOL selectSimpleItem( const LLString& item, BOOL case_sensitive = TRUE ); // FALSE if item not found
BOOL selectSimpleItemByPrefix(const LLString& target, BOOL case_sensitive);
BOOL selectSimpleItemByPrefix(const LLWString& target, BOOL case_sensitive);
- const LLString& getSimpleSelectedItem(S32 column = 0) const;
+ const LLString getSimpleSelectedItem(S32 column = 0) const;
LLSD getSimpleSelectedValue();
// DEPRECATED: Use LLSD versions of addSimpleItem() and getSimpleSelectedValue().
@@ -472,6 +482,8 @@ public:
LLScrollListItem* getFirstData() const;
LLScrollListItem* getLastData() const;
std::vector<LLScrollListItem*> getAllData() const;
+
+ LLScrollListItem* getItem(const LLSD& sd) const;
void setAllowMultipleSelection(BOOL mult ) { mAllowMultipleSelection = mult; }
@@ -501,28 +513,34 @@ public:
S32 getSearchColumn() { return mSearchColumn; }
void setSearchColumn(S32 column) { mSearchColumn = column; }
+ S32 getColumnIndexFromOffset(S32 x);
+ S32 getColumnOffsetFromIndex(S32 index);
+ S32 getRowOffsetFromIndex(S32 index);
void clearSearchString() { mSearchString.clear(); }
// 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);
- virtual BOOL handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
- 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 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);
+ /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
+ /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
+ /*virtual*/ BOOL handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect);
+ /*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);
virtual BOOL isDirty() const;
virtual void resetDirty(); // Clear dirty state
- virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
- virtual void arrange(S32 max_width, S32 max_height);
+ virtual void updateLayout();
+ virtual void fitContents(S32 max_width, S32 max_height);
+
virtual LLRect getRequiredRect();
static BOOL rowPreceeds(LLScrollListItem *new_row, LLScrollListItem *test_row);
@@ -534,12 +552,12 @@ public:
static void onClickColumn(void *userdata);
void updateColumns();
- void updateMaxContentWidth(LLScrollListItem* changed_item);
+ void calcMaxContentWidth(LLScrollListItem* changed_item);
+ S32 getMaxContentWidth() { return mMaxContentWidth; }
void setDisplayHeading(BOOL display);
void setHeadingHeight(S32 heading_height);
void setCollapseEmptyColumns(BOOL collapse);
- void setIsPopup(BOOL is_popup) { mIsPopup = is_popup; }
LLScrollListItem* hitItem(S32 x,S32 y);
virtual void scrollToShowSelected();
@@ -564,9 +582,11 @@ public:
void setTotalStaticColumnWidth(int width) { mTotalStaticColumnWidth = width; }
std::string getSortColumnName();
- BOOL getSortAscending() { return mSortAscending; }
+ BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
+ BOOL needsSorting();
S32 selectMultiple( LLDynamicArray<LLUUID> ids );
+ void sortItems();
protected:
// "Full" interface: use this when you're creating a list that has one or more of the following:
@@ -596,6 +616,7 @@ protected:
void deselectItem(LLScrollListItem* itemp);
void commitIfChanged();
void setSorted(BOOL sorted);
+ BOOL setSort(S32 column, BOOL ascending);
protected:
S32 mCurIndex; // For get[First/Next]Data
@@ -616,7 +637,6 @@ protected:
BOOL mCanSelect;
BOOL mDisplayColumnHeaders;
BOOL mCollapseEmptyColumns;
- BOOL mIsPopup;
typedef std::deque<LLScrollListItem *> item_list;
item_list mItemList;
@@ -626,7 +646,7 @@ protected:
S32 mMaxItemCount;
LLRect mItemListRect;
-
+ S32 mMaxContentWidth;
S32 mColumnPadding;
BOOL mBackgroundVisible;
@@ -652,22 +672,29 @@ protected:
LLWString mSearchString;
LLFrameTimer mSearchTimer;
- LLString mDefaultColumn;
+ LLString mDefaultColumnName;
S32 mSearchColumn;
S32 mNumDynamicWidthColumns;
S32 mTotalStaticColumnWidth;
S32 mSortColumn;
+ S32 mSecondarySortColumn;
+ BOOL mSecondarySortAscending;
BOOL mSortAscending;
BOOL mSorted;
-
+
std::map<LLString, LLScrollListColumn> mColumns;
- std::vector<LLScrollListColumn*> mColumnsIndexed;
BOOL mDirty;
S32 mOriginalSelection;
+ typedef std::vector<LLScrollListColumn*> ordered_columns_t;
+ ordered_columns_t mColumnsIndexed;
+
+ typedef std::pair<S32, BOOL> sort_column_t;
+ std::vector<sort_column_t> mSortColumns;
+
public:
// HACK: Did we draw one selected item this frame?
BOOL mDrewSelected;
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index 29626c25d6..bd91d562aa 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -41,9 +41,6 @@
#include "llcontrol.h"
#include "llimagegl.h"
-const S32 THUMB_WIDTH = 8;
-const S32 TRACK_HEIGHT = 6;
-
LLSlider::LLSlider(
const LLString& name,
const LLRect& rect,
@@ -65,20 +62,24 @@ LLSlider::LLSlider(
mIncrement( increment ),
mVolumeSlider( volume ),
mMouseOffset( 0 ),
- mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
- mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
mThumbCenterColor( LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
- mDisabledThumbColor(LLUI::sColorsGroup->getColor( "SliderDisabledThumbColor" ) ),
mMouseDownCallback( NULL ),
mMouseUpCallback( NULL )
{
+ mThumbImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("icn_slide-thumb_dark.tga")));
+ mTrackImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("icn_slide-groove_dark.tga")));
+ mTrackHighlightImage = LLUI::sImageProvider->getImageByID(LLUUID(LLUI::sAssetsGroup->getString("icn_slide-highlight.tga")));
+
// properly handle setting the starting thumb rect
// do it this way to handle both the operating-on-settings
// and standalone ways of using this
setControlName(control_name, NULL);
setValue(getValueF32());
+
+ updateThumbRect();
+ mDragStartThumbRect = mThumbRect;
}
EWidgetType LLSlider::getWidgetType() const
@@ -107,17 +108,26 @@ void LLSlider::setValue(F32 value, BOOL from_event)
}
mValue = value;
+ updateThumbRect();
+}
+void LLSlider::updateThumbRect()
+{
F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
- S32 left_edge = THUMB_WIDTH/2;
- S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
+ S32 thumb_width = mThumbImage->getWidth();
+ S32 thumb_height = mThumbImage->getHeight();
+ S32 left_edge = (thumb_width / 2);
+ S32 right_edge = mRect.getWidth() - (thumb_width / 2);
S32 x = left_edge + S32( t * (right_edge - left_edge) );
- mThumbRect.mLeft = x - (THUMB_WIDTH/2);
- mThumbRect.mRight = x + (THUMB_WIDTH/2);
+ mThumbRect.mLeft = x - (thumb_width / 2);
+ mThumbRect.mRight = mThumbRect.mLeft + thumb_width;
+ mThumbRect.mBottom = getLocalRect().getCenterY() - (thumb_height / 2);
+ mThumbRect.mTop = mThumbRect.mBottom + thumb_height;
}
+
void LLSlider::setValueAndCommit(F32 value)
{
F32 old_value = mValue;
@@ -139,8 +149,9 @@ BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
{
if( hasMouseCapture() )
{
- S32 left_edge = THUMB_WIDTH/2;
- S32 right_edge = mRect.getWidth() - (THUMB_WIDTH/2);
+ S32 thumb_half_width = mThumbImage->getWidth()/2;
+ S32 left_edge = thumb_half_width;
+ S32 right_edge = mRect.getWidth() - (thumb_half_width);
x += mMouseOffset;
x = llclamp( x, left_edge, right_edge );
@@ -203,7 +214,7 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
// Find the offset of the actual mouse location from the center of the thumb.
if (mThumbRect.pointInRect(x,y))
{
- mMouseOffset = (mThumbRect.mLeft + THUMB_WIDTH/2) - x;
+ mMouseOffset = (mThumbRect.mLeft + mThumbImage->getWidth()/2) - x;
}
else
{
@@ -251,6 +262,9 @@ void LLSlider::draw()
{
if( getVisible() )
{
+ // since thumb image might still be decoding, need thumb to accomodate image size
+ updateThumbRect();
+
// Draw background and thumb.
// drawing solids requires texturing be disabled
@@ -260,104 +274,37 @@ void LLSlider::draw()
F32 opacity = mEnabled ? 1.f : 0.3f;
LLColor4 center_color = (mThumbCenterColor % opacity);
- LLColor4 outline_color = (mThumbOutlineColor % opacity);
LLColor4 track_color = (mTrackColor % opacity);
- LLImageGL* thumb_imagep = NULL;
-
// Track
- if (mVolumeSlider)
- {
- LLRect track(0, mRect.getHeight(), mRect.getWidth(), 0);
-
- track.mBottom += 3;
- track.mTop -= 1;
- track.mRight -= 1;
-
- gl_triangle_2d(track.mLeft, track.mBottom,
- track.mRight, track.mBottom,
- track.mRight, track.mTop,
- center_color,
- TRUE);
- gl_triangle_2d(track.mLeft, track.mBottom,
- track.mRight, track.mBottom,
- track.mRight, track.mTop,
- outline_color,
- FALSE);
- }
- else
- {
- LLUUID thumb_image_id;
- thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
- thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id);
+ LLRect track_rect(mThumbImage->getWidth() / 2,
+ getLocalRect().getCenterY() + (mTrackImage->getHeight() / 2),
+ mRect.getWidth() - mThumbImage->getWidth() / 2,
+ getLocalRect().getCenterY() - (mTrackImage->getHeight() / 2) );
- S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2;
- LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset );
+ gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 3, 3, track_rect.getWidth(), track_rect.getHeight(),
+ mTrackImage, track_color);
+ gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 3, 3, mThumbRect.mLeft, track_rect.getHeight(),
+ mTrackHighlightImage, track_color);
- track_rect.stretch(-1);
- gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(),
- thumb_imagep, track_color);
- }
// Thumb
- if (!thumb_imagep)
- {
- if (mVolumeSlider)
- {
- if (hasMouseCapture())
- {
- LLRect rect(mDragStartThumbRect);
- gl_rect_2d( rect, outline_color );
- rect.stretch(-1);
- gl_rect_2d( rect, mThumbCenterColor % 0.3f );
-
- if (hasFocus())
- {
- LLRect thumb_rect = mThumbRect;
- thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())));
- gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor());
- }
- gl_rect_2d( mThumbRect, mThumbOutlineColor );
- }
- else
- {
- if (hasFocus())
- {
- LLRect thumb_rect = mThumbRect;
- thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())));
- gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor());
- }
- LLRect rect(mThumbRect);
- gl_rect_2d(rect, outline_color);
- rect.stretch(-1);
- gl_rect_2d( rect, center_color);
- }
- }
- else
- {
- gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE);
- if (hasMouseCapture())
- {
- gl_rect_2d(mDragStartThumbRect, center_color, FALSE);
- }
- }
- }
- else if( hasMouseCapture() )
+ if( hasMouseCapture() )
{
- gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(),
- thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
+ gl_draw_scaled_image(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(),
+ mThumbImage, mThumbCenterColor % 0.3f);
if (hasFocus())
{
F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
LLRect highlight_rect = mThumbRect;
highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
- gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
- thumb_imagep, gFocusMgr.getFocusColor());
+ gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 0, 0, highlight_rect.getWidth(), highlight_rect.getHeight(),
+ mThumbImage, gFocusMgr.getFocusColor(), TRUE);
}
- gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
- thumb_imagep, mThumbOutlineColor, TRUE);
+ gl_draw_scaled_image(mThumbRect.mLeft, mThumbRect.mBottom, mThumbRect.getWidth(), mThumbRect.getHeight(),
+ mThumbImage, mThumbOutlineColor);
}
else
@@ -367,12 +314,12 @@ void LLSlider::draw()
F32 lerp_amt = gFocusMgr.getFocusFlashAmt();
LLRect highlight_rect = mThumbRect;
highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
- gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
- thumb_imagep, gFocusMgr.getFocusColor());
+ gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 0, 0, highlight_rect.getWidth(), highlight_rect.getHeight(),
+ mThumbImage, gFocusMgr.getFocusColor(), TRUE);
}
- gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
- thumb_imagep, center_color, TRUE);
+ gl_draw_scaled_image(mThumbRect.mLeft, mThumbRect.mBottom, mThumbRect.getWidth(), mThumbRect.getHeight(),
+ mThumbImage, center_color);
}
LLUICtrl::draw();
}
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 2641eaac74..55be2afbcc 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -36,6 +36,7 @@
#include "v4color.h"
class LLUICtrlFactory;
+class LLImageGL;
class LLSlider : public LLUICtrl
{
@@ -85,6 +86,7 @@ public:
protected:
void setValueAndCommit(F32 value);
+ void updateThumbRect();
protected:
F32 mValue;
@@ -97,11 +99,14 @@ protected:
S32 mMouseOffset;
LLRect mDragStartThumbRect;
+ LLImageGL* mThumbImage;
+ LLImageGL* mTrackImage;
+ LLImageGL* mTrackHighlightImage;
+
LLRect mThumbRect;
LLColor4 mTrackColor;
LLColor4 mThumbOutlineColor;
LLColor4 mThumbCenterColor;
- LLColor4 mDisabledThumbColor;
void (*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
void (*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index dd4a9941c5..3ff3a4f884 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -125,7 +125,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect,
&LLLineEditor::prevalidateFloat );
mEditor->setFollowsLeft();
mEditor->setFollowsBottom();
- mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus );
+ mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this );
mEditor->setIgnoreTab(TRUE);
// don't do this, as selecting the entire text is single clicking in some cases
// and double clicking in others
@@ -150,7 +150,7 @@ LLSliderCtrl::~LLSliderCtrl()
}
// static
-void LLSliderCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata )
+void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
{
LLSliderCtrl* self = (LLSliderCtrl*) userdata;
llassert( caller == self->mEditor );
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index fa6c0bccae..de1c09639c 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -117,7 +117,7 @@ public:
static void onSliderMouseUp(LLUICtrl* caller,void* userdata);
static void onEditorCommit(LLUICtrl* caller, void* userdata);
- static void onEditorGainFocus(LLUICtrl* caller, void *userdata);
+ static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
private:
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 2be2814080..c4b7de768a 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -128,7 +128,7 @@ LLSpinCtrl::LLSpinCtrl( const LLString& name, const LLRect& rect, const LLString
&LLLineEditor::prevalidateFloat );
mEditor->setFollowsLeft();
mEditor->setFollowsBottom();
- mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus );
+ mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this );
//RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
// than when it doesn't. Instead, if you always have to double click to select all the text,
// it's easier to understand
@@ -137,7 +137,7 @@ LLSpinCtrl::LLSpinCtrl( const LLString& name, const LLRect& rect, const LLString
addChild(mEditor);
updateEditor();
- setSpanChildren( TRUE );
+ setUseBoundingRect( TRUE );
}
LLSpinCtrl::~LLSpinCtrl()
@@ -230,7 +230,7 @@ void LLSpinCtrl::onDownBtn( void *userdata )
}
// static
-void LLSpinCtrl::onEditorGainFocus( LLUICtrl* caller, void *userdata )
+void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
{
LLSpinCtrl* self = (LLSpinCtrl*) userdata;
llassert( caller == self->mEditor );
diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h
index f2c7b40cfe..5fc3ccdcc1 100644
--- a/indra/llui/llspinctrl.h
+++ b/indra/llui/llspinctrl.h
@@ -113,7 +113,7 @@ public:
virtual void draw();
static void onEditorCommit(LLUICtrl* caller, void* userdata);
- static void onEditorGainFocus(LLUICtrl* caller, void *userdata);
+ static void onEditorGainFocus(LLFocusableElement* caller, void *userdata);
static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
static void onUpBtn(void *userdata);
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index 1f932f758c..2d3534e7be 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -230,7 +230,7 @@ void LLStyle::setImage(const LLString& src)
}
else
{
- mImagep = LLUI::sImageProvider->getUIImageByID(LLUUID(src));
+ mImagep = LLUI::sImageProvider->getImageByID(LLUUID(src));
}
}
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 1ab11f3644..148060359f 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -156,7 +156,12 @@ void LLTabContainerCommon::lockTabs(S32 num_tabs)
{
// count current tabs or use supplied value and ensure no new tabs get
// inserted between them
- mLockedTabCount = num_tabs > 0 ? num_tabs : getTabCount();
+ mLockedTabCount = num_tabs > 0 ? llmin(getTabCount(), num_tabs) : getTabCount();
+}
+
+void LLTabContainerCommon::unlockTabs()
+{
+ mLockedTabCount = 0;
}
void LLTabContainerCommon::removeTabPanel(LLPanel* child)
@@ -557,7 +562,7 @@ void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name, con
}
void LLTabContainerCommon::setTitle(const LLString& title)
-{
+{
if (mTitleBox)
{
mTitleBox->setText( title );
@@ -721,6 +726,14 @@ void LLTabContainerCommon::insertTuple(LLTabTuple * tuple, eInsertionPoint inser
// insert the new tab in the front of the list
mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
break;
+ case LEFT_OF_CURRENT:
+ // insert the new tab before the current tab (but not before mLockedTabCount)
+ {
+ tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx);
+ mTabList.insert(current_iter, tuple);
+ }
+ break;
+
case RIGHT_OF_CURRENT:
// insert the new tab after the current tab (but not before mLockedTabCount)
{
@@ -946,14 +959,14 @@ void LLTabContainer::addTabPanel(LLPanel* child,
if( LLTabContainer::TOP == mTabPosition )
{
btn_rect.setLeftTopAndSize( 0, mRect.getHeight() - mTopBorderHeight + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
- tab_img = "UIImgBtnTabTopOutUUID";
- tab_selected_img = "UIImgBtnTabTopInUUID";
+ tab_img = "tab_top_blue.tga";
+ tab_selected_img = "tab_top_selected_blue.tga";
}
else
{
btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
- tab_img = "UIImgBtnTabBottomOutUUID";
- tab_selected_img = "UIImgBtnTabBottomInUUID";
+ tab_img = "tab_bottom_blue.tga";
+ tab_selected_img = "tab_bottom_selected_blue.tga";
}
if (placeholder)
@@ -979,7 +992,7 @@ void LLTabContainer::addTabPanel(LLPanel* child,
LLButton* btn = new LLButton(
LLString(child->getName()) + " tab",
btn_rect,
- tab_img, tab_selected_img, "",
+ "", "", "",
&LLTabContainer::onTabBtn, NULL, // set userdata below
font,
trimmed_label, trimmed_label );
@@ -987,7 +1000,7 @@ void LLTabContainer::addTabPanel(LLPanel* child,
btn->setVisible( FALSE );
btn->setToolTip( tooltip );
btn->setScaleImage(TRUE);
- btn->setFixedBorder(14, 14);
+ btn->setImages(tab_img, tab_selected_img);
// Try to squeeze in a bit more text
btn->setLeftHPad( 4 );
@@ -1139,7 +1152,7 @@ BOOL LLTabContainer::selectTab(S32 which)
//if( gFocusMgr.childHasKeyboardFocus( this ) )
//{
- // gFocusMgr.setKeyboardFocus( NULL, NULL );
+ // gFocusMgr.setKeyboardFocus( NULL );
//}
LLTabTuple* selected_tuple = mTabList[which];
@@ -1370,7 +1383,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
{
LLButton* tab_button = mTabList[getCurrentPanelIndex()]->mButton;
gFocusMgr.setMouseCapture(this);
- gFocusMgr.setKeyboardFocus(tab_button, NULL);
+ gFocusMgr.setKeyboardFocus(tab_button);
}
}
return handled;
@@ -1475,7 +1488,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
BOOL LLTabContainer::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect )
{
BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect );
- if (!handled && mTabList.size() > 0 && getVisible() && pointInView( x, y ) )
+ if (!handled && mTabList.size() > 0)
{
LLTabTuple* firsttuple = mTabList[0];
@@ -1645,12 +1658,12 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L
mTotalTabWidth -= tuple->mButton->getRect().getWidth();
S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
- tuple->mButton->getImageOverlay()->getWidth(0) :
+ tuple->mButton->getImageOverlay()->getImage()->getWidth(0) :
0;
tuple->mPadding = image_overlay_width;
- tuple->mButton->setRightHPad(tuple->mPadding + LLBUTTON_H_PAD);
+ tuple->mButton->setRightHPad(6);
tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
tuple->mButton->getRect().getHeight());
// add back in button width to total tab strip width
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index c77547a771..b72ecb8126 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -54,6 +54,7 @@ public:
{
START,
END,
+ LEFT_OF_CURRENT,
RIGHT_OF_CURRENT
} eInsertionPoint;
@@ -91,6 +92,8 @@ public:
eInsertionPoint insertion_point = END) = 0;
virtual void addPlaceholder(LLPanel* child, const LLString& label);
virtual void lockTabs(S32 num_tabs = 0);
+ virtual void unlockTabs();
+ S32 getNumLockedTabs() { return mLockedTabCount; }
virtual void enableTabButton(S32 which, BOOL enable);
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 8bd7b1509f..3b15e3a25f 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -56,6 +56,7 @@ LLTextBox::LLTextBox(const LLString& name, const LLRect& rect, const LLString& t
mBorderVisible( FALSE ),
mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
mBorderDropShadowVisible( FALSE ),
+ mUseEllipses( FALSE ),
mHPad(0),
mVPad(0),
mHAlign( LLFontGL::LEFT ),
@@ -84,6 +85,7 @@ LLTextBox::LLTextBox(const LLString& name, const LLString& text, F32 max_width,
mBorderVisible(FALSE),
mFontStyle(LLFontGL::DROP_SHADOW_SOFT),
mBorderDropShadowVisible(FALSE),
+ mUseEllipses( FALSE ),
mHPad(0),
mVPad(0),
mHAlign(LLFontGL::LEFT),
@@ -393,7 +395,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color,
mHAlign, mVAlign,
mFontStyle,
- line_length, mRect.getWidth(), NULL, TRUE );
+ line_length, mRect.getWidth(), NULL, TRUE, mUseEllipses );
cur_pos += line_length + 1;
y -= llfloor(mFontGL->getLineHeight());
}
@@ -403,7 +405,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color,
mHAlign, mVAlign,
mFontStyle,
- S32_MAX, mRect.getWidth(), NULL, TRUE);
+ S32_MAX, mRect.getWidth(), NULL, TRUE, mUseEllipses);
}
}
@@ -481,7 +483,7 @@ LLView* LLTextBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
text_box->mFontStyle = LLFontGL::getStyleFromString(font_style);
}
- BOOL mouse_opaque;
+ BOOL mouse_opaque = text_box->getMouseOpaque();
if (node->getAttributeBOOL("mouse_opaque", mouse_opaque))
{
text_box->setMouseOpaque(mouse_opaque);
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index c7c79464a0..d25452b941 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -79,6 +79,7 @@ public:
void setText( const LLStringExplicit& text );
void setWrappedText(const LLStringExplicit& text, F32 max_width = -1.0);
// default width means use existing control width
+ void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; }
void setBackgroundVisible(BOOL visible) { mBackgroundVisible = visible; }
void setBorderVisible(BOOL visible) { mBorderVisible = visible; }
@@ -124,6 +125,7 @@ protected:
U8 mFontStyle; // style bit flags for font
BOOL mBorderDropShadowVisible;
+ BOOL mUseEllipses;
S32 mHPad;
S32 mVPad;
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 5c8b7c7281..8b9353eb8e 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -310,9 +310,9 @@ LLTextEditor::LLTextEditor(
mWordWrap( FALSE ),
mTabToNextField( TRUE ),
mCommitOnFocusLost( FALSE ),
- mTakesFocus( TRUE ),
mHideScrollbarForShortDocs( FALSE ),
mTakesNonScrollClicks( TRUE ),
+ mTrackBottom( TRUE ),
mAllowEmbeddedItems( allow_embedded_items ),
mAcceptCallingCardNames(FALSE),
mHandleEditKeysDirectly( FALSE ),
@@ -1141,46 +1141,42 @@ void LLTextEditor::selectAll()
BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
{
- if (pointInView(x, y) && getVisible())
+ for ( child_list_const_iter_t child_it = getChildList()->begin();
+ child_it != getChildList()->end(); ++child_it)
{
- for ( child_list_const_iter_t child_it = getChildList()->begin();
- child_it != getChildList()->end(); ++child_it)
- {
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->getRect().mLeft;
- S32 local_y = y - viewp->getRect().mBottom;
- if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
- {
- return TRUE;
- }
- }
-
- if( mSegments.empty() )
+ LLView* viewp = *child_it;
+ S32 local_x = x - viewp->getRect().mLeft;
+ S32 local_y = y - viewp->getRect().mBottom;
+ if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
{
return TRUE;
}
+ }
- LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
- if( cur_segment )
- {
- BOOL has_tool_tip = FALSE;
- has_tool_tip = cur_segment->getToolTip( msg );
+ if( mSegments.empty() )
+ {
+ return TRUE;
+ }
- if( has_tool_tip )
- {
- // Just use a slop area around the cursor
- // Convert rect local to screen coordinates
- S32 SLOP = 8;
- localPointToScreen(
- x - SLOP, y - SLOP,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
- sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
- }
+ LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
+ if( cur_segment )
+ {
+ BOOL has_tool_tip = FALSE;
+ has_tool_tip = cur_segment->getToolTip( msg );
+
+ if( has_tool_tip )
+ {
+ // Just use a slop area around the cursor
+ // Convert rect local to screen coordinates
+ S32 SLOP = 8;
+ localPointToScreen(
+ x - SLOP, y - SLOP,
+ &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+ sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
+ sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
}
- return TRUE;
}
- return FALSE;
+ return TRUE;
}
BOOL LLTextEditor::handleScrollWheel(S32 x, S32 y, S32 clicks)
@@ -1263,7 +1259,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
handled = TRUE;
}
- if (mTakesFocus)
+ if (hasTabStop())
{
setFocus( TRUE );
handled = TRUE;
@@ -1436,11 +1432,6 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
if( !handled && mTakesNonScrollClicks)
{
- if (mTakesFocus)
- {
- setFocus( TRUE );
- }
-
setCursorAtLocalPos( x, y, FALSE );
deselect();
@@ -3160,6 +3151,9 @@ void LLTextEditor::draw()
}
LLView::draw(); // Draw children (scrollbar and border)
}
+
+ // remember if we are supposed to be at the bottom of the buffer
+ mScrolledToBottom = isScrolledToBottom();
}
void LLTextEditor::reportBadKeystroke()
@@ -3328,6 +3322,17 @@ void LLTextEditor::changeLine( S32 delta )
unbindEmbeddedChars( mGLFont );
}
+BOOL LLTextEditor::isScrolledToTop()
+{
+ return mScrollbar->isAtBeginning();
+}
+
+BOOL LLTextEditor::isScrolledToBottom()
+{
+ return mScrollbar->isAtEnd();
+}
+
+
void LLTextEditor::startOfLine()
{
S32 line, offset;
@@ -3448,6 +3453,13 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
{
LLView::reshape( width, height, called_from_parent );
+ // if scrolled to bottom, stay at bottom
+ // unless user is editing text
+ if (mScrolledToBottom && mTrackBottom && !hasFocus())
+ {
+ endOfDoc();
+ }
+
updateTextRect();
S32 line_height = llround( mGLFont->getLineHeight() );
@@ -4234,6 +4246,8 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
node->getAttributeBOOL("word_wrap", word_wrap);
setWordWrap(word_wrap);
+ node->getAttributeBOOL("track_bottom", mTrackBottom);
+
LLColor4 color;
if (LLUICtrlFactory::getAttributeColor(node,"cursor_color", color))
{
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 7049de7b89..a2ce0d2c47 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -206,13 +206,13 @@ public:
void setTabToNextField(BOOL b) { mTabToNextField = b; }
void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; }
- // If takes focus, will take keyboard focus on click.
- void setTakesFocus(BOOL b) { mTakesFocus = b; }
-
// Hack to handle Notecards
virtual BOOL importBuffer(const LLString& buffer );
virtual BOOL exportBuffer(LLString& buffer );
+ // If takes focus, will take keyboard focus on click.
+ void setTakesFocus(BOOL b) { mTakesFocus = b; }
+
void setSourceID(const LLUUID& id) { mSourceID = id; }
void setAcceptCallingCardNames(BOOL enable) { mAcceptCallingCardNames = enable; }
@@ -244,7 +244,10 @@ public:
void startOfLine();
void endOfLine();
void endOfDoc();
-
+
+ BOOL isScrolledToTop();
+ BOOL isScrolledToBottom();
+
// Getters
const LLWString& getWText() const;
llwchar getWChar(S32 pos);
@@ -439,6 +442,8 @@ protected:
BOOL mTakesFocus;
BOOL mHideScrollbarForShortDocs;
BOOL mTakesNonScrollClicks;
+ BOOL mTrackBottom; // if true, keeps scroll position at bottom during resize
+ BOOL mScrolledToBottom;
BOOL mAllowEmbeddedItems;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 00a230dff3..7561fe8b48 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -79,7 +79,7 @@ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f);
LLWindow* LLUI::sWindow = NULL;
LLHtmlHelp* LLUI::sHtmlHelp = NULL;
BOOL LLUI::sShowXUINames = FALSE;
-std::stack<LLRect> LLUI::sClipRectStack;
+std::stack<LLRect> LLScreenClipRect::sClipRectStack;
//
// Functions
@@ -410,39 +410,76 @@ void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max
}
-void gl_draw_image( S32 x, S32 y, LLImageGL* image, const LLColor4& color )
+void gl_draw_image( S32 x, S32 y, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect )
{
- gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color );
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+ gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect );
}
-void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
{
- gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color );
+ if (NULL == image)
+ {
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
+ }
+ gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect );
}
-void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color)
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect)
{
- stop_glerror();
- F32 border_scale = 1.f;
-
if (NULL == image)
{
llwarns << "image == NULL; aborting function" << llendl;
return;
}
- if (border_height * 2 > height)
- {
- border_scale = (F32)height / ((F32)border_height * 2.f);
- }
- if (border_width * 2 > width)
+ // scale screen size of borders down
+ F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
+ F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
+
+ LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction);
+ gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
+}
+
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect, const LLRectf& scale_rect)
+{
+ stop_glerror();
+
+ if (NULL == image)
{
- border_scale = llmin(border_scale, (F32)width / ((F32)border_width * 2.f));
+ llwarns << "image == NULL; aborting function" << llendl;
+ return;
}
// scale screen size of borders down
- S32 scaled_border_width = llfloor(border_scale * (F32)border_width);
- S32 scaled_border_height = llfloor(border_scale * (F32)border_height);
+ LLRectf clipped_scale_rect = uv_rect;
+ clipped_scale_rect.intersectWith(scale_rect);
+
+ LLRect draw_rect(0, height, width, 0);
+ LLRect draw_scale_rect(llround((F32)image->getWidth() * scale_rect.mLeft),
+ llround((F32)image->getHeight() * scale_rect.mTop),
+ llround((F32)image->getWidth() * scale_rect.mRight),
+ llround((F32)image->getHeight() * scale_rect.mBottom));
+ // scale fixed region of image up with drawn region
+ draw_scale_rect.mRight += width - image->getWidth();
+ draw_scale_rect.mTop += height - image->getHeight();
+
+ S32 border_shrink_width = llmax(0, draw_scale_rect.mLeft - draw_scale_rect.mRight);
+ S32 border_shrink_height = llmax(0, draw_scale_rect.mBottom - draw_scale_rect.mTop);
+
+ F32 shrink_width_ratio = scale_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image->getWidth() * (1.f - scale_rect.getWidth()));
+ F32 shrink_height_ratio = scale_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image->getHeight() * (1.f - scale_rect.getHeight()));
+
+ F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
+ draw_scale_rect.mLeft = llround((F32)draw_scale_rect.mLeft * shrink_scale);
+ draw_scale_rect.mTop = llround(lerp((F32)height, (F32)draw_scale_rect.mTop, shrink_scale));
+ draw_scale_rect.mRight = llround(lerp((F32)width, (F32)draw_scale_rect.mRight, shrink_scale));
+ draw_scale_rect.mBottom = llround((F32)draw_scale_rect.mBottom * shrink_scale);
LLGLSUIDefault gls_ui;
@@ -470,127 +507,124 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
glColor4fv(color.mV);
- F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
- F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
-
glBegin(GL_QUADS);
{
// draw bottom left
- glTexCoord2f(0.f, 0.f);
+ glTexCoord2d(uv_rect.mLeft, uv_rect.mBottom);
glVertex2i(0, 0);
- glTexCoord2f(border_width_fraction, 0.f);
- glVertex2i(scaled_border_width, 0);
+ glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
+ glVertex2i(draw_scale_rect.mLeft, 0);
- glTexCoord2f(border_width_fraction, border_height_fraction);
- glVertex2i(scaled_border_width, scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
- glTexCoord2f(0.f, border_height_fraction);
- glVertex2i(0, scaled_border_height);
+ glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mBottom);
+ glVertex2i(0, draw_scale_rect.mBottom);
// draw bottom middle
- glTexCoord2f(border_width_fraction, 0.f);
- glVertex2i(scaled_border_width, 0);
+ glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mBottom);
+ glVertex2i(draw_scale_rect.mLeft, 0);
- glTexCoord2f(1.f - border_width_fraction, 0.f);
- glVertex2i(width - scaled_border_width, 0);
+ glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mBottom);
+ glVertex2i(draw_scale_rect.mRight, 0);
- glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
- glVertex2i(width - scaled_border_width, scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
- glTexCoord2f(border_width_fraction, border_height_fraction);
- glVertex2i(scaled_border_width, scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
// draw bottom right
- glTexCoord2f(1.f - border_width_fraction, 0.f);
- glVertex2i(width - scaled_border_width, 0);
+ glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mBottom);
+ glVertex2i(draw_scale_rect.mRight, 0);
- glTexCoord2f(1.f, 0.f);
+ glTexCoord2d(uv_rect.mRight, uv_rect.mBottom);
glVertex2i(width, 0);
- glTexCoord2f(1.f, border_height_fraction);
- glVertex2i(width, scaled_border_height);
+ glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mBottom);
+ glVertex2i(width, draw_scale_rect.mBottom);
- glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
- glVertex2i(width - scaled_border_width, scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
// draw left
- glTexCoord2f(0.f, border_height_fraction);
- glVertex2i(0, scaled_border_height);
+ glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mBottom);
+ glVertex2i(0, draw_scale_rect.mBottom);
- glTexCoord2f(border_width_fraction, border_height_fraction);
- glVertex2i(scaled_border_width, scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
- glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(scaled_border_width, height - scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
- glTexCoord2f(0.f, 1.f - border_height_fraction);
- glVertex2i(0, height - scaled_border_height);
+ glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mTop);
+ glVertex2i(0, draw_scale_rect.mTop);
// draw middle
- glTexCoord2f(border_width_fraction, border_height_fraction);
- glVertex2i(scaled_border_width, scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
- glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
- glVertex2i(width - scaled_border_width, scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
- glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(width - scaled_border_width, height - scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
- glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(scaled_border_width, height - scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
// draw right
- glTexCoord2f(1.f - border_width_fraction, border_height_fraction);
- glVertex2i(width - scaled_border_width, scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mBottom);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
- glTexCoord2f(1.f, border_height_fraction);
- glVertex2i(width, scaled_border_height);
+ glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mBottom);
+ glVertex2i(width, draw_scale_rect.mBottom);
- glTexCoord2f(1.f, 1.f - border_height_fraction);
- glVertex2i(width, height - scaled_border_height);
+ glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mTop);
+ glVertex2i(width, draw_scale_rect.mTop);
- glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(width - scaled_border_width, height - scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
// draw top left
- glTexCoord2f(0.f, 1.f - border_height_fraction);
- glVertex2i(0, height - scaled_border_height);
+ glTexCoord2d(uv_rect.mLeft, clipped_scale_rect.mTop);
+ glVertex2i(0, draw_scale_rect.mTop);
- glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(scaled_border_width, height - scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
- glTexCoord2f(border_width_fraction, 1.f);
- glVertex2i(scaled_border_width, height);
+ glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
+ glVertex2i(draw_scale_rect.mLeft, height);
- glTexCoord2f(0.f, 1.f);
+ glTexCoord2d(uv_rect.mLeft, uv_rect.mTop);
glVertex2i(0, height);
// draw top middle
- glTexCoord2f(border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(scaled_border_width, height - scaled_border_height);
+ glTexCoord2f(clipped_scale_rect.mLeft, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
- glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(width - scaled_border_width, height - scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
- glTexCoord2f(1.f - border_width_fraction, 1.f);
- glVertex2i(width - scaled_border_width, height);
+ glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mTop);
+ glVertex2i(draw_scale_rect.mRight, height);
- glTexCoord2f(border_width_fraction, 1.f);
- glVertex2i(scaled_border_width, height);
+ glTexCoord2f(clipped_scale_rect.mLeft, uv_rect.mTop);
+ glVertex2i(draw_scale_rect.mLeft, height);
// draw top right
- glTexCoord2f(1.f - border_width_fraction, 1.f - border_height_fraction);
- glVertex2i(width - scaled_border_width, height - scaled_border_height);
+ glTexCoord2d(clipped_scale_rect.mRight, clipped_scale_rect.mTop);
+ glVertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
- glTexCoord2f(1.f, 1.f - border_height_fraction);
- glVertex2i(width, height - scaled_border_height);
+ glTexCoord2d(uv_rect.mRight, clipped_scale_rect.mTop);
+ glVertex2i(width, draw_scale_rect.mTop);
- glTexCoord2f(1.f, 1.f);
+ glTexCoord2d(uv_rect.mRight, uv_rect.mTop);
glVertex2i(width, height);
- glTexCoord2f(1.f - border_width_fraction, 1.f);
- glVertex2i(width - scaled_border_width, height);
+ glTexCoord2d(clipped_scale_rect.mRight, uv_rect.mTop);
+ glVertex2i(draw_scale_rect.mRight, height);
}
glEnd();
}
@@ -602,12 +636,12 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
}
}
-void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color)
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
{
- gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color );
+ gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect );
}
-void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLImageGL* image, const LLColor4& color)
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
{
if (NULL == image)
{
@@ -635,16 +669,16 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
glBegin(GL_QUADS);
{
- glTexCoord2f(1.f, 1.f);
+ glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
glVertex2i(width, height );
- glTexCoord2f(0.f, 1.f);
+ glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
glVertex2i(0, height );
- glTexCoord2f(0.f, 0.f);
+ glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
glVertex2i(0, 0);
- glTexCoord2f(1.f, 0.f);
+ glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
glVertex2i(width, 0);
}
glEnd();
@@ -653,7 +687,7 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
}
-void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
+void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color, const LLRectf& uv_rect)
{
if (NULL == image)
{
@@ -673,16 +707,16 @@ void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageG
glBegin(GL_QUADS);
{
- glTexCoord2f(1.f, 0.f);
+ glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
glVertex2i(width, height );
- glTexCoord2f(0.f, 0.f);
+ glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
glVertex2i(0, height );
- glTexCoord2f(0.f, 1.f);
+ glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
glVertex2i(0, 0);
- glTexCoord2f(1.f, 1.f);
+ glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
glVertex2i(width, 0);
}
glEnd();
@@ -1584,40 +1618,6 @@ void LLUI::loadIdentity()
LLFontGL::sCurOrigin.mZ = 0;
}
-//static
-void LLUI::setScissorRegionScreen(const LLRect& rect)
-{
- stop_glerror();
- S32 x,y,w,h;
- x = llround(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]);
- y = llround(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]);
- w = llround(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX]);
- h = llround(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY]);
- glScissor( x,y,w,h );
- stop_glerror();
-}
-
-//static
-void LLUI::setScissorRegionLocal(const LLRect& rect)
-{
- stop_glerror();
- S32 screen_left = LLFontGL::sCurOrigin.mX + rect.mLeft;
- S32 screen_bottom = LLFontGL::sCurOrigin.mY + rect.mBottom;
-
- S32 x,y,w,h;
-
- x = llround((F32)screen_left * LLUI::sGLScaleFactor.mV[VX]);
- y = llround((F32)screen_bottom * LLUI::sGLScaleFactor.mV[VY]);
- w = llround((F32)rect.getWidth() * LLUI::sGLScaleFactor.mV[VX]);
- h = llround((F32)rect.getHeight() * LLUI::sGLScaleFactor.mV[VY]);
-
- w = llmax(0,w);
- h = llmax(0,h);
-
- glScissor(x,y,w,h);
- stop_glerror();
-}
-
//static
void LLUI::setScaleFactor(const LLVector2 &scale_factor)
{
@@ -1738,64 +1738,169 @@ LLUUID LLUI::findAssetUUIDByName(const LLString &asset_name)
return LLUUID( foundValue );
}
+//static
+LLUIImage* LLUI::getUIImageByName(const LLString& name)
+{
+ return sImageProvider->getUIImageByID(findAssetUUIDByName(name));
+}
+
+
// static
void LLUI::setHtmlHelp(LLHtmlHelp* html_help)
{
LLUI::sHtmlHelp = html_help;
}
+LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST), mEnabled(enabled)
+{
+ if (mEnabled)
+ {
+ pushClipRect(rect);
+ }
+ mScissorState.setEnabled(!sClipRectStack.empty());
+ updateScissorRegion();
+}
+
+LLScreenClipRect::~LLScreenClipRect()
+{
+ if (mEnabled)
+ {
+ popClipRect();
+ }
+ updateScissorRegion();
+}
+
//static
-void LLUI::pushClipRect(const LLRect& rect)
+void LLScreenClipRect::pushClipRect(const LLRect& rect)
{
LLRect combined_clip_rect = rect;
if (!sClipRectStack.empty())
{
- combined_clip_rect.intersectWith(sClipRectStack.top());
+ LLRect top = sClipRectStack.top();
+ combined_clip_rect.intersectWith(top);
}
sClipRectStack.push(combined_clip_rect);
- setScissorRegionScreen(combined_clip_rect);
}
//static
-void LLUI::popClipRect()
+void LLScreenClipRect::popClipRect()
{
sClipRectStack.pop();
- if (!sClipRectStack.empty())
- {
- setScissorRegionScreen(sClipRectStack.top());
- }
}
-LLClipRect::LLClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled)
+//static
+void LLScreenClipRect::updateScissorRegion()
{
- if (mEnabled)
- {
- LLUI::pushClipRect(rect);
- }
+ if (sClipRectStack.empty()) return;
+
+ LLRect rect = sClipRectStack.top();
+ stop_glerror();
+ S32 x,y,w,h;
+ x = llfloor(rect.mLeft * LLUI::sGLScaleFactor.mV[VX]);
+ y = llfloor(rect.mBottom * LLUI::sGLScaleFactor.mV[VY]);
+ w = llmax(0, llceil(rect.getWidth() * LLUI::sGLScaleFactor.mV[VX])) + 1;
+ h = llmax(0, llceil(rect.getHeight() * LLUI::sGLScaleFactor.mV[VY])) + 1;
+ glScissor( x,y,w,h );
+ stop_glerror();
}
-LLClipRect::~LLClipRect()
+
+LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled)
+: LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX,
+ rect.mTop + LLFontGL::sCurOrigin.mY,
+ rect.mRight + LLFontGL::sCurOrigin.mX,
+ rect.mBottom + LLFontGL::sCurOrigin.mY),
+ enabled)
{
- if (mEnabled)
- {
- LLUI::popClipRect();
- }
}
-LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled)
+
+//
+// LLUIImage
+//
+
+LLUIImage::LLUIImage(LLPointer<LLImageGL> image) :
+ mImage(image),
+ mScaleRegion(0.f, 1.f, 1.f, 0.f),
+ mClipRegion(0.f, 1.f, 1.f, 0.f),
+ mUniformScaling(TRUE),
+ mNoClip(TRUE)
+{
+}
+
+void LLUIImage::setClipRegion(const LLRectf& region)
+{
+ mClipRegion = region;
+ mNoClip = mClipRegion.mLeft == 0.f
+ && mClipRegion.mRight == 1.f
+ && mClipRegion.mBottom == 0.f
+ && mClipRegion.mTop == 1.f;
+}
+
+void LLUIImage::setScaleRegion(const LLRectf& region)
+{
+ mScaleRegion = region;
+ mUniformScaling = mScaleRegion.mLeft == 0.f
+ && mScaleRegion.mRight == 1.f
+ && mScaleRegion.mBottom == 0.f
+ && mScaleRegion.mTop == 1.f;
+}
+
+//TODO: move drawing implementation inside class
+void LLUIImage::draw(S32 x, S32 y, const LLColor4& color)
{
- if (mEnabled)
- {
- LLRect scissor_rect = rect;
- scissor_rect.translate(LLFontGL::sCurOrigin.mX, LLFontGL::sCurOrigin.mY);
- LLUI::pushClipRect(scissor_rect);
- }
+ gl_draw_image(x, y, mImage, color, mClipRegion);
}
-LLLocalClipRect::~LLLocalClipRect()
+void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color)
{
- if (mEnabled)
+ if (mUniformScaling)
{
- LLUI::popClipRect();
+ gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion);
}
+ else
+ {
+ gl_draw_scaled_image_with_border(
+ x, y,
+ width, height,
+ mImage,
+ color,
+ FALSE,
+ mClipRegion,
+ mScaleRegion);
+ }
+}
+
+void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color)
+{
+ gl_draw_scaled_image_with_border(
+ x, y,
+ width, height,
+ mImage,
+ color,
+ TRUE,
+ mClipRegion,
+ mScaleRegion);
+}
+
+void LLUIImage::drawSolid(S32 x, S32 y, const LLColor4& color)
+{
+ gl_draw_scaled_image_with_border(
+ x, y,
+ getWidth(), getHeight(),
+ mImage,
+ color,
+ TRUE,
+ mClipRegion,
+ mScaleRegion);
+}
+
+S32 LLUIImage::getWidth()
+{
+ return mImage->getWidth(0);
+}
+
+S32 LLUIImage::getHeight()
+{
+ return mImage->getHeight(0);
}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index b98f4d5de2..05982aa9e2 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -41,14 +41,15 @@
#include "llhtmlhelp.h"
#include "llgl.h"
#include <stack>
+#include "llimagegl.h"
class LLColor4;
class LLVector3;
class LLVector2;
-class LLImageGL;
class LLUUID;
class LLWindow;
class LLView;
+class LLUIImage;
// UI colors
extern const LLColor4 UI_VERTEX_COLOR;
@@ -83,13 +84,14 @@ void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4&
void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color);
-void gl_draw_image(S32 x, S32 y, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
-void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4 &color, BOOL solid_color = FALSE);
+void gl_draw_image(S32 x, S32 y, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLImageGL* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
// Flip vertical, used for LLFloaterHTML
-void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR);
+void gl_draw_scaled_image_inverted(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom);
void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f );
@@ -166,13 +168,12 @@ public:
//helper functions (should probably move free standing rendering helper functions here)
static LLString locateSkin(const LLString& filename);
- static void pushClipRect(const LLRect& rect);
- static void popClipRect();
static void setCursorPositionScreen(S32 x, S32 y);
static void setCursorPositionLocal(LLView* viewp, S32 x, S32 y);
static void setScaleFactor(const LLVector2& scale_factor);
static void setLineWidth(F32 width);
static LLUUID findAssetUUIDByName(const LLString& name);
+ static LLUIImage* getUIImageByName(const LLString& name);
static LLVector2 getWindowSize();
static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
@@ -180,10 +181,6 @@ public:
static void glRectToScreen(const LLRect& gl, LLRect *screen);
static void setHtmlHelp(LLHtmlHelp* html_help);
-private:
- static void setScissorRegionScreen(const LLRect& rect);
- static void setScissorRegionLocal(const LLRect& rect); // works assuming LLUI::translate has been called
-
public:
static LLControlGroup* sConfigGroup;
static LLControlGroup* sColorsGroup;
@@ -194,7 +191,6 @@ public:
static LLWindow* sWindow;
static BOOL sShowXUINames;
static LLHtmlHelp* sHtmlHelp;
- static std::stack<LLRect> sClipRectStack;
};
@@ -286,6 +282,7 @@ typedef enum e_widget_type
WIDGET_TYPE_MEMORY_VIEW,
WIDGET_TYPE_FRAME_STAT_VIEW,
WIDGET_TYPE_LAYOUT_STACK,
+ WIDGET_TYPE_FLYOUT_BUTTON,
WIDGET_TYPE_DONTCARE,
WIDGET_TYPE_COUNT
} EWidgetType;
@@ -382,24 +379,65 @@ protected:
template <class T, class U> T* LLUISingleton<T,U>::sInstance = NULL;
-class LLClipRect
+class LLScreenClipRect
{
public:
- LLClipRect(const LLRect& rect, BOOL enabled = TRUE);
- virtual ~LLClipRect();
-protected:
+ LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE);
+ virtual ~LLScreenClipRect();
+
+private:
+ static void pushClipRect(const LLRect& rect);
+ static void popClipRect();
+ static void updateScissorRegion();
+
+private:
LLGLState mScissorState;
BOOL mEnabled;
+
+ static std::stack<LLRect> sClipRectStack;
};
-class LLLocalClipRect
+class LLLocalClipRect : public LLScreenClipRect
{
public:
LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
- virtual ~LLLocalClipRect();
+};
+
+class LLUIImage : public LLRefCount
+{
+public:
+ LLUIImage(LLPointer<LLImageGL> image);
+
+ void setClipRegion(const LLRectf& region);
+ void setScaleRegion(const LLRectf& region);
+
+ LLPointer<LLImageGL> getImage() { return mImage; }
+
+ void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR);
+ void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR);
+ void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color);
+ void drawSolid(S32 x, S32 y, const LLColor4& color);
+
+ S32 getWidth();
+ S32 getHeight();
+
protected:
- LLGLState mScissorState;
- BOOL mEnabled;
+ LLRectf mScaleRegion;
+ LLRectf mClipRegion;
+ LLPointer<LLImageGL> mImage;
+ BOOL mUniformScaling;
+ BOOL mNoClip;
+};
+
+//RN: maybe this needs to moved elsewhere?
+class LLImageProviderInterface
+{
+public:
+ LLImageProviderInterface() {};
+ virtual ~LLImageProviderInterface() {};
+
+ virtual LLUIImage* getUIImageByID(const LLUUID& id, BOOL clamped = TRUE) = 0;
+ virtual LLImageGL* getImageByID(const LLUUID& id, BOOL clamped = TRUE) = 0;
};
#endif
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 7d354753d3..8645f50764 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -47,11 +47,53 @@
const U32 MAX_STRING_LENGTH = 10;
-LLUICtrl::LLUICtrl() :
- mCommitCallback(NULL),
- mFocusLostCallback(NULL),
+LLFocusableElement::LLFocusableElement()
+: mFocusLostCallback(NULL),
mFocusReceivedCallback(NULL),
mFocusChangedCallback(NULL),
+ mFocusCallbackUserData(NULL)
+{
+}
+
+void LLFocusableElement::onFocusReceived()
+{
+ if( mFocusReceivedCallback )
+ {
+ mFocusReceivedCallback( this, mFocusCallbackUserData );
+ }
+ if( mFocusChangedCallback )
+ {
+ mFocusChangedCallback( this, mFocusCallbackUserData );
+ }
+}
+
+void LLFocusableElement::onFocusLost()
+{
+ if( mFocusLostCallback )
+ {
+ mFocusLostCallback( this, mFocusCallbackUserData );
+ }
+
+ if( mFocusChangedCallback )
+ {
+ mFocusChangedCallback( this, mFocusCallbackUserData );
+ }
+}
+
+BOOL LLFocusableElement::hasFocus() const
+{
+ return FALSE;
+}
+
+void LLFocusableElement::setFocus(BOOL b)
+{
+}
+
+
+
+LLUICtrl::LLUICtrl() :
+ mCommitCallback(NULL),
+ mLostTopCallback(NULL),
mValidateCallback(NULL),
mCallbackUserData(NULL),
mTentative(FALSE),
@@ -68,9 +110,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 ),
+ mLostTopCallback( NULL ),
mValidateCallback( NULL ),
mCallbackUserData( callback_userdata ),
mTentative( FALSE ),
@@ -128,6 +168,86 @@ LLCtrlScrollInterface* LLUICtrl::getScrollInterface()
return NULL;
}
+BOOL LLUICtrl::hasFocus() const
+{
+ return (gFocusMgr.childHasKeyboardFocus(this));
+}
+
+void LLUICtrl::setFocus(BOOL b)
+{
+ // focus NEVER goes to ui ctrls that are disabled!
+ if (!mEnabled)
+ {
+ return;
+ }
+ if( b )
+ {
+ if (!hasFocus())
+ {
+ gFocusMgr.setKeyboardFocus( this );
+ }
+ }
+ else
+ {
+ if( gFocusMgr.childHasKeyboardFocus(this))
+ {
+ gFocusMgr.setKeyboardFocus( NULL );
+ }
+ }
+}
+
+void LLUICtrl::onFocusReceived()
+{
+ // trigger callbacks
+ LLFocusableElement::onFocusReceived();
+
+ // find first view in hierarchy above new focus that is a LLUICtrl
+ LLView* viewp = getParent();
+ LLUICtrl* last_focus = gFocusMgr.getLastKeyboardFocus();
+
+ while (viewp && !viewp->isCtrl())
+ {
+ viewp = viewp->getParent();
+ }
+
+ // and if it has newly gained focus, call onFocusReceived()
+ LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
+ if (ctrlp && (!last_focus || !last_focus->hasAncestor(ctrlp)))
+ {
+ ctrlp->onFocusReceived();
+ }
+}
+
+void LLUICtrl::onFocusLost()
+{
+ // trigger callbacks
+ LLFocusableElement::onFocusLost();
+
+ // find first view in hierarchy above old focus that is a LLUICtrl
+ LLView* viewp = getParent();
+ while (viewp && !viewp->isCtrl())
+ {
+ viewp = viewp->getParent();
+ }
+
+ // and if it has just lost focus, call onFocusReceived()
+ LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
+ // hasFocus() includes any descendants
+ if (ctrlp && !ctrlp->hasFocus())
+ {
+ ctrlp->onFocusLost();
+ }
+}
+
+void LLUICtrl::onLostTop()
+{
+ if (mLostTopCallback)
+ {
+ mLostTopCallback(this, mCallbackUserData);
+ }
+}
+
+
// virtual
void LLUICtrl::setTabStop( BOOL b )
{
@@ -168,67 +288,6 @@ BOOL LLUICtrl::getIsChrome() const
return mIsChrome;
}
-void LLUICtrl::onFocusReceived()
-{
- if( mFocusReceivedCallback )
- {
- mFocusReceivedCallback( this, mCallbackUserData );
- }
- if( mFocusChangedCallback )
- {
- mFocusChangedCallback( this, mCallbackUserData );
- }
-}
-
-void LLUICtrl::onFocusLost()
-{
- if( mFocusLostCallback )
- {
- mFocusLostCallback( this, mCallbackUserData );
- }
-
- if( mFocusChangedCallback )
- {
- mFocusChangedCallback( this, mCallbackUserData );
- }
-}
-
-BOOL LLUICtrl::hasFocus() const
-{
- return (gFocusMgr.childHasKeyboardFocus(this));
-}
-
-void LLUICtrl::setFocus(BOOL b)
-{
- // focus NEVER goes to ui ctrls that are disabled!
- if (!mEnabled)
- {
- return;
- }
- if( b )
- {
- if (!hasFocus())
- {
- gFocusMgr.setKeyboardFocus( this, &LLUICtrl::onFocusLostCallback );
- onFocusReceived();
- }
- }
- else
- {
- if( gFocusMgr.childHasKeyboardFocus(this))
- {
- gFocusMgr.setKeyboardFocus( NULL, NULL );
- onFocusLost();
- }
- }
-}
-
-// static
-void LLUICtrl::onFocusLostCallback( LLUICtrl* old_focus )
-{
- old_focus->onFocusLost();
-}
-
// this comparator uses the crazy disambiguating logic of LLCompareByTabOrder,
// but to switch up the order so that children that have the default tab group come first
// and those that are prior to the default tab group come last
@@ -262,6 +321,7 @@ public:
}
};
+
BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields)
{
// try to select default tab group child
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index 00f78748a7..ae360f401f 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -53,8 +53,31 @@ class LLCtrlScrollInterface;
typedef void (*LLUICtrlCallback)(LLUICtrl* ctrl, void* userdata);
typedef BOOL (*LLUICtrlValidate)(LLUICtrl* ctrl, void* userdata);
+class LLFocusableElement
+{
+ friend class LLFocusMgr; // allow access to focus change handlers
+public:
+ LLFocusableElement();
+ virtual ~LLFocusableElement() {};
+
+ virtual void setFocus( BOOL b );
+ virtual BOOL hasFocus() const;
+
+ void setFocusLostCallback(void (*cb)(LLFocusableElement* caller, void*), void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; }
+ void setFocusReceivedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; }
+ void setFocusChangedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; }
+
+protected:
+ virtual void onFocusReceived();
+ virtual void onFocusLost();
+ void (*mFocusLostCallback)( LLFocusableElement* caller, void* userdata );
+ void (*mFocusReceivedCallback)( LLFocusableElement* ctrl, void* userdata );
+ void (*mFocusChangedCallback)( LLFocusableElement* ctrl, void* userdata );
+ void* mFocusCallbackUserData;
+};
+
class LLUICtrl
-: public LLView
+: public LLView, public LLFocusableElement
{
public:
LLUICtrl();
@@ -85,6 +108,11 @@ public:
virtual void setFocus( BOOL b );
virtual BOOL hasFocus() const;
+ virtual void onFocusReceived();
+ virtual void onFocusLost();
+
+ virtual void onLostTop(); // called when registered as top ctrl and user clicks elsewhere
+
virtual void setTabStop( BOOL b );
virtual BOOL hasTabStop() const;
@@ -115,6 +143,7 @@ public:
void setCommitCallback( void (*cb)(LLUICtrl*, void*) ) { mCommitCallback = cb; }
void setValidateBeforeCommit( BOOL(*cb)(LLUICtrl*, void*) ) { mValidateCallback = cb; }
+ void setLostTopCallback( void (*cb)(LLUICtrl*, void*) ) { mLostTopCallback = cb; }
// Defaults to no-op!
virtual void setDoubleClickCallback( void (*cb)(void*) );
@@ -126,23 +155,8 @@ public:
virtual void setMinValue(LLSD min_value);
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; }
-
- static void onFocusLostCallback(LLUICtrl* old_focus);
-
/*virtual*/ BOOL focusFirstItem(BOOL prefer_text_fields = FALSE );
- class LLTabStopPostFilter : public LLQueryFilter, public LLSingleton<LLTabStopPostFilter>
- {
- /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const
- {
- return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->hasTabStop() && children.size() == 0, TRUE);
- }
- };
-
class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter>
{
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const
@@ -157,16 +171,9 @@ public:
virtual void resetDirty() {};
protected:
- virtual void onFocusReceived();
- virtual void onFocusLost();
- void onChangeFocus( S32 direction );
-
-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 );
+ void (*mLostTopCallback)( LLUICtrl* ctrl, void* userdata );
BOOL (*mValidateCallback)( LLUICtrl* ctrl, void* userdata );
void* mCallbackUserData;
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 88e4e89a2b..1e8798e7f7 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -173,7 +173,7 @@ std::vector<LLString> LLUICtrlFactory::mXUIPaths;
class LLUICtrlLocate : public LLUICtrl
{
public:
- LLUICtrlLocate() : LLUICtrl("locate", LLRect(0,0,0,0), FALSE, NULL, NULL) {}
+ LLUICtrlLocate() : LLUICtrl("locate", LLRect(0,0,0,0), FALSE, NULL, NULL) { setTabStop(FALSE); }
virtual void draw() { }
virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_LOCATE; }
@@ -181,7 +181,11 @@ public:
static LLView *fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
{
+ LLString name("pad");
+ node->getAttributeString("name", name);
+
LLUICtrlLocate *new_ctrl = new LLUICtrlLocate();
+ new_ctrl->setName(name);
new_ctrl->initFromXML(node, parent);
return new_ctrl;
}
@@ -196,6 +200,7 @@ LLUICtrlFactory::LLUICtrlFactory()
LLUICtrlCreator<LLButton>::registerCreator(LL_BUTTON_TAG, this);
LLUICtrlCreator<LLCheckBoxCtrl>::registerCreator(LL_CHECK_BOX_CTRL_TAG, this);
LLUICtrlCreator<LLComboBox>::registerCreator(LL_COMBO_BOX_TAG, this);
+ LLUICtrlCreator<LLFlyoutButton>::registerCreator(LL_FLYOUT_BUTTON_TAG, this);
LLUICtrlCreator<LLLineEditor>::registerCreator(LL_LINE_EDITOR_TAG, this);
LLUICtrlCreator<LLSearchEditor>::registerCreator(LL_SEARCH_EDITOR_TAG, this);
LLUICtrlCreator<LLScrollListCtrl>::registerCreator(LL_SCROLL_LIST_CTRL_TAG, this);
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index a047f9912e..370288e949 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -113,7 +113,7 @@ LLView::LLView() :
mSaveToXML(TRUE),
mIsFocusRoot(FALSE),
mLastVisible(TRUE),
- mSpanChildren(FALSE),
+ mUseBoundingRect(FALSE),
mVisible(TRUE),
mHidden(FALSE),
mNextInsertionOrdinal(0)
@@ -133,7 +133,7 @@ LLView::LLView(const LLString& name, BOOL mouse_opaque) :
mSaveToXML(TRUE),
mIsFocusRoot(FALSE),
mLastVisible(TRUE),
- mSpanChildren(FALSE),
+ mUseBoundingRect(FALSE),
mVisible(TRUE),
mHidden(FALSE),
mNextInsertionOrdinal(0)
@@ -148,6 +148,7 @@ LLView::LLView(
mParentView(NULL),
mName(name),
mRect(rect),
+ mBoundingRect(rect),
mReshapeFlags(reshape),
mDefaultTabGroup(0),
mEnabled(TRUE),
@@ -156,7 +157,7 @@ LLView::LLView(
mSaveToXML(TRUE),
mIsFocusRoot(FALSE),
mLastVisible(TRUE),
- mSpanChildren(FALSE),
+ mUseBoundingRect(FALSE),
mVisible(TRUE),
mHidden(FALSE),
mNextInsertionOrdinal(0)
@@ -235,10 +236,16 @@ BOOL LLView::setToolTipArg(const LLStringExplicit& key, const LLStringExplicit&
return TRUE;
}
+void LLView::setToolTipArgs( const LLString::format_map_t& args )
+{
+ mToolTipMsg.setArgList(args);
+}
+
// virtual
void LLView::setRect(const LLRect& rect)
{
mRect = rect;
+ updateBoundingRect();
}
@@ -287,9 +294,18 @@ void LLView::setName(LLString name)
mName = name;
}
-void LLView::setSpanChildren( BOOL span_children )
+void LLView::setUseBoundingRect( BOOL use_bounding_rect )
+{
+ if (mUseBoundingRect != use_bounding_rect)
+ {
+ mUseBoundingRect = use_bounding_rect;
+ updateBoundingRect();
+ }
+}
+
+BOOL LLView::getUseBoundingRect()
{
- mSpanChildren = span_children; updateRect();
+ return mUseBoundingRect;
}
const LLString& LLView::getToolTip()
@@ -306,7 +322,7 @@ const LLString& LLView::getName() const
void LLView::sendChildToFront(LLView* child)
{
- if (child->mParentView == this)
+ if (child && child->getParent() == this)
{
mChildList.remove( child );
mChildList.push_front(child);
@@ -315,7 +331,7 @@ void LLView::sendChildToFront(LLView* child)
void LLView::sendChildToBack(LLView* child)
{
- if (child->mParentView == this)
+ if (child && child->getParent() == this)
{
mChildList.remove( child );
mChildList.push_back(child);
@@ -330,6 +346,14 @@ void LLView::moveChildToFrontOfTabGroup(LLUICtrl* child)
}
}
+void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
+{
+ if(mCtrlOrder.find(child) != mCtrlOrder.end())
+ {
+ mCtrlOrder[child].second = mNextInsertionOrdinal++;
+ }
+}
+
void LLView::addChild(LLView* child, S32 tab_group)
{
if (mParentView == child)
@@ -353,7 +377,7 @@ void LLView::addChild(LLView* child, S32 tab_group)
}
child->mParentView = this;
- updateRect();
+ updateBoundingRect();
}
@@ -380,7 +404,7 @@ void LLView::addChildAtEnd(LLView* child, S32 tab_group)
}
child->mParentView = this;
- updateRect();
+ updateBoundingRect();
}
// remove the specified child from the view, and set it's parent to NULL.
@@ -403,6 +427,7 @@ void LLView::removeChild(LLView* child, BOOL deleteIt)
{
llerrs << "LLView::removeChild called with non-child" << llendl;
}
+ updateBoundingRect();
}
void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
@@ -782,6 +807,7 @@ void LLView::setVisible(BOOL visible)
// tell all children of this view that the visibility may have changed
onVisibilityChange( visible );
}
+ updateBoundingRect();
}
}
@@ -815,6 +841,7 @@ void LLView::onVisibilityChange ( BOOL new_visibility )
void LLView::translate(S32 x, S32 y)
{
mRect.translate(x, y);
+ updateBoundingRect();
}
// virtual
@@ -831,7 +858,8 @@ void LLView::snappedTo(LLView* snap_view)
BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
{
BOOL handled = childrenHandleHover( x, y, mask ) != NULL;
- if( !handled && mMouseOpaque && pointInView( x, y ) )
+ if( !handled
+ && blockMouseEvent(x, y) )
{
LLUI::sWindow->setCursor(UI_CURSOR_ARROW);
lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
@@ -876,45 +904,46 @@ BOOL LLView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_scre
LLString tool_tip;
- if ( getVisible() && getEnabled())
+ for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
{
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ LLView* viewp = *child_it;
+ S32 local_x = x - viewp->mRect.mLeft;
+ S32 local_y = y - viewp->mRect.mBottom;
+ if( viewp->pointInView(local_x, local_y)
+ && viewp->getVisible()
+ && viewp->getEnabled()
+ && viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ))
{
- LLView* viewp = *child_it;
- S32 local_x = x - viewp->mRect.mLeft;
- S32 local_y = y - viewp->mRect.mBottom;
- if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
- {
- handled = TRUE;
- break;
- }
+ handled = TRUE;
+ break;
}
+ }
- tool_tip = mToolTipMsg.getString();
- if (LLUI::sShowXUINames && (tool_tip.find(".xml", 0) == LLString::npos) &&
- (mName.find("Drag", 0) == LLString::npos))
- {
- tool_tip = getShowNamesToolTip();
- }
-
+ tool_tip = mToolTipMsg.getString();
+ if (
+ LLUI::sShowXUINames &&
+ (tool_tip.find(".xml", 0) == LLString::npos) &&
+ (mName.find("Drag", 0) == LLString::npos))
+ {
+ tool_tip = getShowNamesToolTip();
+ }
- BOOL showNamesTextBox = LLUI::sShowXUINames && (getWidgetType() == WIDGET_TYPE_TEXT_BOX);
+ BOOL showNamesTextBox = LLUI::sShowXUINames && (getWidgetType() == WIDGET_TYPE_TEXT_BOX);
- if( !handled && (mMouseOpaque || showNamesTextBox) && pointInView( x, y ) && !tool_tip.empty())
- {
+ if( !handled && (blockMouseEvent(x, y) || showNamesTextBox) && !tool_tip.empty())
+ {
- msg = tool_tip;
+ msg = tool_tip;
- // Convert rect local to screen coordinates
- localPointToScreen(
- 0, 0,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- localPointToScreen(
- mRect.getWidth(), mRect.getHeight(),
- &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
-
- handled = TRUE;
- }
+ // Convert rect local to screen coordinates
+ localPointToScreen(
+ 0, 0,
+ &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+ localPointToScreen(
+ mRect.getWidth(), mRect.getHeight(),
+ &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+
+ handled = TRUE;
}
return handled;
@@ -1025,7 +1054,7 @@ BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
cargo_data,
accept,
tooltip_msg) != NULL;
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
*accept = ACCEPT_NO;
handled = TRUE;
@@ -1081,7 +1110,7 @@ BOOL LLView::hasMouseCapture()
BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = childrenHandleMouseUp( x, y, mask ) != NULL;
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
handled = TRUE;
}
@@ -1092,7 +1121,7 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
{
LLView* handled_view = childrenHandleMouseDown( x, y, mask );
BOOL handled = (handled_view != NULL);
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
handled = TRUE;
handled_view = this;
@@ -1118,7 +1147,7 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
{
BOOL handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
handleMouseDown(x, y, mask);
handled = TRUE;
@@ -1132,7 +1161,7 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
if( getVisible() && mEnabled )
{
handled = childrenHandleScrollWheel( x, y, clicks ) != NULL;
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
handled = TRUE;
}
@@ -1143,7 +1172,7 @@ BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
BOOL handled = childrenHandleRightMouseDown( x, y, mask ) != NULL;
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
handled = TRUE;
}
@@ -1153,7 +1182,7 @@ BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask)
{
BOOL handled = childrenHandleRightMouseUp( x, y, mask ) != NULL;
- if( !handled && mMouseOpaque )
+ if( !handled && blockMouseEvent(x, y) )
{
handled = TRUE;
}
@@ -1428,10 +1457,10 @@ void LLView::draw()
focus_view = NULL;
}
+ ++sDepth;
for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
{
LLView *viewp = *child_iter;
- ++sDepth;
if (viewp->getVisible() && viewp != focus_view)
{
@@ -1449,8 +1478,8 @@ void LLView::draw()
}
}
- --sDepth;
}
+ --sDepth;
if (focus_view && focus_view->getVisible())
{
@@ -1467,50 +1496,61 @@ void LLView::draw()
//Draw a box for debugging.
void LLView::drawDebugRect()
{
- // drawing solids requires texturing be disabled
- LLGLSNoTexture no_texture;
-
- // draw red rectangle for the border
- LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
- if (sEditingUI)
+ LLUI::pushMatrix();
{
- border_color.mV[0] = 1.f;
- }
- else
- {
- border_color.mV[sDepth%3] = 1.f;
- }
+ // drawing solids requires texturing be disabled
+ LLGLSNoTexture no_texture;
- glColor4fv( border_color.mV );
+ if (mUseBoundingRect)
+ {
+ LLUI::translate((F32)mBoundingRect.mLeft - (F32)mRect.mLeft, (F32)mBoundingRect.mBottom - (F32)mRect.mBottom, 0.f);
+ }
- glBegin(GL_LINES);
- glVertex2i(0, mRect.getHeight() - 1);
- glVertex2i(0, 0);
+ LLRect debug_rect = mUseBoundingRect ? mBoundingRect : mRect;
- glVertex2i(0, 0);
- glVertex2i(mRect.getWidth() - 1, 0);
+ // draw red rectangle for the border
+ LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
+ if (sEditingUI)
+ {
+ border_color.mV[0] = 1.f;
+ }
+ else
+ {
+ border_color.mV[sDepth%3] = 1.f;
+ }
- glVertex2i(mRect.getWidth() - 1, 0);
- glVertex2i(mRect.getWidth() - 1, mRect.getHeight() - 1);
+ glColor4fv( border_color.mV );
- glVertex2i(mRect.getWidth() - 1, mRect.getHeight() - 1);
- glVertex2i(0, mRect.getHeight() - 1);
- glEnd();
+ glBegin(GL_LINES);
+ glVertex2i(0, debug_rect.getHeight() - 1);
+ glVertex2i(0, 0);
- // Draw the name if it's not a leaf node
- if (mChildList.size() && !sEditingUI)
- {
- //char temp[256];
- S32 x, y;
- glColor4fv( border_color.mV );
- x = mRect.getWidth()/2;
- y = mRect.getHeight()/2;
- LLString debug_text = llformat("%s (%d x %d)", getName().c_str(),
- mRect.getWidth(), mRect.getHeight());
- LLFontGL::sSansSerifSmall->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
- LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
- S32_MAX, S32_MAX, NULL, FALSE);
+ glVertex2i(0, 0);
+ glVertex2i(debug_rect.getWidth() - 1, 0);
+
+ glVertex2i(debug_rect.getWidth() - 1, 0);
+ glVertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
+
+ glVertex2i(debug_rect.getWidth() - 1, debug_rect.getHeight() - 1);
+ glVertex2i(0, debug_rect.getHeight() - 1);
+ glEnd();
+
+ // Draw the name if it's not a leaf node
+ if (mChildList.size() && !sEditingUI)
+ {
+ //char temp[256];
+ S32 x, y;
+ glColor4fv( border_color.mV );
+ x = debug_rect.getWidth()/2;
+ y = debug_rect.getHeight()/2;
+ LLString debug_text = llformat("%s (%d x %d)", getName().c_str(),
+ debug_rect.getWidth(), debug_rect.getHeight());
+ LLFontGL::sSansSerifSmall->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
+ LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
+ S32_MAX, S32_MAX, NULL, FALSE);
+ }
}
+ LLUI::popMatrix();
}
void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw)
@@ -1537,9 +1577,6 @@ void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_dr
void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
{
- // make sure this view contains all its children
- updateRect();
-
// compute how much things changed and apply reshape logic to children
S32 delta_width = width - mRect.getWidth();
S32 delta_height = height - mRect.getHeight();
@@ -1608,6 +1645,8 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
mParentView->reshape(mParentView->getRect().getWidth(), mParentView->getRect().getHeight(), FALSE);
}
}
+
+ updateBoundingRect();
}
LLRect LLView::getRequiredRect()
@@ -1615,6 +1654,53 @@ LLRect LLView::getRequiredRect()
return mRect;
}
+void LLView::updateBoundingRect()
+{
+ if (isDead()) return;
+
+ if (mUseBoundingRect)
+ {
+ LLRect local_bounding_rect = LLRect::null;
+
+ child_list_const_iter_t child_it;
+ for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+ {
+ LLView* childp = *child_it;
+ if (!childp->getVisible()) continue;
+
+ LLRect child_bounding_rect = childp->getBoundingRect();
+
+ if (local_bounding_rect.isNull())
+ {
+ // start out with bounding rect equal to first visible child's bounding rect
+ local_bounding_rect = child_bounding_rect;
+ }
+ else
+ {
+ // accumulate non-null children rectangles
+ if (!child_bounding_rect.isNull())
+ {
+ local_bounding_rect.unionWith(child_bounding_rect);
+ }
+ }
+ }
+
+ mBoundingRect = local_bounding_rect;
+ // translate into parent-relative coordinates
+ mBoundingRect.translate(mRect.mLeft, mRect.mBottom);
+ }
+ else
+ {
+ mBoundingRect = mRect;
+ }
+
+ // give parent view a chance to resize, in case we just moved, for example
+ if (getParent() && getParent()->mUseBoundingRect)
+ {
+ getParent()->updateBoundingRect();
+ }
+}
+
const LLRect LLView::getScreenRect() const
{
// *FIX: check for one-off error
@@ -1624,6 +1710,15 @@ const LLRect LLView::getScreenRect() const
return screen_rect;
}
+const LLRect LLView::getLocalBoundingRect() const
+{
+ LLRect local_bounding_rect = getBoundingRect();
+ local_bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
+
+ return local_bounding_rect;
+}
+
+
const LLRect LLView::getLocalRect() const
{
LLRect local_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
@@ -1637,38 +1732,7 @@ const LLRect LLView::getLocalSnapRect() const
return local_snap_rect;
}
-void LLView::updateRect()
-{
- if (mSpanChildren && mChildList.size())
- {
- LLView* first_child = (*mChildList.begin());
- LLRect child_spanning_rect = first_child->mRect;
-
- for ( child_list_iter_t child_it = ++mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- if (viewp->getVisible())
- {
- child_spanning_rect.unionWith(viewp->mRect);
- }
- }
-
- S32 translate_x = llmin(0, child_spanning_rect.mLeft);
- S32 translate_y = llmin(0, child_spanning_rect.mBottom);
- S32 new_width = llmax(mRect.getWidth() + translate_x, child_spanning_rect.getWidth());
- S32 new_height = llmax(mRect.getHeight() + translate_y, child_spanning_rect.getHeight());
-
- mRect.setOriginAndSize(mRect.mLeft + translate_x, mRect.mBottom + translate_y, new_width, new_height);
-
- for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
- {
- LLView* viewp = *child_it;
- viewp->mRect.translate(-translate_x, -translate_y);
- }
- }
-}
-
-BOOL LLView::hasAncestor(LLView* parentp)
+BOOL LLView::hasAncestor(const LLView* parentp)
{
if (!parentp)
{
@@ -1743,14 +1807,23 @@ LLView* LLView::getChildByName(const LLString& name, BOOL recurse) const
return NULL;
}
-// virtual
-void LLView::onFocusLost()
-{
+BOOL LLView::parentPointInView(S32 x, S32 y, EHitTestType type) const
+{
+ return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
+ ? mBoundingRect.pointInRect( x, y )
+ : mRect.pointInRect( x, y );
}
-// virtual
-void LLView::onFocusReceived()
+BOOL LLView::pointInView(S32 x, S32 y, EHitTestType type) const
+{
+ return (mUseBoundingRect && type == HIT_TEST_USE_BOUNDING_RECT)
+ ? mBoundingRect.pointInRect( x + mRect.mLeft, y + mRect.mBottom )
+ : mRect.localPointInRect( x, y );
+}
+
+BOOL LLView::blockMouseEvent(S32 x, S32 y) const
{
+ return mMouseOpaque && pointInView(x, y, HIT_TEST_IGNORE_BOUNDING_RECT);
}
// virtual
@@ -2024,9 +2097,9 @@ LLXMLNodePtr LLView::getXML(bool save_children) const
// Export all widgets as enabled and visible - code must disable.
node->createChild("hidden", TRUE)->setBoolValue(mHidden);
node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque );
- if (!mToolTipMsg.empty())
+ if (!mToolTipMsg.getString().empty())
{
- node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg);
+ node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg.getString());
}
if (mSoundFlags != MOUSE_UP)
{
@@ -2116,7 +2189,7 @@ const LLCtrlQuery & LLView::getTabOrderQuery()
query.addPreFilter(LLVisibleFilter::getInstance());
query.addPreFilter(LLEnabledFilter::getInstance());
query.addPreFilter(LLTabStopFilter::getInstance());
- query.addPostFilter(LLUICtrl::LLTabStopPostFilter::getInstance());
+ query.addPostFilter(LLLeavesFilter::getInstance());
}
return query;
}
@@ -2129,6 +2202,7 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()
query.addPreFilter(LLVisibleFilter::getInstance());
query.addPreFilter(LLEnabledFilter::getInstance());
query.addPreFilter(LLView::LLFocusRootsFilter::getInstance());
+ query.addPostFilter(LLRootsFilter::getInstance());
}
return query;
}
@@ -2593,10 +2667,10 @@ const S32 VPAD = 4;
U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect)
{
U32 follows = 0;
- S32 x = FLOATER_H_MARGIN;
- S32 y = 0;
- S32 w = 0;
- S32 h = 0;
+ S32 x = rect.mLeft;
+ S32 y = rect.mBottom;
+ S32 w = rect.getWidth();
+ S32 h = rect.getHeight();
U32 last_x = 0;
U32 last_y = 0;
@@ -2639,8 +2713,15 @@ U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, con
// view if you don't specify a width.
if (parent_view)
{
- w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
- h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
+ if(w == 0)
+ {
+ w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
+ }
+
+ if(h == 0)
+ {
+ h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
+ }
}
if (node->hasAttribute("width"))
@@ -2765,44 +2846,7 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
setRect(view_rect);
setFollows(follows_flags);
- if (node->hasAttribute("follows"))
- {
- setFollowsNone();
-
- LLString follows;
- node->getAttributeString("follows", follows);
-
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("|");
- tokenizer tokens(follows, sep);
- tokenizer::iterator token_iter = tokens.begin();
-
- while(token_iter != tokens.end())
- {
- const std::string& token_str = *token_iter;
- if (token_str == "left")
- {
- setFollowsLeft();
- }
- else if (token_str == "right")
- {
- setFollowsRight();
- }
- else if (token_str == "top")
- {
- setFollowsTop();
- }
- else if (token_str == "bottom")
- {
- setFollowsBottom();
- }
- else if (token_str == "all")
- {
- setFollowsAll();
- }
- ++token_iter;
- }
- }
+ parseFollowsFlags(node);
if (node->hasAttribute("control_name"))
{
@@ -2839,11 +2883,57 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
setHidden(hidden);
}
+ node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect);
+ node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
+
node->getAttributeS32("default_tab_group", mDefaultTabGroup);
reshape(view_rect.getWidth(), view_rect.getHeight());
}
+void LLView::parseFollowsFlags(LLXMLNodePtr node)
+{
+ if (node->hasAttribute("follows"))
+ {
+ setFollowsNone();
+
+ LLString follows;
+ node->getAttributeString("follows", follows);
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|");
+ tokenizer tokens(follows, sep);
+ tokenizer::iterator token_iter = tokens.begin();
+
+ while(token_iter != tokens.end())
+ {
+ const std::string& token_str = *token_iter;
+ if (token_str == "left")
+ {
+ setFollowsLeft();
+ }
+ else if (token_str == "right")
+ {
+ setFollowsRight();
+ }
+ else if (token_str == "top")
+ {
+ setFollowsTop();
+ }
+ else if (token_str == "bottom")
+ {
+ setFollowsBottom();
+ }
+ else if (token_str == "all")
+ {
+ setFollowsAll();
+ }
+ ++token_iter;
+ }
+ }
+}
+
+
// static
LLFontGL* LLView::selectFont(LLXMLNodePtr node)
{
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 8248d50d9d..e54983d67d 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -50,6 +50,7 @@
#include "llviewquery.h"
#include "llxmlnode.h"
#include "stdenums.h"
+#include "lluistring.h"
class LLColor4;
class LLWindow;
@@ -146,6 +147,7 @@ protected:
LLString mName;
// location in pixels, relative to surrounding structure, bottom,left=0,0
LLRect mRect;
+ LLRect mBoundingRect;
U32 mReshapeFlags;
@@ -161,11 +163,11 @@ protected:
BOOL mSaveToXML;
BOOL mIsFocusRoot;
+ BOOL mUseBoundingRect; // hit test against bounding rectangle that includes all child elements
public:
LLViewHandle mViewHandle;
BOOL mLastVisible;
- BOOL mSpanChildren;
private:
BOOL mVisible;
@@ -217,6 +219,7 @@ public:
void setMouseOpaque( BOOL b );
void setToolTip( const LLStringExplicit& msg );
BOOL setToolTipArg( const LLStringExplicit& key, const LLStringExplicit& text );
+ void setToolTipArgs( const LLString::format_map_t& args );
virtual void setRect(const LLRect &rect);
void setFollows(U32 flags);
@@ -231,13 +234,15 @@ public:
void setSoundFlags(U8 flags);
void setName(LLString name);
- void setSpanChildren( BOOL span_children );
+ void setUseBoundingRect( BOOL use_bounding_rect );
+ BOOL getUseBoundingRect();
const LLString& getToolTip();
void sendChildToFront(LLView* child);
void sendChildToBack(LLView* child);
void moveChildToFrontOfTabGroup(LLUICtrl* child);
+ void moveChildToBackOfTabGroup(LLUICtrl* child);
void addChild(LLView* view, S32 tab_group = 0);
void addChildAtEnd(LLView* view, S32 tab_group = 0);
@@ -264,7 +269,7 @@ public:
{
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const
{
- return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot());
+ return filterResult_t(view->isCtrl() && view->isFocusRoot(), TRUE);
}
};
@@ -312,20 +317,22 @@ public:
BOOL followsAll() const { return mReshapeFlags & FOLLOWS_ALL; }
const LLRect& getRect() const { return mRect; }
+ const LLRect& getBoundingRect() const { return mBoundingRect; }
+ const LLRect getLocalBoundingRect() const;
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
+ void updateBoundingRect();
LLView* getRootView();
LLView* getParent() const { return mParentView; }
LLView* getFirstChild() { return (mChildList.empty()) ? NULL : *(mChildList.begin()); }
S32 getChildCount() const { return (S32)mChildList.size(); }
template<class _Pr3> void sortChildren(_Pr3 _Pred) { mChildList.sort(_Pred); }
- BOOL hasAncestor(LLView* parentp);
+ BOOL hasAncestor(const LLView* parentp);
BOOL hasChild(const LLString& childname, BOOL recurse = FALSE) const;
@@ -390,6 +397,7 @@ public:
static U32 createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect = LLRect());
virtual void initFromXML(LLXMLNodePtr node, LLView* parent);
+ void parseFollowsFlags(LLXMLNodePtr node);
static LLFontGL* selectFont(LLXMLNodePtr node);
static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node);
@@ -428,12 +436,16 @@ public:
BOOL getVisible() const { return mVisible && !mHidden; }
U8 getSoundFlags() const { return mSoundFlags; }
- // Default to no action
- virtual void onFocusLost();
- virtual void onFocusReceived();
+ typedef enum e_hit_test_type
+ {
+ HIT_TEST_USE_BOUNDING_RECT,
+ HIT_TEST_IGNORE_BOUNDING_RECT
+ }EHitTestType;
+
+ BOOL parentPointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const;
+ BOOL pointInView(S32 x, S32 y, EHitTestType type = HIT_TEST_USE_BOUNDING_RECT) const;
+ BOOL blockMouseEvent(S32 x, S32 y) const;
- BOOL parentPointInView(S32 x, S32 y) const { return mRect.pointInRect( x, y ); }
- BOOL pointInView(S32 x, S32 y) const { return mRect.localPointInRect( x, y ); }
virtual void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
virtual void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
virtual BOOL localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view);
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index f6cbe3aac1..8fbe671613 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -84,7 +84,7 @@ void LLViewBorder::setColorsExtended( const LLColor4& shadow_light, const LLColo
void LLViewBorder::setTexture( const LLUUID &image_id )
{
- mTexture = LLUI::sImageProvider->getUIImageByID(image_id);
+ mTexture = LLUI::sImageProvider->getImageByID(image_id);
}
diff --git a/indra/llui/llviewquery.cpp b/indra/llui/llviewquery.cpp
index c07587f0ff..db00c76821 100644
--- a/indra/llui/llviewquery.cpp
+++ b/indra/llui/llviewquery.cpp
@@ -37,9 +37,14 @@
void LLQuerySorter::operator() (LLView * parent, viewList_t &children) const {}
-filterResult_t LLNoLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const
+filterResult_t LLLeavesFilter::operator() (const LLView* const view, const viewList_t & children) const
{
- return filterResult_t(!(view->getChildList()->size() == 0), TRUE);
+ return filterResult_t(children.empty(), TRUE);
+}
+
+filterResult_t LLRootsFilter::operator() (const LLView* const view, const viewList_t & children) const
+{
+ return filterResult_t(TRUE, FALSE);
}
filterResult_t LLVisibleFilter::operator() (const LLView* const view, const viewList_t & children) const
@@ -56,6 +61,16 @@ filterResult_t LLTabStopFilter::operator() (const LLView* const view, const view
view->canFocusChildren());
}
+filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewList_t & children) const
+{
+ return filterResult_t(view->isCtrl(),TRUE);
+}
+
+filterResult_t LLWidgetTypeFilter::operator() (const LLView* const view, const viewList_t & children) const
+{
+ return filterResult_t(view->getWidgetType() == mType, TRUE);
+}
+
// LLViewQuery
LLViewQuery::LLViewQuery(): mPreFilters(), mPostFilters(), mSorterp()
@@ -73,45 +88,53 @@ const LLViewQuery::filterList_t & LLViewQuery::getPostFilters() const { return m
void LLViewQuery::setSorter(const LLQuerySorter* sorterp) { mSorterp = sorterp; }
const LLQuerySorter* LLViewQuery::getSorter() const { return mSorterp; }
-viewList_t LLViewQuery::run(LLView * view) const
+viewList_t LLViewQuery::run(LLView* view) const
{
viewList_t result;
- filterResult_t pre = runFilters(view, viewList_t(), mPreFilters);
+ // prefilter gets immediate children of view
+ filterResult_t pre = runFilters(view, *view->getChildList(), mPreFilters);
if(!pre.first && !pre.second)
{
- // skip post filters completely if we're not including ourselves or the children
+ // not including ourselves or the children
+ // nothing more to do
return result;
}
+
+ viewList_t filtered_children;
+ filterResult_t post(TRUE, TRUE);
if(pre.second)
{
// run filters on children
- viewList_t filtered_children;
filterChildren(view, filtered_children);
- filterResult_t post = runFilters(view, filtered_children, mPostFilters);
- if(pre.first && post.first)
- {
- result.push_back(view);
- }
- if(post.second)
+ // only run post filters if this element passed pre filters
+ // so if you failed to pass the pre filter, you can't filter out children in post
+ if (pre.first)
{
- result.insert(result.end(), filtered_children.begin(), filtered_children.end());
+ post = runFilters(view, filtered_children, mPostFilters);
}
}
- else
+
+ if(pre.first && post.first)
{
- if(pre.first)
- {
- result.push_back(view);
- }
+ result.push_back(view);
+ }
+
+ if(pre.second && post.second)
+ {
+ result.insert(result.end(), filtered_children.begin(), filtered_children.end());
}
+
return result;
}
void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const
{
LLView::child_list_t views(*(view->getChildList()));
- (*mSorterp)(view, views); // sort the children per the sorter
+ if (mSorterp)
+ {
+ (*mSorterp)(view, views); // sort the children per the sorter
+ }
for(LLView::child_list_iter_t iter = views.begin();
iter != views.end();
iter++)
diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h
index 3919ba4bcb..63559e8240 100644
--- a/indra/llui/llviewquery.h
+++ b/indra/llui/llviewquery.h
@@ -35,6 +35,7 @@
#include <list>
#include "llmemory.h"
+#include "llui.h"
class LLView;
@@ -42,35 +43,60 @@ typedef std::list<LLView *> viewList_t;
typedef std::pair<BOOL, BOOL> filterResult_t;
// Abstract base class for all filters.
-class LLQueryFilter : public LLRefCount
+class LLQueryFilter
{
public:
+ virtual ~LLQueryFilter() {};
virtual filterResult_t operator() (const LLView* const view, const viewList_t & children) const =0;
};
-class LLQuerySorter : public LLRefCount
+class LLQuerySorter
{
public:
+ virtual ~LLQuerySorter() {};
virtual void operator() (LLView * parent, viewList_t &children) const;
};
-class LLNoLeavesFilter : public LLQueryFilter, public LLSingleton<LLNoLeavesFilter>
+class LLLeavesFilter : public LLQueryFilter, public LLSingleton<LLLeavesFilter>
{
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
};
+
+class LLRootsFilter : public LLQueryFilter, public LLSingleton<LLRootsFilter>
+{
+ /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+
class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>
{
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
};
+
class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>
{
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
};
+
class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>
{
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
};
+class LLCtrlFilter : public LLQueryFilter, public LLSingleton<LLCtrlFilter>
+{
+ /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+};
+
+class LLWidgetTypeFilter : public LLQueryFilter
+{
+public:
+ LLWidgetTypeFilter(EWidgetType type) : mType(type) {};
+private:
+ /*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
+
+ EWidgetType mType;
+};
+
// Algorithm for flattening
class LLViewQuery
{