aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llui')
-rw-r--r--linden/indra/llui/files.lst1
-rw-r--r--linden/indra/llui/llbutton.cpp28
-rw-r--r--linden/indra/llui/llbutton.h7
-rw-r--r--linden/indra/llui/llcheckboxctrl.cpp12
-rw-r--r--linden/indra/llui/llcheckboxctrl.h2
-rw-r--r--linden/indra/llui/llctrlselectioninterface.h3
-rw-r--r--linden/indra/llui/llfloater.cpp286
-rw-r--r--linden/indra/llui/llfloater.h14
-rw-r--r--linden/indra/llui/llfocusmgr.cpp9
-rw-r--r--linden/indra/llui/llfocusmgr.h1
-rw-r--r--linden/indra/llui/lllineeditor.h1
-rw-r--r--linden/indra/llui/llmenugl.cpp52
-rw-r--r--linden/indra/llui/llpanel.cpp659
-rw-r--r--linden/indra/llui/llpanel.h58
-rw-r--r--linden/indra/llui/llradiogroup.cpp66
-rw-r--r--linden/indra/llui/llradiogroup.h21
-rw-r--r--linden/indra/llui/llresizebar.cpp86
-rw-r--r--linden/indra/llui/llresizebar.h11
-rw-r--r--linden/indra/llui/llresmgr.cpp3
-rw-r--r--linden/indra/llui/llscrollcontainer.cpp3
-rw-r--r--linden/indra/llui/llscrolllistctrl.cpp55
-rw-r--r--linden/indra/llui/llscrolllistctrl.h1
-rw-r--r--linden/indra/llui/llslider.cpp158
-rw-r--r--linden/indra/llui/llslider.h6
-rw-r--r--linden/indra/llui/llsliderctrl.cpp10
-rw-r--r--linden/indra/llui/llsliderctrl.h4
-rw-r--r--linden/indra/llui/lltabcontainer.cpp114
-rw-r--r--linden/indra/llui/lltabcontainer.h11
-rw-r--r--linden/indra/llui/lltabcontainervertical.cpp74
-rw-r--r--linden/indra/llui/lltexteditor.cpp51
-rw-r--r--linden/indra/llui/lltexteditor.h4
-rw-r--r--linden/indra/llui/llui.cpp60
-rw-r--r--linden/indra/llui/llui.h57
-rw-r--r--linden/indra/llui/lluictrl.cpp2
-rw-r--r--linden/indra/llui/lluictrl.h3
-rw-r--r--linden/indra/llui/lluictrlfactory.cpp36
-rw-r--r--linden/indra/llui/lluictrlfactory.h8
-rw-r--r--linden/indra/llui/lluistring.cpp3
-rw-r--r--linden/indra/llui/lluistring.h2
-rw-r--r--linden/indra/llui/lluixmltags.h1
-rw-r--r--linden/indra/llui/llview.cpp125
-rw-r--r--linden/indra/llui/llview.h2
42 files changed, 1607 insertions, 503 deletions
diff --git a/linden/indra/llui/files.lst b/linden/indra/llui/files.lst
index 5a62573..96bb170 100644
--- a/linden/indra/llui/files.lst
+++ b/linden/indra/llui/files.lst
@@ -8,7 +8,6 @@ llui/lldraghandle.cpp
8llui/lleditmenuhandler.cpp 8llui/lleditmenuhandler.cpp
9llui/llfloater.cpp 9llui/llfloater.cpp
10llui/llfocusmgr.cpp 10llui/llfocusmgr.cpp
11llui/llhtmlhelp.h
12llui/lliconctrl.cpp 11llui/lliconctrl.cpp
13llui/llkeywords.cpp 12llui/llkeywords.cpp
14llui/lllineeditor.cpp 13llui/lllineeditor.cpp
diff --git a/linden/indra/llui/llbutton.cpp b/linden/indra/llui/llbutton.cpp
index de8b82e..aa50a6e 100644
--- a/linden/indra/llui/llbutton.cpp
+++ b/linden/indra/llui/llbutton.cpp
@@ -89,7 +89,8 @@ LLButton::LLButton( const LLString& name, const LLRect& rect, const LLString& co
89 mCurGlowStrength(0.f), 89 mCurGlowStrength(0.f),
90 mNeedsHighlight(FALSE), 90 mNeedsHighlight(FALSE),
91 mCommitOnReturn(TRUE), 91 mCommitOnReturn(TRUE),
92 mImagep( NULL ) 92 mImagep( NULL ),
93 mIsDirty( FALSE )
93{ 94{
94 mUnselectedLabel = name; 95 mUnselectedLabel = name;
95 mSelectedLabel = name; 96 mSelectedLabel = name;
@@ -216,6 +217,9 @@ void LLButton::init(void (*click_callback)(void*), void *callback_data, const LL
216 mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) ); 217 mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) );
217 mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) ); 218 mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) );
218 mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) ); 219 mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) );
220
221 mImageOverlayAlignment = LLFontGL::HCENTER;
222 mImageOverlayColor = LLColor4::white;
219} 223}
220 224
221LLButton::~LLButton() 225LLButton::~LLButton()
@@ -271,8 +275,12 @@ void LLButton::onCommit()
271 { 275 {
272 (*mClickedCallback)( mCallbackUserData ); 276 (*mClickedCallback)( mCallbackUserData );
273 } 277 }
278
279 mIsDirty = TRUE;
274} 280}
275 281
282
283
276BOOL LLButton::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent) 284BOOL LLButton::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
277{ 285{
278 BOOL handled = FALSE; 286 BOOL handled = FALSE;
@@ -282,7 +290,8 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
282 { 290 {
283 (*mClickedCallback)( mCallbackUserData ); 291 (*mClickedCallback)( mCallbackUserData );
284 } 292 }
285 handled = TRUE; 293 handled = TRUE;
294 mIsDirty = TRUE;
286 } 295 }
287 return handled; 296 return handled;
288} 297}
@@ -299,6 +308,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent )
299 (*mClickedCallback)( mCallbackUserData ); 308 (*mClickedCallback)( mCallbackUserData );
300 } 309 }
301 handled = TRUE; 310 handled = TRUE;
311 mIsDirty = TRUE;
302 } 312 }
303 } 313 }
304 return handled; 314 return handled;
@@ -359,6 +369,8 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
359 { 369 {
360 (*mClickedCallback)( mCallbackUserData ); 370 (*mClickedCallback)( mCallbackUserData );
361 } 371 }
372
373 mIsDirty = TRUE;
362 } 374 }
363 375
364 mMouseDownTimer.stop(); 376 mMouseDownTimer.stop();
@@ -618,7 +630,7 @@ void LLButton::draw()
618 // draw overlay image 630 // draw overlay image
619 if (mImageOverlay.notNull()) 631 if (mImageOverlay.notNull())
620 { 632 {
621 const S32 IMG_PAD = 4; 633 const S32 IMG_PAD = 5;
622 // get max width and height (discard level 0) 634 // get max width and height (discard level 0)
623 S32 overlay_width = mImageOverlay->getWidth(0); 635 S32 overlay_width = mImageOverlay->getWidth(0);
624 S32 overlay_height = mImageOverlay->getHeight(0); 636 S32 overlay_height = mImageOverlay->getHeight(0);
@@ -639,7 +651,7 @@ void LLButton::draw()
639 overlay_width, 651 overlay_width,
640 overlay_height, 652 overlay_height,
641 mImageOverlay, 653 mImageOverlay,
642 LLColor4::white); 654 mImageOverlayColor);
643 break; 655 break;
644 case LLFontGL::HCENTER: 656 case LLFontGL::HCENTER:
645 gl_draw_scaled_image( 657 gl_draw_scaled_image(
@@ -648,7 +660,7 @@ void LLButton::draw()
648 overlay_width, 660 overlay_width,
649 overlay_height, 661 overlay_height,
650 mImageOverlay, 662 mImageOverlay,
651 LLColor4::white); 663 mImageOverlayColor);
652 break; 664 break;
653 case LLFontGL::RIGHT: 665 case LLFontGL::RIGHT:
654 gl_draw_scaled_image( 666 gl_draw_scaled_image(
@@ -657,7 +669,7 @@ void LLButton::draw()
657 overlay_width, 669 overlay_width,
658 overlay_height, 670 overlay_height,
659 mImageOverlay, 671 mImageOverlay,
660 LLColor4::white); 672 mImageOverlayColor);
661 break; 673 break;
662 default: 674 default:
663 // draw nothing 675 // draw nothing
@@ -761,6 +773,7 @@ void LLButton::setToggleState(BOOL b)
761void LLButton::setValue(const LLSD& value ) 773void LLButton::setValue(const LLSD& value )
762{ 774{
763 mToggleState = value.asBoolean(); 775 mToggleState = value.asBoolean();
776 mIsDirty = FALSE;
764} 777}
765 778
766LLSD LLButton::getValue() const 779LLSD LLButton::getValue() const
@@ -876,7 +889,7 @@ void LLButton::setHoverImages( const LLString& image_name, const LLString& selec
876 setImageHoverSelected(selected_name); 889 setImageHoverSelected(selected_name);
877} 890}
878 891
879void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment) 892void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment, const LLColor4& color)
880{ 893{
881 if (image_name.empty()) 894 if (image_name.empty())
882 { 895 {
@@ -887,6 +900,7 @@ void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alig
887 LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name); 900 LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name);
888 mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id); 901 mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id);
889 mImageOverlayAlignment = alignment; 902 mImageOverlayAlignment = alignment;
903 mImageOverlayColor = color;
890 } 904 }
891} 905}
892 906
diff --git a/linden/indra/llui/llbutton.h b/linden/indra/llui/llbutton.h
index 6e11779..aedc411 100644
--- a/linden/indra/llui/llbutton.h
+++ b/linden/indra/llui/llbutton.h
@@ -100,6 +100,8 @@ public:
100 // HACK: "committing" a button is the same as clicking on it. 100 // HACK: "committing" a button is the same as clicking on it.
101 virtual void onCommit(); 101 virtual void onCommit();
102 102
103 virtual BOOL isDirty() { return mIsDirty; }; // Returns TRUE if the user has clicked on the button at all
104
103 void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } 105 void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; }
104 void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } 106 void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; }
105 107
@@ -142,7 +144,7 @@ public:
142 144
143 void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } 145 void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; }
144 146
145 void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER); 147 void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
146 LLPointer<LLImageGL> getImageOverlay() { return mImageOverlay; } 148 LLPointer<LLImageGL> getImageOverlay() { return mImageOverlay; }
147 149
148 150
@@ -208,6 +210,7 @@ protected:
208 210
209 LLPointer<LLImageGL> mImageOverlay; 211 LLPointer<LLImageGL> mImageOverlay;
210 LLFontGL::HAlign mImageOverlayAlignment; 212 LLFontGL::HAlign mImageOverlayAlignment;
213 LLColor4 mImageOverlayColor;
211 214
212 LLPointer<LLImageGL> mImageUnselected; 215 LLPointer<LLImageGL> mImageUnselected;
213 LLUIString mUnselectedLabel; 216 LLUIString mUnselectedLabel;
@@ -276,6 +279,8 @@ protected:
276 279
277 LLPointer<LLImageGL> mImagep; 280 LLPointer<LLImageGL> mImagep;
278 281
282 BOOL mIsDirty;
283
279 static LLFrameTimer sFlashingTimer; 284 static LLFrameTimer sFlashingTimer;
280}; 285};
281 286
diff --git a/linden/indra/llui/llcheckboxctrl.cpp b/linden/indra/llui/llcheckboxctrl.cpp
index 5f3350e..24cf680 100644
--- a/linden/indra/llui/llcheckboxctrl.cpp
+++ b/linden/indra/llui/llcheckboxctrl.cpp
@@ -267,6 +267,18 @@ void LLCheckBoxCtrl::setControlName(const LLString& control_name, LLView* contex
267 mButton->setControlName(control_name, context); 267 mButton->setControlName(control_name, context);
268} 268}
269 269
270
271// virtual Returns TRUE if the user has modified this control.
272BOOL LLCheckBoxCtrl::isDirty()
273{
274 if ( mButton )
275 {
276 return mButton->isDirty();
277 }
278 return FALSE; // Shouldn't get here
279}
280
281
270// virtual 282// virtual
271LLXMLNodePtr LLCheckBoxCtrl::getXML(bool save_children) const 283LLXMLNodePtr LLCheckBoxCtrl::getXML(bool save_children) const
272{ 284{
diff --git a/linden/indra/llui/llcheckboxctrl.h b/linden/indra/llui/llcheckboxctrl.h
index 1b895cb..37b1330 100644
--- a/linden/indra/llui/llcheckboxctrl.h
+++ b/linden/indra/llui/llcheckboxctrl.h
@@ -110,6 +110,8 @@ public:
110 110
111 static void onButtonPress(void *userdata); 111 static void onButtonPress(void *userdata);
112 112
113 virtual BOOL isDirty(); // Returns TRUE if the user has modified this control.
114
113protected: 115protected:
114 // note: value is stored in toggle state of button 116 // note: value is stored in toggle state of button
115 LLButton* mButton; 117 LLButton* mButton;
diff --git a/linden/indra/llui/llctrlselectioninterface.h b/linden/indra/llui/llctrlselectioninterface.h
index 878648d..e21f039 100644
--- a/linden/indra/llui/llctrlselectioninterface.h
+++ b/linden/indra/llui/llctrlselectioninterface.h
@@ -51,6 +51,8 @@ public:
51 51
52 virtual BOOL getCanSelect() const = 0; 52 virtual BOOL getCanSelect() const = 0;
53 53
54 virtual S32 getItemCount() const = 0;
55
54 virtual BOOL selectFirstItem() = 0; 56 virtual BOOL selectFirstItem() = 0;
55 virtual BOOL selectNthItem( S32 index ) = 0; 57 virtual BOOL selectNthItem( S32 index ) = 0;
56 58
@@ -76,7 +78,6 @@ class LLCtrlListInterface : public LLCtrlSelectionInterface
76public: 78public:
77 virtual ~LLCtrlListInterface(); 79 virtual ~LLCtrlListInterface();
78 80
79 virtual S32 getItemCount() const = 0;
80 virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0; 81 virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM) = 0;
81 virtual void clearColumns() = 0; 82 virtual void clearColumns() = 0;
82 virtual void setColumnLabel(const LLString& column, const LLString& label) = 0; 83 virtual void setColumnLabel(const LLString& column, const LLString& label) = 0;
diff --git a/linden/indra/llui/llfloater.cpp b/linden/indra/llui/llfloater.cpp
index 6ab182f..b45661f 100644
--- a/linden/indra/llui/llfloater.cpp
+++ b/linden/indra/llui/llfloater.cpp
@@ -312,28 +312,32 @@ void LLFloater::init(const LLString& title,
312 { 312 {
313 // Resize bars (sides) 313 // Resize bars (sides)
314 const S32 RESIZE_BAR_THICKNESS = 3; 314 const S32 RESIZE_BAR_THICKNESS = 3;
315 mResizeBar[0] = new LLResizeBar( 315 mResizeBar[LLResizeBar::LEFT] = new LLResizeBar(
316 "resizebar_left", 316 "resizebar_left",
317 this,
317 LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0), 318 LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0),
318 min_width, min_height, LLResizeBar::LEFT ); 319 min_width, S32_MAX, LLResizeBar::LEFT );
319 addChild( mResizeBar[0] ); 320 addChild( mResizeBar[0] );
320 321
321 mResizeBar[1] = new LLResizeBar( 322 mResizeBar[LLResizeBar::TOP] = new LLResizeBar(
322 "resizebar_top", 323 "resizebar_top",
324 this,
323 LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS), 325 LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS),
324 min_width, min_height, LLResizeBar::TOP ); 326 min_height, S32_MAX, LLResizeBar::TOP );
325 addChild( mResizeBar[1] ); 327 addChild( mResizeBar[1] );
326 328
327 mResizeBar[2] = new LLResizeBar( 329 mResizeBar[LLResizeBar::RIGHT] = new LLResizeBar(
328 "resizebar_right", 330 "resizebar_right",
331 this,
329 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), 332 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
330 min_width, min_height, LLResizeBar::RIGHT ); 333 min_width, S32_MAX, LLResizeBar::RIGHT );
331 addChild( mResizeBar[2] ); 334 addChild( mResizeBar[2] );
332 335
333 mResizeBar[3] = new LLResizeBar( 336 mResizeBar[LLResizeBar::BOTTOM] = new LLResizeBar(
334 "resizebar_bottom", 337 "resizebar_bottom",
338 this,
335 LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0), 339 LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0),
336 min_width, min_height, LLResizeBar::BOTTOM ); 340 min_height, S32_MAX, LLResizeBar::BOTTOM );
337 addChild( mResizeBar[3] ); 341 addChild( mResizeBar[3] );
338 342
339 343
@@ -367,18 +371,6 @@ void LLFloater::init(const LLString& title,
367 LLResizeHandle::LEFT_TOP ); 371 LLResizeHandle::LEFT_TOP );
368 addChild(mResizeHandle[3]); 372 addChild(mResizeHandle[3]);
369 } 373 }
370 else
371 {
372 mResizeBar[0] = NULL;
373 mResizeBar[1] = NULL;
374 mResizeBar[2] = NULL;
375 mResizeBar[3] = NULL;
376
377 mResizeHandle[0] = NULL;
378 mResizeHandle[1] = NULL;
379 mResizeHandle[2] = NULL;
380 mResizeHandle[3] = NULL;
381 }
382 374
383 // Close button. 375 // Close button.
384 if (close_btn) 376 if (close_btn)
@@ -392,6 +384,13 @@ void LLFloater::init(const LLString& title,
392 mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; 384 mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
393 } 385 }
394 386
387 // Keep track of whether this window has ever been dragged while it
388 // was minimized. If it has, we'll remember its position for the
389 // next time it's minimized.
390 mHasBeenDraggedWhileMinimized = FALSE;
391 mPreviousMinimizedLeft = 0;
392 mPreviousMinimizedBottom = 0;
393
395 buildButtons(); 394 buildButtons();
396 395
397 // JC - Don't do this here, because many floaters first construct themselves, 396 // JC - Don't do this here, because many floaters first construct themselves,
@@ -626,7 +625,14 @@ void LLFloater::setResizeLimits( S32 min_width, S32 min_height )
626 { 625 {
627 if( mResizeBar[i] ) 626 if( mResizeBar[i] )
628 { 627 {
629 mResizeBar[i]->setResizeLimits( min_width, min_height ); 628 if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
629 {
630 mResizeBar[i]->setResizeLimits( min_width, S32_MAX );
631 }
632 else
633 {
634 mResizeBar[i]->setResizeLimits( min_height, S32_MAX );
635 }
630 } 636 }
631 if( mResizeHandle[i] ) 637 if( mResizeHandle[i] )
632 { 638 {
@@ -678,6 +684,25 @@ const LLString& LLFloater::getTitle() const
678 return mDragHandle ? mDragHandle->getTitle() : LLString::null; 684 return mDragHandle ? mDragHandle->getTitle() : LLString::null;
679} 685}
680 686
687void LLFloater::setShortTitle( const LLString& short_title )
688{
689 mShortTitle = short_title;
690}
691
692LLString LLFloater::getShortTitle()
693{
694 if (mShortTitle.empty())
695 {
696 return mDragHandle ? mDragHandle->getTitle() : LLString::null;
697 }
698 else
699 {
700 return mShortTitle;
701 }
702}
703
704
705
681BOOL LLFloater::canSnapTo(LLView* other_view) 706BOOL LLFloater::canSnapTo(LLView* other_view)
682{ 707{
683 if (NULL == other_view) 708 if (NULL == other_view)
@@ -757,6 +782,16 @@ void LLFloater::userSetShape(const LLRect& new_rect)
757 } 782 }
758 } 783 }
759 } 784 }
785 else
786 {
787 // If minimized, and origin has changed, set
788 // mHasBeenDraggedWhileMinimized to TRUE
789 if ((new_rect.mLeft != old_rect.mLeft) ||
790 (new_rect.mBottom != old_rect.mBottom))
791 {
792 mHasBeenDraggedWhileMinimized = TRUE;
793 }
794 }
760} 795}
761 796
762void LLFloater::setMinimized(BOOL minimize) 797void LLFloater::setMinimized(BOOL minimize)
@@ -769,9 +804,19 @@ void LLFloater::setMinimized(BOOL minimize)
769 804
770 reshape( MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE, TRUE); 805 reshape( MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE, TRUE);
771 806
772 S32 left, bottom; 807 // If the floater has been dragged while minimized in the
773 gFloaterView->getMinimizePosition(&left, &bottom); 808 // past, then locate it at its previous minimized location.
774 setOrigin( left, bottom ); 809 // Otherwise, ask the view for a minimize position.
810 if (mHasBeenDraggedWhileMinimized)
811 {
812 setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
813 }
814 else
815 {
816 S32 left, bottom;
817 gFloaterView->getMinimizePosition(&left, &bottom);
818 setOrigin( left, bottom );
819 }
775 820
776 if (mButtonsEnabled[BUTTON_MINIMIZE]) 821 if (mButtonsEnabled[BUTTON_MINIMIZE])
777 { 822 {
@@ -824,6 +869,15 @@ void LLFloater::setMinimized(BOOL minimize)
824 } 869 }
825 else 870 else
826 { 871 {
872 // If this window has been dragged while minimized (at any time),
873 // remember its position for the next time it's minimized.
874 if (mHasBeenDraggedWhileMinimized)
875 {
876 const LLRect& currentRect = getRect();
877 mPreviousMinimizedLeft = currentRect.mLeft;
878 mPreviousMinimizedBottom = currentRect.mBottom;
879 }
880
827 reshape( mPreviousRect.getWidth(), mPreviousRect.getHeight(), TRUE ); 881 reshape( mPreviousRect.getWidth(), mPreviousRect.getHeight(), TRUE );
828 setOrigin( mPreviousRect.mLeft, mPreviousRect.mBottom ); 882 setOrigin( mPreviousRect.mLeft, mPreviousRect.mBottom );
829 883
@@ -987,12 +1041,22 @@ void LLFloater::setHost(LLMultiFloater* host)
987 } 1041 }
988} 1042}
989 1043
990void LLFloater::moveResizeHandleToFront() 1044void LLFloater::moveResizeHandlesToFront()
991{ 1045{
992 // 0 is the bottom right 1046 for( S32 i = 0; i < 4; i++ )
993 if( mResizeHandle[0] )
994 { 1047 {
995 sendChildToFront(mResizeHandle[0]); 1048 if( mResizeBar[i] )
1049 {
1050 sendChildToFront(mResizeBar[i]);
1051 }
1052 }
1053
1054 for( S32 i = 0; i < 4; i++ )
1055 {
1056 if( mResizeHandle[i] )
1057 {
1058 sendChildToFront(mResizeHandle[i]);
1059 }
996 } 1060 }
997} 1061}
998 1062
@@ -1040,7 +1104,6 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
1040 if( mMinimized ) 1104 if( mMinimized )
1041 { 1105 {
1042 // Offer the click to the close button. 1106 // Offer the click to the close button.
1043 // Any other click = restore
1044 if( mButtonsEnabled[BUTTON_CLOSE] ) 1107 if( mButtonsEnabled[BUTTON_CLOSE] )
1045 { 1108 {
1046 S32 local_x = x - mButtons[BUTTON_CLOSE]->getRect().mLeft; 1109 S32 local_x = x - mButtons[BUTTON_CLOSE]->getRect().mLeft;
@@ -1054,9 +1117,22 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
1054 } 1117 }
1055 } 1118 }
1056 1119
1057 // restore 1120 // Offer the click to the restore button.
1058 bringToFront( x, y ); 1121 if( mButtonsEnabled[BUTTON_RESTORE] )
1059 return TRUE; 1122 {
1123 S32 local_x = x - mButtons[BUTTON_RESTORE]->getRect().mLeft;
1124 S32 local_y = y - mButtons[BUTTON_RESTORE]->getRect().mBottom;
1125
1126 if (mButtons[BUTTON_RESTORE]->pointInView(local_x, local_y)
1127 && mButtons[BUTTON_RESTORE]->handleMouseDown(local_x, local_y, mask))
1128 {
1129 // restore button handled it, return
1130 return TRUE;
1131 }
1132 }
1133
1134 // Otherwise pass to drag handle for movement
1135 return mDragHandle->handleMouseDown(x, y, mask);
1060 } 1136 }
1061 else 1137 else
1062 { 1138 {
@@ -1177,6 +1253,10 @@ BOOL LLFloater::getEditModeEnabled()
1177void LLFloater::show(LLFloater* floaterp) 1253void LLFloater::show(LLFloater* floaterp)
1178{ 1254{
1179 if (floaterp) floaterp->open(); 1255 if (floaterp) floaterp->open();
1256 if (floaterp->getHost())
1257 {
1258 floaterp->getHost()->open();
1259 }
1180} 1260}
1181 1261
1182//static 1262//static
@@ -1190,7 +1270,7 @@ BOOL LLFloater::visible(LLFloater* floaterp)
1190{ 1270{
1191 if (floaterp) 1271 if (floaterp)
1192 { 1272 {
1193 return floaterp->isInVisibleChain(); 1273 return !floaterp->isMinimized() && floaterp->isInVisibleChain();
1194 } 1274 }
1195 return FALSE; 1275 return FALSE;
1196} 1276}
@@ -1217,12 +1297,15 @@ void LLFloater::onClickTearOff(void *userdata)
1217 // reparent to floater view 1297 // reparent to floater view
1218 gFloaterView->addChild(self); 1298 gFloaterView->addChild(self);
1219 1299
1220 new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->mRect.getWidth(), self->mRect.getHeight());
1221
1222 self->open(); /* Flawfinder: ignore */ 1300 self->open(); /* Flawfinder: ignore */
1223 self->setRect(new_rect); 1301
1302 // only force position for floaters that don't have that data saved
1303 if (self->mRectControl.empty())
1304 {
1305 new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->mRect.getWidth(), self->mRect.getHeight());
1306 self->setRect(new_rect);
1307 }
1224 gFloaterView->adjustToFitScreen(self, FALSE); 1308 gFloaterView->adjustToFitScreen(self, FALSE);
1225 self->setCanDrag(TRUE);
1226 // give focus to new window to keep continuity for the user 1309 // give focus to new window to keep continuity for the user
1227 self->setFocus(TRUE); 1310 self->setFocus(TRUE);
1228 } 1311 }
@@ -1232,6 +1315,8 @@ void LLFloater::onClickTearOff(void *userdata)
1232 if (new_host) 1315 if (new_host)
1233 { 1316 {
1234 new_host->showFloater(self); 1317 new_host->showFloater(self);
1318 // make sure host is visible
1319 new_host->open();
1235 } 1320 }
1236 } 1321 }
1237} 1322}
@@ -1468,30 +1553,14 @@ void LLFloater::setCanResize(BOOL can_resize)
1468{ 1553{
1469 if (mResizable && !can_resize) 1554 if (mResizable && !can_resize)
1470 { 1555 {
1471 removeChild(mResizeBar[0]); 1556 for (S32 i = 0; i < 4; i++)
1472 removeChild(mResizeBar[1]); 1557 {
1473 removeChild(mResizeBar[2]); 1558 removeChild(mResizeBar[i], TRUE);
1474 removeChild(mResizeBar[3]); 1559 mResizeBar[i] = NULL;
1475 removeChild(mResizeHandle[0]); 1560
1476 removeChild(mResizeHandle[1]); 1561 removeChild(mResizeHandle[i], TRUE);
1477 removeChild(mResizeHandle[2]); 1562 mResizeHandle[i] = NULL;
1478 removeChild(mResizeHandle[3]); 1563 }
1479 delete mResizeBar[0];
1480 delete mResizeBar[1];
1481 delete mResizeBar[2];
1482 delete mResizeBar[3];
1483 delete mResizeHandle[0];
1484 delete mResizeHandle[1];
1485 delete mResizeHandle[2];
1486 mResizeHandle[3] = NULL;
1487 mResizeBar[0] = NULL;
1488 mResizeBar[1] = NULL;
1489 mResizeBar[2] = NULL;
1490 mResizeBar[3] = NULL;
1491 mResizeHandle[0] = NULL;
1492 mResizeHandle[1] = NULL;
1493 mResizeHandle[2] = NULL;
1494 mResizeHandle[3] = NULL;
1495 } 1564 }
1496 else if (!mResizable && can_resize) 1565 else if (!mResizable && can_resize)
1497 { 1566 {
@@ -1499,26 +1568,30 @@ void LLFloater::setCanResize(BOOL can_resize)
1499 const S32 RESIZE_BAR_THICKNESS = 3; 1568 const S32 RESIZE_BAR_THICKNESS = 3;
1500 mResizeBar[0] = new LLResizeBar( 1569 mResizeBar[0] = new LLResizeBar(
1501 "resizebar_left", 1570 "resizebar_left",
1571 this,
1502 LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0), 1572 LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0),
1503 mMinWidth, mMinHeight, LLResizeBar::LEFT ); 1573 mMinWidth, S32_MAX, LLResizeBar::LEFT );
1504 addChild( mResizeBar[0] ); 1574 addChild( mResizeBar[0] );
1505 1575
1506 mResizeBar[1] = new LLResizeBar( 1576 mResizeBar[1] = new LLResizeBar(
1507 "resizebar_top", 1577 "resizebar_top",
1578 this,
1508 LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS), 1579 LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS),
1509 mMinWidth, mMinHeight, LLResizeBar::TOP ); 1580 mMinHeight, S32_MAX, LLResizeBar::TOP );
1510 addChild( mResizeBar[1] ); 1581 addChild( mResizeBar[1] );
1511 1582
1512 mResizeBar[2] = new LLResizeBar( 1583 mResizeBar[2] = new LLResizeBar(
1513 "resizebar_right", 1584 "resizebar_right",
1585 this,
1514 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), 1586 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
1515 mMinWidth, mMinHeight, LLResizeBar::RIGHT ); 1587 mMinWidth, S32_MAX, LLResizeBar::RIGHT );
1516 addChild( mResizeBar[2] ); 1588 addChild( mResizeBar[2] );
1517 1589
1518 mResizeBar[3] = new LLResizeBar( 1590 mResizeBar[3] = new LLResizeBar(
1519 "resizebar_bottom", 1591 "resizebar_bottom",
1592 this,
1520 LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0), 1593 LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0),
1521 mMinWidth, mMinHeight, LLResizeBar::BOTTOM ); 1594 mMinHeight, S32_MAX, LLResizeBar::BOTTOM );
1522 addChild( mResizeBar[3] ); 1595 addChild( mResizeBar[3] );
1523 1596
1524 1597
@@ -1855,7 +1928,7 @@ LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLF
1855 sibling->getVisible() && 1928 sibling->getVisible() &&
1856 expanded_base_rect.rectInRect(&sibling->getRect())) 1929 expanded_base_rect.rectInRect(&sibling->getRect()))
1857 { 1930 {
1858 base_rect |= sibling->getRect(); 1931 base_rect.unionWith(sibling->getRect());
1859 } 1932 }
1860 } 1933 }
1861 1934
@@ -2550,18 +2623,22 @@ BOOL LLMultiFloater::closeAllFloaters()
2550 return TRUE; //else all tabs were successfully closed... 2623 return TRUE; //else all tabs were successfully closed...
2551} 2624}
2552 2625
2553void LLMultiFloater::growToFit(LLFloater* floaterp, S32 width, S32 height) 2626void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
2554{ 2627{
2555 floater_data_map_t::iterator found_data_it; 2628 S32 new_width = llmax(mRect.getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
2556 found_data_it = mFloaterDataMap.find(floaterp->getHandle()); 2629 S32 new_height = llmax(mRect.getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
2557 if (found_data_it != mFloaterDataMap.end()) 2630
2631 if (isMinimized())
2558 { 2632 {
2559 // store new width and height with this floater so that it will keep its size when detached 2633 mPreviousRect.setLeftTopAndSize(mPreviousRect.mLeft, mPreviousRect.mTop, new_width, new_height);
2560 found_data_it->second.mWidth = width; 2634 }
2561 found_data_it->second.mHeight = height; 2635 else
2636 {
2637 S32 old_height = mRect.getHeight();
2638 reshape(new_width, new_height);
2639 // keep top left corner in same position
2640 translate(0, old_height - new_height);
2562 } 2641 }
2563
2564 resizeToContents();
2565} 2642}
2566 2643
2567/** 2644/**
@@ -2618,12 +2695,18 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
2618 floaterp->setCanMinimize(FALSE); 2695 floaterp->setCanMinimize(FALSE);
2619 floaterp->setCanResize(FALSE); 2696 floaterp->setCanResize(FALSE);
2620 floaterp->setCanDrag(FALSE); 2697 floaterp->setCanDrag(FALSE);
2698 floaterp->storeRectControl();
2699
2700 if (mAutoResize)
2701 {
2702 growToFit(floater_data.mWidth, floater_data.mHeight);
2703 }
2621 2704
2622 //add the panel, add it to proper maps 2705 //add the panel, add it to proper maps
2623 mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); 2706 mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point);
2624 mFloaterDataMap[floaterp->getHandle()] = floater_data; 2707 mFloaterDataMap[floaterp->getHandle()] = floater_data;
2625 2708
2626 resizeToContents(); 2709 updateResizeLimits();
2627 2710
2628 if ( select_added_floater ) 2711 if ( select_added_floater )
2629 { 2712 {
@@ -2673,7 +2756,6 @@ void LLMultiFloater::showFloater(LLFloater* floaterp)
2673 { 2756 {
2674 addFloater(floaterp, TRUE); 2757 addFloater(floaterp, TRUE);
2675 } 2758 }
2676 setVisibleAndFrontmost();
2677} 2759}
2678 2760
2679void LLMultiFloater::removeFloater(LLFloater* floaterp) 2761void LLMultiFloater::removeFloater(LLFloater* floaterp)
@@ -2696,9 +2778,11 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp)
2696 } 2778 }
2697 mTabContainer->removeTabPanel(floaterp); 2779 mTabContainer->removeTabPanel(floaterp);
2698 floaterp->setBackgroundVisible(TRUE); 2780 floaterp->setBackgroundVisible(TRUE);
2781 floaterp->setCanDrag(TRUE);
2699 floaterp->setHost(NULL); 2782 floaterp->setHost(NULL);
2783 floaterp->applyRectControl();
2700 2784
2701 resizeToContents(); 2785 updateResizeLimits();
2702 2786
2703 tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); 2787 tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
2704} 2788}
@@ -2840,18 +2924,8 @@ BOOL LLMultiFloater::postBuild()
2840 return FALSE; 2924 return FALSE;
2841} 2925}
2842 2926
2843void LLMultiFloater::resizeToContents() 2927void LLMultiFloater::updateResizeLimits()
2844{ 2928{
2845 // we're already in the middle of a reshape, don't interrupt it
2846 floater_data_map_t::iterator floater_it;
2847 S32 new_width = 0;
2848 S32 new_height = 0;
2849 for (floater_it = mFloaterDataMap.begin(); floater_it != mFloaterDataMap.end(); ++floater_it)
2850 {
2851 new_width = llmax(new_width, floater_it->second.mWidth + LLPANEL_BORDER_WIDTH * 2);
2852 new_height = llmax(new_height, floater_it->second.mHeight + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
2853 }
2854
2855 S32 new_min_width = 0; 2929 S32 new_min_width = 0;
2856 S32 new_min_height = 0; 2930 S32 new_min_height = 0;
2857 S32 tab_idx; 2931 S32 tab_idx;
@@ -2867,21 +2941,23 @@ void LLMultiFloater::resizeToContents()
2867 setResizeLimits(new_min_width, new_min_height); 2941 setResizeLimits(new_min_width, new_min_height);
2868 2942
2869 S32 cur_height = mRect.getHeight(); 2943 S32 cur_height = mRect.getHeight();
2944 S32 new_width = llmax(mRect.getWidth(), new_min_width);
2945 S32 new_height = llmax(mRect.getHeight(), new_min_height);
2870 2946
2871 if (mAutoResize) 2947 if (isMinimized())
2872 { 2948 {
2873 reshape(new_width, new_height); 2949 mPreviousRect.setLeftTopAndSize(mPreviousRect.mLeft, mPreviousRect.mTop, llmax(mPreviousRect.getWidth(), new_width), llmax(mPreviousRect.getHeight(), new_height));
2874 } 2950 }
2875 else 2951 else
2876 { 2952 {
2877 reshape(llmax(new_min_width, mRect.getWidth()), llmax(new_min_height, mRect.getHeight())); 2953 reshape(new_width, new_height);
2878 }
2879 2954
2880 // make sure upper left corner doesn't move 2955 // make sure upper left corner doesn't move
2881 translate(0, cur_height - mRect.getHeight()); 2956 translate(0, cur_height - mRect.getHeight());
2882 2957
2883 // Try to keep whole view onscreen, don't allow partial offscreen. 2958 // Try to keep whole view onscreen, don't allow partial offscreen.
2884 gFloaterView->adjustToFitScreen(this, FALSE); 2959 gFloaterView->adjustToFitScreen(this, FALSE);
2960 }
2885} 2961}
2886 2962
2887// virtual 2963// virtual
@@ -2937,6 +3013,7 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
2937{ 3013{
2938 LLString name(getName()); 3014 LLString name(getName());
2939 LLString title(getTitle()); 3015 LLString title(getTitle());
3016 LLString short_title(getShortTitle());
2940 LLString rect_control(""); 3017 LLString rect_control("");
2941 BOOL resizable = isResizable(); 3018 BOOL resizable = isResizable();
2942 S32 min_width = getMinWidth(); 3019 S32 min_width = getMinWidth();
@@ -2948,6 +3025,7 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
2948 3025
2949 node->getAttributeString("name", name); 3026 node->getAttributeString("name", name);
2950 node->getAttributeString("title", title); 3027 node->getAttributeString("title", title);
3028 node->getAttributeString("short_title", short_title);
2951 node->getAttributeString("rect_control", rect_control); 3029 node->getAttributeString("rect_control", rect_control);
2952 node->getAttributeBOOL("can_resize", resizable); 3030 node->getAttributeBOOL("can_resize", resizable);
2953 node->getAttributeBOOL("can_minimize", minimizable); 3031 node->getAttributeBOOL("can_minimize", minimizable);
@@ -2974,6 +3052,8 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
2974 minimizable, 3052 minimizable,
2975 close_btn); 3053 close_btn);
2976 3054
3055 setShortTitle(short_title);
3056
2977 BOOL can_tear_off; 3057 BOOL can_tear_off;
2978 if (node->getAttributeBOOL("can_tear_off", can_tear_off)) 3058 if (node->getAttributeBOOL("can_tear_off", can_tear_off))
2979 { 3059 {
@@ -2988,17 +3068,13 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
2988 LLFloater::setFloaterHost((LLMultiFloater*) this); 3068 LLFloater::setFloaterHost((LLMultiFloater*) this);
2989 } 3069 }
2990 3070
2991 LLXMLNodePtr child; 3071 initChildrenXML(node, factory);
2992 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) 3072
2993 {
2994 factory->createWidget(this, child);
2995 }
2996 if (node->hasName("multi_floater")) 3073 if (node->hasName("multi_floater"))
2997 { 3074 {
2998 LLFloater::setFloaterHost(last_host); 3075 LLFloater::setFloaterHost(last_host);
2999 } 3076 }
3000 3077
3001
3002 BOOL result = postBuild(); 3078 BOOL result = postBuild();
3003 3079
3004 if (!result) 3080 if (!result)
@@ -3011,4 +3087,6 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor
3011 { 3087 {
3012 this->open(); /* Flawfinder: ignore */ 3088 this->open(); /* Flawfinder: ignore */
3013 } 3089 }
3090
3091 moveResizeHandlesToFront();
3014} 3092}
diff --git a/linden/indra/llui/llfloater.h b/linden/indra/llui/llfloater.h
index 8b610e3..baa192a 100644
--- a/linden/indra/llui/llfloater.h
+++ b/linden/indra/llui/llfloater.h
@@ -143,8 +143,10 @@ public:
143 143
144 void setTitle( const LLString& title ); 144 void setTitle( const LLString& title );
145 const LLString& getTitle() const; 145 const LLString& getTitle() const;
146 void setShortTitle( const LLString& short_title );
147 LLString getShortTitle();
146 virtual void setMinimized(BOOL b); 148 virtual void setMinimized(BOOL b);
147 void moveResizeHandleToFront(); 149 void moveResizeHandlesToFront();
148 void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE); 150 void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE);
149 void addDependentFloater(LLViewHandle dependent_handle, BOOL reposition = TRUE); 151 void addDependentFloater(LLViewHandle dependent_handle, BOOL reposition = TRUE);
150 LLFloater* getDependee() { return (LLFloater*)LLFloater::getFloaterByHandle(mDependeeHandle); } 152 LLFloater* getDependee() { return (LLFloater*)LLFloater::getFloaterByHandle(mDependeeHandle); }
@@ -242,6 +244,7 @@ protected:
242 LLRect mPreviousRect; 244 LLRect mPreviousRect;
243 BOOL mForeground; 245 BOOL mForeground;
244 LLViewHandle mDependeeHandle; 246 LLViewHandle mDependeeHandle;
247 LLString mShortTitle;
245 248
246 BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. 249 BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible.
247 250
@@ -281,6 +284,10 @@ protected:
281 static handle_map_t sFloaterMap; 284 static handle_map_t sFloaterMap;
282 285
283 std::vector<LLView*> mMinimizedHiddenChildren; 286 std::vector<LLView*> mMinimizedHiddenChildren;
287
288 BOOL mHasBeenDraggedWhileMinimized;
289 S32 mPreviousMinimizedBottom;
290 S32 mPreviousMinimizedLeft;
284}; 291};
285 292
286///////////////////////////////////////////////////////////// 293/////////////////////////////////////////////////////////////
@@ -367,12 +374,11 @@ public:
367 /*virtual*/ void draw(); 374 /*virtual*/ void draw();
368 /*virtual*/ void setVisible(BOOL visible); 375 /*virtual*/ void setVisible(BOOL visible);
369 /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent); 376 /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
370
371 /*virtual*/ EWidgetType getWidgetType() const; 377 /*virtual*/ EWidgetType getWidgetType() const;
372 /*virtual*/ LLString getWidgetTag() const; 378 /*virtual*/ LLString getWidgetTag() const;
373 379
374 virtual void setCanResize(BOOL can_resize); 380 virtual void setCanResize(BOOL can_resize);
375 virtual void growToFit(LLFloater* floaterp, S32 width, S32 height); 381 virtual void growToFit(S32 content_width, S32 content_height);
376 virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainerCommon::eInsertionPoint insertion_point = LLTabContainerCommon::END); 382 virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainerCommon::eInsertionPoint insertion_point = LLTabContainerCommon::END);
377 383
378 virtual void showFloater(LLFloater* floaterp); 384 virtual void showFloater(LLFloater* floaterp);
@@ -394,7 +400,7 @@ public:
394 void setTabContainer(LLTabContainerCommon* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } 400 void setTabContainer(LLTabContainerCommon* tab_container) { if (!mTabContainer) mTabContainer = tab_container; }
395 static void onTabSelected(void* userdata, bool); 401 static void onTabSelected(void* userdata, bool);
396 402
397 virtual void resizeToContents(); 403 virtual void updateResizeLimits();
398 404
399protected: 405protected:
400 struct LLFloaterData 406 struct LLFloaterData
diff --git a/linden/indra/llui/llfocusmgr.cpp b/linden/indra/llui/llfocusmgr.cpp
index f79164e..f9f3350 100644
--- a/linden/indra/llui/llfocusmgr.cpp
+++ b/linden/indra/llui/llfocusmgr.cpp
@@ -152,8 +152,7 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, FocusLostCallback on_focu
152 152
153 if (lock) 153 if (lock)
154 { 154 {
155 mLockedView = mKeyboardFocus; 155 lockFocus();
156 mKeyboardLockedFocusLostCallback = on_focus_lost;
157 } 156 }
158} 157}
159 158
@@ -312,6 +311,12 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( LLUICtrl* top_view )
312 } 311 }
313} 312}
314 313
314void LLFocusMgr::lockFocus()
315{
316 mLockedView = mKeyboardFocus;
317 mKeyboardLockedFocusLostCallback = mKeyboardFocusLostCallback;
318}
319
315void LLFocusMgr::unlockFocus() 320void LLFocusMgr::unlockFocus()
316{ 321{
317 mLockedView = NULL; 322 mLockedView = NULL;
diff --git a/linden/indra/llui/llfocusmgr.h b/linden/indra/llui/llfocusmgr.h
index e189945..9b7a84e 100644
--- a/linden/indra/llui/llfocusmgr.h
+++ b/linden/indra/llui/llfocusmgr.h
@@ -81,6 +81,7 @@ public:
81 81
82 // All Three 82 // All Three
83 void releaseFocusIfNeeded( LLView* top_view ); 83 void releaseFocusIfNeeded( LLView* top_view );
84 void lockFocus();
84 void unlockFocus(); 85 void unlockFocus();
85 BOOL focusLocked() { return mLockedView != NULL; } 86 BOOL focusLocked() { return mLockedView != NULL; }
86 87
diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h
index e715737..5ff2de7 100644
--- a/linden/indra/llui/lllineeditor.h
+++ b/linden/indra/llui/lllineeditor.h
@@ -127,6 +127,7 @@ public:
127 virtual void setRect(const LLRect& rect); 127 virtual void setRect(const LLRect& rect);
128 virtual BOOL acceptsTextInput() const; 128 virtual BOOL acceptsTextInput() const;
129 virtual void onCommit(); 129 virtual void onCommit();
130 virtual BOOL isDirty() { return ( mText.getString() != mPrevText ); }; // Returns TRUE if the user has changed value at all
130 131
131 // assumes UTF8 text 132 // assumes UTF8 text
132 virtual void setValue(const LLSD& value ); 133 virtual void setValue(const LLSD& value );
diff --git a/linden/indra/llui/llmenugl.cpp b/linden/indra/llui/llmenugl.cpp
index 9530f26..b0d2d9f 100644
--- a/linden/indra/llui/llmenugl.cpp
+++ b/linden/indra/llui/llmenugl.cpp
@@ -172,6 +172,14 @@ LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const
172 out << LLKeyboard::stringFromKey(mAcceleratorKey); 172 out << LLKeyboard::stringFromKey(mAcceleratorKey);
173 173
174 node->createChild("shortcut", TRUE)->setStringValue(out.str()); 174 node->createChild("shortcut", TRUE)->setStringValue(out.str());
175
176#ifdef LL_DARWIN
177 // Write in special tag if this key is really a ctrl combination on the Mac
178 if (mAcceleratorMask & MASK_MAC_CONTROL)
179 {
180 node->createChild("useMacCtrl", TRUE)->setBoolValue( TRUE );
181 }
182#endif // LL_DARWIN
175 } 183 }
176 184
177 return node; 185 return node;
@@ -204,7 +212,7 @@ BOOL LLMenuItemGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
204 212
205BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) 213BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
206{ 214{
207 if( mEnabled && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == mAcceleratorMask) ) 215 if( mEnabled && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
208 { 216 {
209 doIt(); 217 doIt();
210 return TRUE; 218 return TRUE;
@@ -236,7 +244,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
236 for (list_it = listp->begin(); list_it != listp->end(); ++list_it) 244 for (list_it = listp->begin(); list_it != listp->end(); ++list_it)
237 { 245 {
238 accelerator = *list_it; 246 accelerator = *list_it;
239 if ((accelerator->mKey == mAcceleratorKey) && (accelerator->mMask == mAcceleratorMask)) 247 if ((accelerator->mKey == mAcceleratorKey) && (accelerator->mMask == (mAcceleratorMask & MASK_NORMALKEYS)))
240 { 248 {
241 249
242 // *NOTE: get calling code to throw up warning or route 250 // *NOTE: get calling code to throw up warning or route
@@ -260,7 +268,7 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list <LLKeyBinding*> *listp)
260 if (accelerator) 268 if (accelerator)
261 { 269 {
262 accelerator->mKey = mAcceleratorKey; 270 accelerator->mKey = mAcceleratorKey;
263 accelerator->mMask = mAcceleratorMask; 271 accelerator->mMask = (mAcceleratorMask & MASK_NORMALKEYS);
264// accelerator->mName = mLabel; 272// accelerator->mName = mLabel;
265 } 273 }
266 listp->push_back(accelerator);//addData(accelerator); 274 listp->push_back(accelerator);//addData(accelerator);
@@ -284,7 +292,16 @@ void LLMenuItemGL::appendAcceleratorString( LLString& st )
284 // Standard Mac names for modifier keys in menu equivalents 292 // Standard Mac names for modifier keys in menu equivalents
285 // We could use the symbol characters, but they only exist in certain fonts. 293 // We could use the symbol characters, but they only exist in certain fonts.
286 if( mAcceleratorMask & MASK_CONTROL ) 294 if( mAcceleratorMask & MASK_CONTROL )
287 st.append( "Cmd-" ); // Symbol would be "\xE2\x8C\x98" 295 {
296 if ( mAcceleratorMask & MASK_MAC_CONTROL )
297 {
298 st.append( "Ctrl-" );
299 }
300 else
301 {
302 st.append( "Cmd-" ); // Symbol would be "\xE2\x8C\x98"
303 }
304 }
288 if( mAcceleratorMask & MASK_ALT ) 305 if( mAcceleratorMask & MASK_ALT )
289 st.append( "Opt-" ); // Symbol would be "\xE2\x8C\xA5" 306 st.append( "Opt-" ); // Symbol would be "\xE2\x8C\xA5"
290 if( mAcceleratorMask & MASK_SHIFT ) 307 if( mAcceleratorMask & MASK_SHIFT )
@@ -299,7 +316,7 @@ void LLMenuItemGL::appendAcceleratorString( LLString& st )
299#endif 316#endif
300 317
301 LLString keystr = LLKeyboard::stringFromKey( mAcceleratorKey ); 318 LLString keystr = LLKeyboard::stringFromKey( mAcceleratorKey );
302 if ((mAcceleratorMask & (MASK_CONTROL|MASK_ALT|MASK_SHIFT)) && 319 if ((mAcceleratorMask & MASK_NORMALKEYS) &&
303 (keystr[0] == '-' || keystr[0] == '=')) 320 (keystr[0] == '-' || keystr[0] == '='))
304 { 321 {
305 st.append( " " ); 322 st.append( " " );
@@ -998,7 +1015,7 @@ void LLMenuItemCallGL::buildDrawLabel( void )
998 1015
999BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask ) 1016BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask )
1000{ 1017{
1001 if( (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == mAcceleratorMask) ) 1018 if( (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
1002 { 1019 {
1003 LLPointer<LLEvent> fired_event = new LLEvent(this); 1020 LLPointer<LLEvent> fired_event = new LLEvent(this);
1004 fireEvent(fired_event, "on_build"); 1021 fireEvent(fired_event, "on_build");
@@ -1394,9 +1411,9 @@ void LLMenuItemBranchGL::updateBranchParent(LLView* parentp)
1394 } 1411 }
1395} 1412}
1396 1413
1397void LLMenuItemBranchGL::onVisibilityChange( BOOL curVisibilityIn ) 1414void LLMenuItemBranchGL::onVisibilityChange( BOOL new_visibility )
1398{ 1415{
1399 if (curVisibilityIn == FALSE && mBranch->getVisible() && !mBranch->getTornOff()) 1416 if (new_visibility == FALSE && !mBranch->getTornOff())
1400 { 1417 {
1401 mBranch->setVisible(FALSE); 1418 mBranch->setVisible(FALSE);
1402 } 1419 }
@@ -1965,10 +1982,23 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory
1965 child->hasName(LL_MENU_ITEM_CHECK_GL_TAG)) 1982 child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
1966 { 1983 {
1967 MASK mask = 0; 1984 MASK mask = 0;
1985
1986#ifdef LL_DARWIN
1987 // See if this Mac accelerator should really use the ctrl key and not get mapped to cmd
1988 BOOL useMacCtrl = FALSE;
1989 child->getAttributeBOOL("useMacCtrl", useMacCtrl);
1990#endif // LL_DARWIN
1991
1968 LLString shortcut; 1992 LLString shortcut;
1969 child->getAttributeString("shortcut", shortcut); 1993 child->getAttributeString("shortcut", shortcut);
1970 if (shortcut.find("control") != shortcut.npos) 1994 if (shortcut.find("control") != shortcut.npos)
1971 { 1995 {
1996#ifdef LL_DARWIN
1997 if ( useMacCtrl )
1998 {
1999 mask |= MASK_MAC_CONTROL;
2000 }
2001#endif // LL_DARWIN
1972 mask |= MASK_CONTROL; 2002 mask |= MASK_CONTROL;
1973 } 2003 }
1974 if (shortcut.find("alt") != shortcut.npos) 2004 if (shortcut.find("alt") != shortcut.npos)
@@ -2935,6 +2965,12 @@ BOOL LLMenuGL::handleKey( KEY key, MASK mask, BOOL called_from_parent )
2935 2965
2936BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask) 2966BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
2937{ 2967{
2968 // don't handle if not enabled
2969 if(!mEnabled)
2970 {
2971 return FALSE;
2972 }
2973
2938 // Pass down even if not visible 2974 // Pass down even if not visible
2939 item_list_t::iterator item_iter; 2975 item_list_t::iterator item_iter;
2940 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) 2976 for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
diff --git a/linden/indra/llui/llpanel.cpp b/linden/indra/llui/llpanel.cpp
index dfa3f8a..91a327b 100644
--- a/linden/indra/llui/llpanel.cpp
+++ b/linden/indra/llui/llpanel.cpp
@@ -51,9 +51,18 @@
51#include "llviewborder.h" 51#include "llviewborder.h"
52#include "llbutton.h" 52#include "llbutton.h"
53 53
54// LLLayoutStack
55#include "llgl.h"
56#include "llglheaders.h"
57#include "llresizebar.h"
58#include "llcriticaldamp.h"
59
54LLPanel::panel_map_t LLPanel::sPanelMap; 60LLPanel::panel_map_t LLPanel::sPanelMap;
55LLPanel::alert_queue_t LLPanel::sAlertQueue; 61LLPanel::alert_queue_t LLPanel::sAlertQueue;
56 62
63const S32 RESIZE_BAR_OVERLAP = 1;
64const S32 PANEL_STACK_GAP = RESIZE_BAR_HEIGHT;
65
57void LLPanel::init() 66void LLPanel::init()
58{ 67{
59 // mRectControl 68 // mRectControl
@@ -119,13 +128,16 @@ void LLPanel::addBorder(LLViewBorder::EBevel border_bevel,
119 addChild( mBorder ); 128 addChild( mBorder );
120} 129}
121 130
131void LLPanel::removeBorder()
132{
133 delete mBorder;
134 mBorder = NULL;
135}
136
122 137
123LLPanel::~LLPanel() 138LLPanel::~LLPanel()
124{ 139{
125 if( !mRectControl.empty() ) 140 storeRectControl();
126 {
127 LLUI::sConfigGroup->setRect( mRectControl, mRect );
128 }
129 sPanelMap.erase(mViewHandle); 141 sPanelMap.erase(mViewHandle);
130} 142}
131 143
@@ -179,44 +191,41 @@ void LLPanel::setCtrlsEnabled( BOOL b )
179 191
180void LLPanel::draw() 192void LLPanel::draw()
181{ 193{
182 if( getVisible() ) 194 // draw background
195 if( mBgVisible )
183 { 196 {
184 // draw background 197 //RN: I don't see the point of this
185 if( mBgVisible ) 198 S32 left = 0;//LLPANEL_BORDER_WIDTH;
186 { 199 S32 top = mRect.getHeight();// - LLPANEL_BORDER_WIDTH;
187 //RN: I don't see the point of this 200 S32 right = mRect.getWidth();// - LLPANEL_BORDER_WIDTH;
188 S32 left = 0;//LLPANEL_BORDER_WIDTH; 201 S32 bottom = 0;//LLPANEL_BORDER_WIDTH;
189 S32 top = mRect.getHeight();// - LLPANEL_BORDER_WIDTH;
190 S32 right = mRect.getWidth();// - LLPANEL_BORDER_WIDTH;
191 S32 bottom = 0;//LLPANEL_BORDER_WIDTH;
192 202
193 if (mBgOpaque ) 203 if (mBgOpaque )
194 { 204 {
195 gl_rect_2d( left, top, right, bottom, mBgColorOpaque ); 205 gl_rect_2d( left, top, right, bottom, mBgColorOpaque );
196 }
197 else
198 {
199 gl_rect_2d( left, top, right, bottom, mBgColorAlpha );
200 }
201 } 206 }
202 207 else
203 if( mDefaultBtn)
204 { 208 {
205 if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled()) 209 gl_rect_2d( left, top, right, bottom, mBgColorAlpha );
206 {
207 LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
208 BOOL focus_is_child_button = focus_ctrl->getWidgetType() == WIDGET_TYPE_BUTTON && static_cast<LLButton *>(focus_ctrl)->getCommitOnReturn();
209 // only enable default button when current focus is not a return-capturing button
210 mDefaultBtn->setBorderEnabled(!focus_is_child_button);
211 }
212 else
213 {
214 mDefaultBtn->setBorderEnabled(FALSE);
215 }
216 } 210 }
211 }
217 212
218 LLView::draw(); 213 if( mDefaultBtn)
214 {
215 if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled())
216 {
217 LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
218 BOOL focus_is_child_button = focus_ctrl->getWidgetType() == WIDGET_TYPE_BUTTON && static_cast<LLButton *>(focus_ctrl)->getCommitOnReturn();
219 // only enable default button when current focus is not a return-capturing button
220 mDefaultBtn->setBorderEnabled(!focus_is_child_button);
221 }
222 else
223 {
224 mDefaultBtn->setBorderEnabled(FALSE);
225 }
219 } 226 }
227
228 LLView::draw();
220} 229}
221 230
222void LLPanel::refresh() 231void LLPanel::refresh()
@@ -572,7 +581,7 @@ LLXMLNodePtr LLPanel::getXML(bool save_children) const
572 return node; 581 return node;
573} 582}
574 583
575LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parentp, LLUICtrlFactory *factory) 584LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *factory)
576{ 585{
577 LLString name("panel"); 586 LLString name("panel");
578 node->getAttributeString("name", name); 587 node->getAttributeString("name", name);
@@ -581,11 +590,21 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parentp, LLUICtrlFactory *fa
581 // Fall back on a default panel, if there was no special factory. 590 // Fall back on a default panel, if there was no special factory.
582 if (!panelp) 591 if (!panelp)
583 { 592 {
584 panelp = new LLPanel("tab panel"); 593 LLRect rect;
594 createRect(node, rect, parent, LLRect());
595 panelp = new LLPanel(name, rect);
596 panelp->initPanelXML(node, parent, factory);
597 // preserve panel's width and height, but override the location
598 const LLRect& panelrect = panelp->getRect();
599 S32 w = panelrect.getWidth();
600 S32 h = panelrect.getHeight();
601 rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
602 panelp->setRect(rect);
603 }
604 else
605 {
606 panelp->initPanelXML(node, parent, factory);
585 } 607 }
586
587 panelp->initPanelXML(node, parentp, factory);
588
589 return panelp; 608 return panelp;
590} 609}
591 610
@@ -597,11 +616,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
597 616
598 setPanelParameters(node, parent); 617 setPanelParameters(node, parent);
599 618
600 LLXMLNodePtr child; 619 initChildrenXML(node, factory);
601 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
602 {
603 factory->createWidget(this, child);
604 }
605 620
606 LLString xml_filename; 621 LLString xml_filename;
607 node->getAttributeString("filename", xml_filename); 622 node->getAttributeString("filename", xml_filename);
@@ -610,8 +625,16 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
610 625
611 if (!xml_filename.empty()) 626 if (!xml_filename.empty())
612 { 627 {
628 // Preserve postion of embedded panel but allow panel to dictate width/height
629 LLRect rect(getRect());
613 didPost = factory->buildPanel(this, xml_filename, NULL); 630 didPost = factory->buildPanel(this, xml_filename, NULL);
614 } else { 631 S32 w = getRect().getWidth();
632 S32 h = getRect().getHeight();
633 rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
634 setRect(rect);
635 }
636 else
637 {
615 didPost = FALSE; 638 didPost = FALSE;
616 } 639 }
617 640
@@ -624,10 +647,32 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
624 return didPost; 647 return didPost;
625} 648}
626 649
627void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp) 650void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory)
651{
652 LLXMLNodePtr child;
653 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
654 {
655 // look for string declarations for programmatic text
656 if (child->hasName("string"))
657 {
658 LLString string_name;
659 child->getAttributeString("name", string_name);
660 if (!string_name.empty())
661 {
662 mUIStrings[string_name] = LLUIString(child->getTextContents());
663 }
664 }
665 else
666 {
667 factory->createWidget(this, child);
668 }
669 }
670}
671
672void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
628{ 673{
629 /////// Rect, follows, tool_tip, enabled, visible attributes /////// 674 /////// Rect, follows, tool_tip, enabled, visible attributes ///////
630 initFromXML(node, parentp); 675 initFromXML(node, parent);
631 676
632 /////// Border attributes /////// 677 /////// Border attributes ///////
633 BOOL border = FALSE; 678 BOOL border = FALSE;
@@ -652,6 +697,10 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp)
652 697
653 addBorder(bevel_style, border_style, border_thickness); 698 addBorder(bevel_style, border_style, border_thickness);
654 } 699 }
700 else
701 {
702 removeBorder();
703 }
655 704
656 /////// Background attributes /////// 705 /////// Background attributes ///////
657 BOOL background_visible = FALSE; 706 BOOL background_visible = FALSE;
@@ -676,6 +725,30 @@ void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp)
676 setLabel(label); 725 setLabel(label);
677} 726}
678 727
728LLString LLPanel::getFormattedUIString(const LLString& name, const LLString::format_map_t& args) const
729{
730 ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
731 if (found_it != mUIStrings.end())
732 {
733 // make a copy as format works in place
734 LLUIString formatted_string = found_it->second;
735 formatted_string.setArgList(args);
736 return formatted_string.getString();
737 }
738 return LLString::null;
739}
740
741LLUIString LLPanel::getUIString(const LLString& name) const
742{
743 ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
744 if (found_it != mUIStrings.end())
745 {
746 return found_it->second;
747 }
748 return LLUIString(LLString::null);
749}
750
751
679void LLPanel::childSetVisible(const LLString& id, bool visible) 752void LLPanel::childSetVisible(const LLString& id, bool visible)
680{ 753{
681 LLView* child = getChildByName(id, true); 754 LLView* child = getChildByName(id, true);
@@ -1065,3 +1138,493 @@ void LLPanel::childDisplayNotFound()
1065 LLAlertDialog::showXml("FloaterNotFound", args); 1138 LLAlertDialog::showXml("FloaterNotFound", args);
1066} 1139}
1067 1140
1141void LLPanel::storeRectControl()
1142{
1143 if( !mRectControl.empty() )
1144 {
1145 LLUI::sConfigGroup->setRect( mRectControl, mRect );
1146 }
1147}
1148
1149
1150//
1151// LLLayoutStack
1152//
1153struct LLLayoutStack::LLEmbeddedPanel
1154{
1155 LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize) :
1156 mPanel(panelp),
1157 mMinWidth(min_width),
1158 mMinHeight(min_height),
1159 mAutoResize(auto_resize),
1160 mOrientation(orientation),
1161 mVisibleAmt(1.f) // default to fully visible
1162 {
1163 LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
1164 LLRect resize_bar_rect = panelp->getRect();
1165
1166 S32 min_dim;
1167 if (orientation == HORIZONTAL)
1168 {
1169 min_dim = mMinHeight;
1170 }
1171 else
1172 {
1173 min_dim = mMinWidth;
1174 }
1175 mResizeBar = new LLResizeBar("resizer", mPanel, LLRect(), min_dim, S32_MAX, side);
1176 mResizeBar->setEnableSnapping(FALSE);
1177 // panels initialized as hidden should not start out partially visible
1178 if (!mPanel->getVisible())
1179 {
1180 mVisibleAmt = 0.f;
1181 }
1182 }
1183
1184 LLPanel* mPanel;
1185 S32 mMinWidth;
1186 S32 mMinHeight;
1187 BOOL mAutoResize;
1188 LLResizeBar* mResizeBar;
1189 eLayoutOrientation mOrientation;
1190 F32 mVisibleAmt;
1191};
1192
1193LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) :
1194 mOrientation(orientation),
1195 mMinWidth(0),
1196 mMinHeight(0)
1197{
1198}
1199
1200LLLayoutStack::~LLLayoutStack()
1201{
1202}
1203
1204void LLLayoutStack::draw()
1205{
1206 updateLayout();
1207 {
1208 // clip if outside nominal bounds
1209 LLLocalClipRect clip(getLocalRect(), mRect.getWidth() > mMinWidth || mRect.getHeight() > mMinHeight);
1210 e_panel_list_t::iterator panel_it;
1211 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1212 {
1213 LLRect clip_rect = (*panel_it)->mPanel->getRect();
1214 // scale clipping rectangle by visible amount
1215 if (mOrientation == HORIZONTAL)
1216 {
1217 clip_rect.mRight = clip_rect.mLeft + llround(clip_rect.getWidth() * (*panel_it)->mVisibleAmt);
1218 }
1219 else
1220 {
1221 clip_rect.mBottom = clip_rect.mTop - llround(clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
1222 }
1223 LLLocalClipRect clip(clip_rect, (*panel_it)->mVisibleAmt < 1.f);
1224 // only force drawing invisible children if visible amount is non-zero
1225 drawChild((*panel_it)->mPanel, 0, 0, (*panel_it)->mVisibleAmt > 0.f);
1226 }
1227 }
1228}
1229
1230void LLLayoutStack::removeCtrl(LLUICtrl* ctrl)
1231{
1232 LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel((LLPanel*)ctrl);
1233
1234 if (embedded_panelp)
1235 {
1236 mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
1237 delete embedded_panelp;
1238 }
1239
1240 calcMinExtents();
1241
1242 LLView::removeCtrl(ctrl);
1243}
1244
1245void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)
1246{
1247 LLView::reshape(width, height, called_from_parent);
1248 //updateLayout();
1249}
1250
1251LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
1252{
1253 LLXMLNodePtr node = LLView::getXML();
1254 return node;
1255}
1256
1257//static
1258LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
1259{
1260 LLString orientation_string("vertical");
1261 node->getAttributeString("orientation", orientation_string);
1262
1263 eLayoutOrientation orientation = VERTICAL;
1264
1265 if (orientation_string == "horizontal")
1266 {
1267 orientation = HORIZONTAL;
1268 }
1269 else if (orientation_string == "vertical")
1270 {
1271 orientation = VERTICAL;
1272 }
1273 else
1274 {
1275 llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl;
1276 }
1277
1278 LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
1279
1280 layout_stackp->initFromXML(node, parent);
1281
1282 LLXMLNodePtr child;
1283 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
1284 {
1285 if (child->hasName("layout_panel"))
1286 {
1287 S32 min_width = 0;
1288 S32 min_height = 0;
1289 BOOL auto_resize = TRUE;
1290
1291 child->getAttributeS32("min_width", min_width);
1292 child->getAttributeS32("min_height", min_height);
1293 child->getAttributeBOOL("auto_resize", auto_resize);
1294
1295 LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
1296 panelp->setFollowsNone();
1297 if (panelp)
1298 {
1299 layout_stackp->addPanel(panelp, min_width, min_height, auto_resize);
1300 }
1301 }
1302 }
1303
1304 return layout_stackp;
1305}
1306
1307S32 LLLayoutStack::getMinWidth()
1308{
1309 return mMinWidth;
1310}
1311
1312S32 LLLayoutStack::getMinHeight()
1313{
1314 return mMinHeight;
1315}
1316
1317void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index)
1318{
1319 LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize);
1320
1321 mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
1322 addChild(panel);
1323 addChild(embedded_panel->mResizeBar);
1324
1325 // bring all resize bars to the front so that they are clickable even over the panels
1326 // with a bit of overlap
1327 for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1328 {
1329 e_panel_list_t::iterator next_it = panel_it;
1330 ++next_it;
1331
1332 LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
1333 sendChildToFront(resize_barp);
1334 // last resize bar is disabled, since its not between any two panels
1335 if ( next_it == mPanels.end() )
1336 {
1337 resize_barp->setEnabled(FALSE);
1338 }
1339 else
1340 {
1341 resize_barp->setEnabled(TRUE);
1342 }
1343 }
1344
1345 //updateLayout();
1346}
1347
1348void LLLayoutStack::removePanel(LLPanel* panel)
1349{
1350 removeChild(panel);
1351 //updateLayout();
1352}
1353
1354void LLLayoutStack::updateLayout(BOOL force_resize)
1355{
1356 calcMinExtents();
1357
1358 // calculate current extents
1359 S32 cur_width = 0;
1360 S32 cur_height = 0;
1361
1362 const F32 ANIM_OPEN_TIME = 0.02f;
1363 const F32 ANIM_CLOSE_TIME = 0.02f;
1364
1365 e_panel_list_t::iterator panel_it;
1366 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1367 {
1368 LLPanel* panelp = (*panel_it)->mPanel;
1369 if (panelp->getVisible())
1370 {
1371 (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
1372 if ((*panel_it)->mVisibleAmt > 0.99f)
1373 {
1374 (*panel_it)->mVisibleAmt = 1.f;
1375 }
1376 }
1377 else // not visible
1378 {
1379 (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
1380 if ((*panel_it)->mVisibleAmt < 0.001f)
1381 {
1382 (*panel_it)->mVisibleAmt = 0.f;
1383 }
1384 }
1385 if (mOrientation == HORIZONTAL)
1386 {
1387 // all panels get expanded to max of all the minimum dimensions
1388 cur_height = llmax(mMinHeight, panelp->getRect().getHeight());
1389 cur_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt);
1390 if (panel_it != mPanels.end())
1391 {
1392 cur_width += PANEL_STACK_GAP;
1393 }
1394 }
1395 else //VERTICAL
1396 {
1397 cur_width = llmax(mMinWidth, panelp->getRect().getWidth());
1398 cur_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt);
1399 if (panel_it != mPanels.end())
1400 {
1401 cur_height += PANEL_STACK_GAP;
1402 }
1403 }
1404 }
1405
1406 S32 num_resizable_panels = 0;
1407 S32 shrink_headroom_available = 0;
1408 S32 shrink_headroom_total = 0;
1409 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1410 {
1411 // panels that are not fully visible do not count towards shrink headroom
1412 if ((*panel_it)->mVisibleAmt < 1.f)
1413 continue;
1414 // if currently resizing a panel or the panel is flagged as not automatically resizing
1415 // only track total available headroom, but don't use it for automatic resize logic
1416 if ((*panel_it)->mResizeBar->hasMouseCapture() || (!(*panel_it)->mAutoResize && !force_resize))
1417 {
1418 if (mOrientation == HORIZONTAL)
1419 {
1420 shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
1421 }
1422 else //VERTICAL
1423 {
1424 shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
1425 }
1426 }
1427 else
1428 {
1429 num_resizable_panels++;
1430 if (mOrientation == HORIZONTAL)
1431 {
1432 shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
1433 shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
1434 }
1435 else //VERTICAL
1436 {
1437 shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
1438 shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
1439 }
1440 }
1441 }
1442
1443 // positive means panels need to grow, negative means shrink
1444 S32 pixels_to_distribute;
1445 if (mOrientation == HORIZONTAL)
1446 {
1447 pixels_to_distribute = mRect.getWidth() - cur_width;
1448 }
1449 else //VERTICAL
1450 {
1451 pixels_to_distribute = mRect.getHeight() - cur_height;
1452 }
1453
1454 S32 cur_x = 0;
1455 S32 cur_y = mRect.getHeight();
1456
1457 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1458 {
1459 LLPanel* panelp = (*panel_it)->mPanel;
1460
1461 S32 cur_width = panelp->getRect().getWidth();
1462 S32 cur_height = panelp->getRect().getHeight();
1463 S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
1464 S32 new_height = llmax((*panel_it)->mMinHeight, cur_height);
1465
1466 S32 delta_size = 0;
1467
1468 // if panel can automatically resize (not animating, and resize flag set)...
1469 if ((*panel_it)->mVisibleAmt == 1.f && (force_resize || (*panel_it)->mAutoResize) && !(*panel_it)->mResizeBar->hasMouseCapture())
1470 {
1471 if (mOrientation == HORIZONTAL)
1472 {
1473 // if we're shrinking
1474 if (pixels_to_distribute < 0)
1475 {
1476 // shrink proportionally to amount over minimum
1477 delta_size = llround((F32)pixels_to_distribute * (F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available);
1478 }
1479 else
1480 {
1481 // grow all elements equally
1482 delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
1483 }
1484 new_width = llmax((*panel_it)->mMinWidth, panelp->getRect().getWidth() + delta_size);
1485 }
1486 else
1487 {
1488 new_width = llmax(mMinWidth, mRect.getWidth());
1489 }
1490
1491 if (mOrientation == VERTICAL)
1492 {
1493 if (pixels_to_distribute < 0)
1494 {
1495 // shrink proportionally to amount over minimum
1496 delta_size = llround((F32)pixels_to_distribute * (F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available);
1497 }
1498 else
1499 {
1500 delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
1501 }
1502 new_height = llmax((*panel_it)->mMinHeight, panelp->getRect().getHeight() + delta_size);
1503 }
1504 else
1505 {
1506 new_height = llmax(mMinHeight, mRect.getHeight());
1507 }
1508 }
1509 else // don't resize
1510 {
1511 if (mOrientation == HORIZONTAL)
1512 {
1513 new_height = llmax(mMinHeight, mRect.getHeight());
1514 }
1515 else // VERTICAL
1516 {
1517 new_width = llmax(mMinWidth, mRect.getWidth());
1518 }
1519 }
1520
1521 // adjust running headroom count based on new sizes
1522 shrink_headroom_total += delta_size;
1523
1524 panelp->reshape(new_width, new_height);
1525 panelp->setOrigin(cur_x, cur_y - new_height);
1526
1527 LLRect panel_rect = panelp->getRect();
1528 LLRect resize_bar_rect = panel_rect;
1529 if (mOrientation == HORIZONTAL)
1530 {
1531 resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
1532 resize_bar_rect.mRight = panel_rect.mRight + PANEL_STACK_GAP + RESIZE_BAR_OVERLAP;
1533 }
1534 else
1535 {
1536 resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
1537 resize_bar_rect.mBottom = panel_rect.mBottom - PANEL_STACK_GAP - RESIZE_BAR_OVERLAP;
1538 }
1539 (*panel_it)->mResizeBar->setRect(resize_bar_rect);
1540
1541 if (mOrientation == HORIZONTAL)
1542 {
1543 cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP;
1544 }
1545 else //VERTICAL
1546 {
1547 cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + PANEL_STACK_GAP;
1548 }
1549 }
1550
1551 // update resize bars with new limits
1552 LLResizeBar* last_resize_bar = NULL;
1553 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1554 {
1555 LLPanel* panelp = (*panel_it)->mPanel;
1556
1557 if (mOrientation == HORIZONTAL)
1558 {
1559 (*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinWidth, (*panel_it)->mMinWidth + shrink_headroom_total);
1560 }
1561 else //VERTICAL
1562 {
1563 (*panel_it)->mResizeBar->setResizeLimits((*panel_it)->mMinHeight, (*panel_it)->mMinHeight + shrink_headroom_total);
1564 }
1565 // hide resize bars for invisible panels
1566 (*panel_it)->mResizeBar->setVisible(panelp->getVisible());
1567 if (panelp->getVisible())
1568 {
1569 last_resize_bar = (*panel_it)->mResizeBar;
1570 }
1571 }
1572
1573 // hide last resize bar as there is nothing past it
1574 if (last_resize_bar)
1575 {
1576 last_resize_bar->setVisible(FALSE);
1577 }
1578
1579 // not enough room to fit existing contents
1580 if (!force_resize &&
1581 ((cur_y != -PANEL_STACK_GAP) || (cur_x != mRect.getWidth() + PANEL_STACK_GAP)))
1582 {
1583 // do another layout pass with all stacked elements contributing
1584 // even those that don't usually resize
1585 llassert_always(force_resize == FALSE);
1586 updateLayout(TRUE);
1587 }
1588}
1589
1590LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp)
1591{
1592 e_panel_list_t::iterator panel_it;
1593 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1594 {
1595 if ((*panel_it)->mPanel == panelp)
1596 {
1597 return *panel_it;
1598 }
1599 }
1600 return NULL;
1601}
1602
1603void LLLayoutStack::calcMinExtents()
1604{
1605 mMinWidth = 0;
1606 mMinHeight = 0;
1607
1608 e_panel_list_t::iterator panel_it;
1609 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
1610 {
1611 if (mOrientation == HORIZONTAL)
1612 {
1613 mMinHeight = llmax(mMinHeight, (*panel_it)->mMinHeight);
1614 mMinWidth += (*panel_it)->mMinWidth;
1615 if (panel_it != mPanels.begin())
1616 {
1617 mMinWidth += PANEL_STACK_GAP;
1618 }
1619 }
1620 else //VERTICAL
1621 {
1622 mMinWidth = llmax(mMinWidth, (*panel_it)->mMinWidth);
1623 mMinHeight += (*panel_it)->mMinHeight;
1624 if (panel_it != mPanels.begin())
1625 {
1626 mMinHeight += PANEL_STACK_GAP;
1627 }
1628 }
1629 }
1630}
diff --git a/linden/indra/llui/llpanel.h b/linden/indra/llui/llpanel.h
index fea3eee..28c56fa 100644
--- a/linden/indra/llui/llpanel.h
+++ b/linden/indra/llui/llpanel.h
@@ -35,6 +35,7 @@
35#include "llcallbackmap.h" 35#include "llcallbackmap.h"
36#include "lluictrl.h" 36#include "lluictrl.h"
37#include "llviewborder.h" 37#include "llviewborder.h"
38#include "lluistring.h"
38#include "v4color.h" 39#include "v4color.h"
39#include <list> 40#include <list>
40#include <queue> 41#include <queue>
@@ -91,6 +92,8 @@ public:
91 LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE, 92 LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE,
92 S32 border_thickness = LLPANEL_BORDER_WIDTH ); 93 S32 border_thickness = LLPANEL_BORDER_WIDTH );
93 94
95 void removeBorder();
96
94 virtual ~LLPanel(); 97 virtual ~LLPanel();
95 virtual void draw(); 98 virtual void draw();
96 virtual void refresh(); // called in setFocus() 99 virtual void refresh(); // called in setFocus()
@@ -117,6 +120,7 @@ public:
117 LLString getLabel() const { return mLabel; } 120 LLString getLabel() const { return mLabel; }
118 121
119 void setRectControl(const LLString& rect_control) { mRectControl.assign(rect_control); } 122 void setRectControl(const LLString& rect_control) { mRectControl.assign(rect_control); }
123 void storeRectControl();
120 124
121 void setBorderVisible( BOOL b ); 125 void setBorderVisible( BOOL b );
122 126
@@ -136,8 +140,12 @@ public:
136 virtual LLXMLNodePtr getXML(bool save_children = true) const; 140 virtual LLXMLNodePtr getXML(bool save_children = true) const;
137 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); 141 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
138 BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); 142 BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
143 void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory);
139 void setPanelParameters(LLXMLNodePtr node, LLView *parentp); 144 void setPanelParameters(LLXMLNodePtr node, LLView *parentp);
140 145
146 LLString getFormattedUIString(const LLString& name, const LLString::format_map_t& args = LLUIString::sNullArgs) const;
147 LLUIString getUIString(const LLString& name) const;
148
141 // ** Wrappers for setting child properties by name ** -TomY 149 // ** Wrappers for setting child properties by name ** -TomY
142 150
143 // Override to set not found list 151 // Override to set not found list
@@ -216,6 +224,8 @@ public:
216 typedef std::queue<LLAlertInfo> alert_queue_t; 224 typedef std::queue<LLAlertInfo> alert_queue_t;
217 static alert_queue_t sAlertQueue; 225 static alert_queue_t sAlertQueue;
218 226
227 typedef std::map<LLString, LLUIString> ui_string_map_t;
228
219private: 229private:
220 // common constructor 230 // common constructor
221 void init(); 231 void init();
@@ -241,6 +251,8 @@ protected:
241 LLString mLabel; 251 LLString mLabel;
242 S32 mLastTabGroup; 252 S32 mLastTabGroup;
243 253
254 ui_string_map_t mUIStrings;
255
244 typedef std::map<LLString, EWidgetType> requirements_map_t; 256 typedef std::map<LLString, EWidgetType> requirements_map_t;
245 requirements_map_t mRequirements; 257 requirements_map_t mRequirements;
246 258
@@ -248,4 +260,50 @@ protected:
248 static panel_map_t sPanelMap; 260 static panel_map_t sPanelMap;
249}; 261};
250 262
263class LLLayoutStack : public LLView
264{
265public:
266 typedef enum e_layout_orientation
267 {
268 HORIZONTAL,
269 VERTICAL
270 } eLayoutOrientation;
271
272 LLLayoutStack(eLayoutOrientation orientation);
273 virtual ~LLLayoutStack();
274
275 /*virtual*/ void draw();
276 /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
277 /*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
278 /*virtual*/ void removeCtrl(LLUICtrl* ctrl);
279 virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_LAYOUT_STACK; }
280 virtual LLString getWidgetTag() const { return LL_LAYOUT_STACK_TAG; }
281
282 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
283
284 S32 getMinWidth();
285 S32 getMinHeight();
286
287 void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, S32 index = S32_MAX);
288 void removePanel(LLPanel* panel);
289 void updateLayout(BOOL force_resize = FALSE);
290
291protected:
292 struct LLEmbeddedPanel;
293
294 LLEmbeddedPanel* findEmbeddedPanel(LLPanel* panelp);
295 void calcMinExtents();
296 S32 getMinStackSize();
297 S32 getCurStackSize();
298
299protected:
300 eLayoutOrientation mOrientation;
301
302 typedef std::vector<LLEmbeddedPanel*> e_panel_list_t;
303 e_panel_list_t mPanels;
304
305 S32 mMinWidth;
306 S32 mMinHeight;
307};
308
251#endif 309#endif
diff --git a/linden/indra/llui/llradiogroup.cpp b/linden/indra/llui/llradiogroup.cpp
index eda54b1..0104998 100644
--- a/linden/indra/llui/llradiogroup.cpp
+++ b/linden/indra/llui/llradiogroup.cpp
@@ -169,7 +169,7 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
169{ 169{
170 BOOL handled = FALSE; 170 BOOL handled = FALSE;
171 // do any of the tab buttons have keyboard focus? 171 // do any of the tab buttons have keyboard focus?
172 if (getEnabled() && !called_from_parent) 172 if (getEnabled() && !called_from_parent && mask == MASK_NONE)
173 { 173 {
174 switch(key) 174 switch(key)
175 { 175 {
@@ -441,6 +441,69 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
441 return radio_group; 441 return radio_group;
442} 442}
443 443
444// LLCtrlSelectionInterface functions
445BOOL LLRadioGroup::setCurrentByID( const LLUUID& id )
446{
447 return FALSE;
448}
449
450LLUUID LLRadioGroup::getCurrentID()
451{
452 return LLUUID::null;
453}
454
455BOOL LLRadioGroup::setSelectedByValue(LLSD value, BOOL selected)
456{
457 S32 idx = 0;
458 std::string value_string = value.asString();
459 for (button_list_t::const_iterator iter = mRadioButtons.begin();
460 iter != mRadioButtons.end(); ++iter)
461 {
462 if((*iter)->getName() == value_string)
463 {
464 setSelectedIndex(idx);
465 return TRUE;
466 }
467 idx++;
468 }
469
470 return FALSE;
471}
472
473LLSD LLRadioGroup::getSimpleSelectedValue()
474{
475 return getValue();
476}
477
478BOOL LLRadioGroup::isSelected(LLSD value)
479{
480 S32 idx = 0;
481 std::string value_string = value.asString();
482 for (button_list_t::const_iterator iter = mRadioButtons.begin();
483 iter != mRadioButtons.end(); ++iter)
484 {
485 if((*iter)->getName() == value_string)
486 {
487 if (idx == mSelectedIndex)
488 {
489 return TRUE;
490 }
491 }
492 idx++;
493 }
494 return FALSE;
495}
496
497BOOL LLRadioGroup::operateOnSelection(EOperation op)
498{
499 return FALSE;
500}
501
502BOOL LLRadioGroup::operateOnAll(EOperation op)
503{
504 return FALSE;
505}
506
444 507
445LLRadioCtrl::LLRadioCtrl(const LLString& name, const LLRect& rect, const LLString& label, 508LLRadioCtrl::LLRadioCtrl(const LLString& name, const LLRect& rect, const LLString& label,
446 const LLFontGL* font, void (*commit_callback)(LLUICtrl*, void*), void* callback_userdata) : 509 const LLFontGL* font, void (*commit_callback)(LLUICtrl*, void*), void* callback_userdata) :
@@ -458,3 +521,4 @@ void LLRadioCtrl::setValue(const LLSD& value)
458 LLCheckBoxCtrl::setValue(value); 521 LLCheckBoxCtrl::setValue(value);
459 mButton->setTabStop(value.asBoolean()); 522 mButton->setTabStop(value.asBoolean());
460} 523}
524
diff --git a/linden/indra/llui/llradiogroup.h b/linden/indra/llui/llradiogroup.h
index 0cd5901..3dec41d 100644
--- a/linden/indra/llui/llradiogroup.h
+++ b/linden/indra/llui/llradiogroup.h
@@ -35,6 +35,7 @@
35 35
36#include "lluictrl.h" 36#include "lluictrl.h"
37#include "llcheckboxctrl.h" 37#include "llcheckboxctrl.h"
38#include "llctrlselectioninterface.h"
38 39
39class LLFontGL; 40class LLFontGL;
40 41
@@ -52,7 +53,7 @@ public:
52}; 53};
53 54
54class LLRadioGroup 55class LLRadioGroup
55: public LLUICtrl 56: public LLUICtrl, public LLCtrlSelectionInterface
56{ 57{
57public: 58public:
58 // Build a radio group. The number (0...n-1) of the currently selected 59 // Build a radio group. The number (0...n-1) of the currently selected
@@ -83,7 +84,6 @@ public:
83 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); 84 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
84 void setIndexEnabled(S32 index, BOOL enabled); 85 void setIndexEnabled(S32 index, BOOL enabled);
85 86
86 S32 getItemCount() { return mRadioButtons.size(); }
87 // return the index value of the selected item 87 // return the index value of the selected item
88 S32 getSelectedIndex() const; 88 S32 getSelectedIndex() const;
89 89
@@ -107,6 +107,23 @@ public:
107 // button. 107 // button.
108 static void onClickButton(LLUICtrl* radio, void* userdata); 108 static void onClickButton(LLUICtrl* radio, void* userdata);
109 109
110 //========================================================================
111 LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; };
112
113 // LLCtrlSelectionInterface functions
114 /*virtual*/ S32 getItemCount() const { return mRadioButtons.size(); }
115 /*virtual*/ BOOL getCanSelect() const { return TRUE; }
116 /*virtual*/ BOOL selectFirstItem() { return setSelectedIndex(0); }
117 /*virtual*/ BOOL selectNthItem( S32 index ) { return setSelectedIndex(index); }
118 /*virtual*/ S32 getFirstSelectedIndex() { return getSelectedIndex(); }
119 /*virtual*/ BOOL setCurrentByID( const LLUUID& id );
120 /*virtual*/ LLUUID getCurrentID(); // LLUUID::null if no items in menu
121 /*virtual*/ BOOL setSelectedByValue(LLSD value, BOOL selected);
122 /*virtual*/ LLSD getSimpleSelectedValue();
123 /*virtual*/ BOOL isSelected(LLSD value);
124 /*virtual*/ BOOL operateOnSelection(EOperation op);
125 /*virtual*/ BOOL operateOnAll(EOperation op);
126
110protected: 127protected:
111 // protected function shared by the two constructors. 128 // protected function shared by the two constructors.
112 void init(BOOL border); 129 void init(BOOL border);
diff --git a/linden/indra/llui/llresizebar.cpp b/linden/indra/llui/llresizebar.cpp
index 79127a8..f716e8e 100644
--- a/linden/indra/llui/llresizebar.cpp
+++ b/linden/indra/llui/llresizebar.cpp
@@ -38,16 +38,18 @@
38#include "llfocusmgr.h" 38#include "llfocusmgr.h"
39#include "llwindow.h" 39#include "llwindow.h"
40 40
41LLResizeBar::LLResizeBar( const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, Side side ) 41LLResizeBar::LLResizeBar( const LLString& name, LLView* resizing_view, const LLRect& rect, S32 min_size, S32 max_size, Side side )
42 : 42 :
43 LLView( name, rect, TRUE ), 43 LLView( name, rect, TRUE ),
44 mDragLastScreenX( 0 ), 44 mDragLastScreenX( 0 ),
45 mDragLastScreenY( 0 ), 45 mDragLastScreenY( 0 ),
46 mLastMouseScreenX( 0 ), 46 mLastMouseScreenX( 0 ),
47 mLastMouseScreenY( 0 ), 47 mLastMouseScreenY( 0 ),
48 mMinWidth( min_width ), 48 mMinSize( min_size ),
49 mMinHeight( min_height ), 49 mMaxSize( max_size ),
50 mSide( side ) 50 mSide( side ),
51 mSnappingEnabled(TRUE),
52 mResizingView(resizing_view)
51{ 53{
52 // set up some generically good follow code. 54 // set up some generically good follow code.
53 switch( side ) 55 switch( side )
@@ -149,12 +151,11 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
149 // Make sure the mouse in still over the application. We don't want to make the parent 151 // Make sure the mouse in still over the application. We don't want to make the parent
150 // so big that we can't see the resize handle any more. 152 // so big that we can't see the resize handle any more.
151 LLRect valid_rect = getRootView()->getRect(); 153 LLRect valid_rect = getRootView()->getRect();
152 LLView* resizing_view = getParent();
153 154
154 if( valid_rect.localPointInRect( screen_x, screen_y ) && resizing_view ) 155 if( valid_rect.localPointInRect( screen_x, screen_y ) && mResizingView )
155 { 156 {
156 // Resize the parent 157 // Resize the parent
157 LLRect orig_rect = resizing_view->getRect(); 158 LLRect orig_rect = mResizingView->getRect();
158 LLRect scaled_rect = orig_rect; 159 LLRect scaled_rect = orig_rect;
159 160
160 S32 new_width = orig_rect.getWidth(); 161 S32 new_width = orig_rect.getWidth();
@@ -163,76 +164,63 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
163 switch( mSide ) 164 switch( mSide )
164 { 165 {
165 case LEFT: 166 case LEFT:
166 new_width = orig_rect.getWidth() - delta_x; 167 new_width = llclamp(orig_rect.getWidth() - delta_x, mMinSize, mMaxSize);
167 if( new_width < mMinWidth ) 168 delta_x = orig_rect.getWidth() - new_width;
168 {
169 new_width = mMinWidth;
170 delta_x = orig_rect.getWidth() - mMinWidth;
171 }
172 scaled_rect.translate(delta_x, 0); 169 scaled_rect.translate(delta_x, 0);
173 break; 170 break;
174 171
175 case TOP: 172 case TOP:
176 new_height = orig_rect.getHeight() + delta_y; 173 new_height = llclamp(orig_rect.getHeight() + delta_y, mMinSize, mMaxSize);
177 if( new_height < mMinHeight ) 174 delta_y = new_height - orig_rect.getHeight();
178 {
179 new_height = mMinHeight;
180 delta_y = mMinHeight - orig_rect.getHeight();
181 }
182 break; 175 break;
183 176
184 case RIGHT: 177 case RIGHT:
185 new_width = orig_rect.getWidth() + delta_x; 178 new_width = llclamp(orig_rect.getWidth() + delta_x, mMinSize, mMaxSize);
186 if( new_width < mMinWidth ) 179 delta_x = new_width - orig_rect.getWidth();
187 {
188 new_width = mMinWidth;
189 delta_x = mMinWidth - orig_rect.getWidth();
190 }
191 break; 180 break;
192 181
193 case BOTTOM: 182 case BOTTOM:
194 new_height = orig_rect.getHeight() - delta_y; 183 new_height = llclamp(orig_rect.getHeight() - delta_y, mMinSize, mMaxSize);
195 if( new_height < mMinHeight ) 184 delta_y = orig_rect.getHeight() - new_height;
196 {
197 new_height = mMinHeight;
198 delta_y = orig_rect.getHeight() - mMinHeight;
199 }
200 scaled_rect.translate(0, delta_y); 185 scaled_rect.translate(0, delta_y);
201 break; 186 break;
202 } 187 }
203 188
204 scaled_rect.mTop = scaled_rect.mBottom + new_height; 189 scaled_rect.mTop = scaled_rect.mBottom + new_height;
205 scaled_rect.mRight = scaled_rect.mLeft + new_width; 190 scaled_rect.mRight = scaled_rect.mLeft + new_width;
206 resizing_view->setRect(scaled_rect); 191 mResizingView->setRect(scaled_rect);
207 192
208 LLView* snap_view = NULL; 193 LLView* snap_view = NULL;
209 194
210 switch( mSide ) 195 if (mSnappingEnabled)
211 { 196 {
212 case LEFT: 197 switch( mSide )
213 snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); 198 {
214 break; 199 case LEFT:
215 case TOP: 200 snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
216 snap_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); 201 break;
217 break; 202 case TOP:
218 case RIGHT: 203 snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
219 snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); 204 break;
220 break; 205 case RIGHT:
221 case BOTTOM: 206 snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
222 snap_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin")); 207 break;
223 break; 208 case BOTTOM:
209 snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
210 break;
211 }
224 } 212 }
225 213
226 // register "snap" behavior with snapped view 214 // register "snap" behavior with snapped view
227 resizing_view->snappedTo(snap_view); 215 mResizingView->snappedTo(snap_view);
228 216
229 // restore original rectangle so the appropriate changes are detected 217 // restore original rectangle so the appropriate changes are detected
230 resizing_view->setRect(orig_rect); 218 mResizingView->setRect(orig_rect);
231 // change view shape as user operation 219 // change view shape as user operation
232 resizing_view->userSetShape(scaled_rect); 220 mResizingView->userSetShape(scaled_rect);
233 221
234 // update last valid mouse cursor position based on resized view's actual size 222 // update last valid mouse cursor position based on resized view's actual size
235 LLRect new_rect = resizing_view->getRect(); 223 LLRect new_rect = mResizingView->getRect();
236 switch(mSide) 224 switch(mSide)
237 { 225 {
238 case LEFT: 226 case LEFT:
diff --git a/linden/indra/llui/llresizebar.h b/linden/indra/llui/llresizebar.h
index e1fc0f9..d3596ec 100644
--- a/linden/indra/llui/llresizebar.h
+++ b/linden/indra/llui/llresizebar.h
@@ -37,7 +37,7 @@ class LLResizeBar : public LLView
37public: 37public:
38 enum Side { LEFT, TOP, RIGHT, BOTTOM }; 38 enum Side { LEFT, TOP, RIGHT, BOTTOM };
39 39
40 LLResizeBar(const LLString& name, const LLRect& rect, S32 min_width, S32 min_height, Side side ); 40 LLResizeBar(const LLString& name, LLView* resizing_view, const LLRect& rect, S32 min_size, S32 max_size, Side side );
41 41
42 virtual EWidgetType getWidgetType() const; 42 virtual EWidgetType getWidgetType() const;
43 virtual LLString getWidgetTag() const; 43 virtual LLString getWidgetTag() const;
@@ -47,7 +47,8 @@ public:
47 virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); 47 virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
48 virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); 48 virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
49 49
50 void setResizeLimits( S32 min_width, S32 min_height ) { mMinWidth = min_width; mMinHeight = min_height; } 50 void setResizeLimits( S32 min_size, S32 max_size ) { mMinSize = min_size; mMaxSize = max_size; }
51 void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; }
51 52
52protected: 53protected:
53 S32 mDragLastScreenX; 54 S32 mDragLastScreenX;
@@ -55,9 +56,11 @@ protected:
55 S32 mLastMouseScreenX; 56 S32 mLastMouseScreenX;
56 S32 mLastMouseScreenY; 57 S32 mLastMouseScreenY;
57 LLCoordGL mLastMouseDir; 58 LLCoordGL mLastMouseDir;
58 S32 mMinWidth; 59 S32 mMinSize;
59 S32 mMinHeight; 60 S32 mMaxSize;
60 Side mSide; 61 Side mSide;
62 BOOL mSnappingEnabled;
63 LLView* mResizingView;
61}; 64};
62 65
63const S32 RESIZE_BAR_HEIGHT = 3; 66const S32 RESIZE_BAR_HEIGHT = 3;
diff --git a/linden/indra/llui/llresmgr.cpp b/linden/indra/llui/llresmgr.cpp
index 2350093..5ed2cb3 100644
--- a/linden/indra/llui/llresmgr.cpp
+++ b/linden/indra/llui/llresmgr.cpp
@@ -440,6 +440,9 @@ const LLString LLLocale::SYSTEM_LOCALE("English_United States.1252");
440#elif LL_DARWIN 440#elif LL_DARWIN
441const LLString LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLString::null; 441const LLString LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLString::null;
442const LLString LLLocale::SYSTEM_LOCALE("en_US.iso8859-1"); 442const LLString LLLocale::SYSTEM_LOCALE("en_US.iso8859-1");
443#elif LL_SOLARIS
444const LLString LLLocale::USER_LOCALE("en_US.ISO8859-1");
445const LLString LLLocale::SYSTEM_LOCALE("C");
443#else // LL_LINUX likes this 446#else // LL_LINUX likes this
444const LLString LLLocale::USER_LOCALE("en_US.utf8"); 447const LLString LLLocale::USER_LOCALE("en_US.utf8");
445const LLString LLLocale::SYSTEM_LOCALE("C"); 448const LLString LLLocale::SYSTEM_LOCALE("C");
diff --git a/linden/indra/llui/llscrollcontainer.cpp b/linden/indra/llui/llscrollcontainer.cpp
index be41aa8..b910964 100644
--- a/linden/indra/llui/llscrollcontainer.cpp
+++ b/linden/indra/llui/llscrollcontainer.cpp
@@ -505,8 +505,7 @@ void LLScrollableContainerView::draw()
505 BOOL show_h_scrollbar = FALSE; 505 BOOL show_h_scrollbar = FALSE;
506 calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar ); 506 calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
507 507
508 LLGLEnable scissor_test(GL_SCISSOR_TEST); 508 LLLocalClipRect clip(LLRect(mInnerRect.mLeft,
509 LLUI::setScissorRegionLocal(LLRect(mInnerRect.mLeft,
510 mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height, 509 mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height,
511 visible_width, 510 visible_width,
512 mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) 511 mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0)
diff --git a/linden/indra/llui/llscrolllistctrl.cpp b/linden/indra/llui/llscrolllistctrl.cpp
index 5571d39..56a6a22 100644
--- a/linden/indra/llui/llscrolllistctrl.cpp
+++ b/linden/indra/llui/llscrolllistctrl.cpp
@@ -51,7 +51,7 @@
51#include "llkeyboard.h" 51#include "llkeyboard.h"
52#include "llresizebar.h" 52#include "llresizebar.h"
53 53
54const S32 LIST_BORDER_PAD = 2; // white space inside the border and to the left of the scrollbar 54const S32 LIST_BORDER_PAD = 0; // white space inside the border and to the left of the scrollbar
55const S32 MIN_COLUMN_WIDTH = 20; 55const S32 MIN_COLUMN_WIDTH = 20;
56const S32 LIST_SNAP_PADDING = 5; 56const S32 LIST_SNAP_PADDING = 5;
57 57
@@ -417,6 +417,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLString& name, const LLRect& rect,
417 mCommitOnKeyboardMovement(TRUE), 417 mCommitOnKeyboardMovement(TRUE),
418 mCommitOnSelectionChange(FALSE), 418 mCommitOnSelectionChange(FALSE),
419 mSelectionChanged(FALSE), 419 mSelectionChanged(FALSE),
420 mNeedsScroll(FALSE),
420 mCanSelect(TRUE), 421 mCanSelect(TRUE),
421 mDisplayColumnHeaders(FALSE), 422 mDisplayColumnHeaders(FALSE),
422 mCollapseEmptyColumns(FALSE), 423 mCollapseEmptyColumns(FALSE),
@@ -1439,14 +1440,16 @@ void LLScrollListCtrl::drawItems()
1439 S32 x = mItemListRect.mLeft; 1440 S32 x = mItemListRect.mLeft;
1440 S32 y = mItemListRect.mTop - mLineHeight; 1441 S32 y = mItemListRect.mTop - mLineHeight;
1441 1442
1442 S32 num_page_lines = mPageLines; 1443 // allow for partial line at bottom
1444 S32 num_page_lines = mPageLines + 1;
1443 1445
1444 LLRect item_rect; 1446 LLRect item_rect;
1445 1447
1446 LLGLSUIDefault gls_ui; 1448 LLGLSUIDefault gls_ui;
1447 1449
1448 { 1450 {
1449 1451 LLLocalClipRect clip(mItemListRect);
1452
1450 S32 cur_x = x; 1453 S32 cur_x = x;
1451 S32 cur_y = y; 1454 S32 cur_y = y;
1452 1455
@@ -1558,6 +1561,11 @@ void LLScrollListCtrl::draw()
1558{ 1561{
1559 if( getVisible() ) 1562 if( getVisible() )
1560 { 1563 {
1564 if (mNeedsScroll)
1565 {
1566 scrollToShowSelected();
1567 mNeedsScroll = FALSE;
1568 }
1561 LLRect background(0, mRect.getHeight(), mRect.getWidth(), 0); 1569 LLRect background(0, mRect.getHeight(), mRect.getWidth(), 0);
1562 // Draw background 1570 // Draw background
1563 if (mBackgroundVisible) 1571 if (mBackgroundVisible)
@@ -1710,6 +1718,7 @@ BOOL LLScrollListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
1710 1718
1711 gFocusMgr.setMouseCapture(this); 1719 gFocusMgr.setMouseCapture(this);
1712 selectItemAt(x, y, mask); 1720 selectItemAt(x, y, mask);
1721 mNeedsScroll = TRUE;
1713 } 1722 }
1714 1723
1715 return TRUE; 1724 return TRUE;
@@ -1719,17 +1728,16 @@ BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
1719{ 1728{
1720 if (hasMouseCapture()) 1729 if (hasMouseCapture())
1721 { 1730 {
1731 // release mouse capture immediately so
1732 // scroll to show selected logic will work
1733 gFocusMgr.setMouseCapture(NULL);
1722 if(mask == MASK_NONE) 1734 if(mask == MASK_NONE)
1723 { 1735 {
1724 selectItemAt(x, y, mask); 1736 selectItemAt(x, y, mask);
1737 mNeedsScroll = TRUE;
1725 } 1738 }
1726 } 1739 }
1727 1740
1728 if (hasMouseCapture())
1729 {
1730 gFocusMgr.setMouseCapture(NULL);
1731 }
1732
1733 // always commit when mouse operation is completed inside list 1741 // always commit when mouse operation is completed inside list
1734 if (mItemListRect.pointInRect(x,y)) 1742 if (mItemListRect.pointInRect(x,y))
1735 { 1743 {
@@ -1770,7 +1778,8 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
1770 mItemListRect.getWidth(), 1778 mItemListRect.getWidth(),
1771 mLineHeight ); 1779 mLineHeight );
1772 1780
1773 int num_page_lines = mPageLines; 1781 // allow for partial line at bottom
1782 S32 num_page_lines = mPageLines + 1;
1774 1783
1775 S32 line = 0; 1784 S32 line = 0;
1776 item_list::iterator iter; 1785 item_list::iterator iter;
@@ -1803,6 +1812,7 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
1803 if(mask == MASK_NONE) 1812 if(mask == MASK_NONE)
1804 { 1813 {
1805 selectItemAt(x, y, mask); 1814 selectItemAt(x, y, mask);
1815 mNeedsScroll = TRUE;
1806 } 1816 }
1807 } 1817 }
1808 else if (mCanSelect) 1818 else if (mCanSelect)
@@ -1850,7 +1860,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1850 { 1860 {
1851 // commit implicit in call 1861 // commit implicit in call
1852 selectPrevItem(FALSE); 1862 selectPrevItem(FALSE);
1853 scrollToShowSelected(); 1863 mNeedsScroll = TRUE;
1854 handled = TRUE; 1864 handled = TRUE;
1855 } 1865 }
1856 break; 1866 break;
@@ -1859,7 +1869,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1859 { 1869 {
1860 // commit implicit in call 1870 // commit implicit in call
1861 selectNextItem(FALSE); 1871 selectNextItem(FALSE);
1862 scrollToShowSelected(); 1872 mNeedsScroll = TRUE;
1863 handled = TRUE; 1873 handled = TRUE;
1864 } 1874 }
1865 break; 1875 break;
@@ -1867,7 +1877,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1867 if (mAllowKeyboardMovement || hasFocus()) 1877 if (mAllowKeyboardMovement || hasFocus())
1868 { 1878 {
1869 selectNthItem(getFirstSelectedIndex() - (mScrollbar->getPageSize() - 1)); 1879 selectNthItem(getFirstSelectedIndex() - (mScrollbar->getPageSize() - 1));
1870 scrollToShowSelected(); 1880 mNeedsScroll = TRUE;
1871 if (mCommitOnKeyboardMovement 1881 if (mCommitOnKeyboardMovement
1872 && !mCommitOnSelectionChange) 1882 && !mCommitOnSelectionChange)
1873 { 1883 {
@@ -1880,7 +1890,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1880 if (mAllowKeyboardMovement || hasFocus()) 1890 if (mAllowKeyboardMovement || hasFocus())
1881 { 1891 {
1882 selectNthItem(getFirstSelectedIndex() + (mScrollbar->getPageSize() - 1)); 1892 selectNthItem(getFirstSelectedIndex() + (mScrollbar->getPageSize() - 1));
1883 scrollToShowSelected(); 1893 mNeedsScroll = TRUE;
1884 if (mCommitOnKeyboardMovement 1894 if (mCommitOnKeyboardMovement
1885 && !mCommitOnSelectionChange) 1895 && !mCommitOnSelectionChange)
1886 { 1896 {
@@ -1893,7 +1903,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1893 if (mAllowKeyboardMovement || hasFocus()) 1903 if (mAllowKeyboardMovement || hasFocus())
1894 { 1904 {
1895 selectFirstItem(); 1905 selectFirstItem();
1896 scrollToShowSelected(); 1906 mNeedsScroll = TRUE;
1897 if (mCommitOnKeyboardMovement 1907 if (mCommitOnKeyboardMovement
1898 && !mCommitOnSelectionChange) 1908 && !mCommitOnSelectionChange)
1899 { 1909 {
@@ -1906,7 +1916,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1906 if (mAllowKeyboardMovement || hasFocus()) 1916 if (mAllowKeyboardMovement || hasFocus())
1907 { 1917 {
1908 selectNthItem(getItemCount() - 1); 1918 selectNthItem(getItemCount() - 1);
1909 scrollToShowSelected(); 1919 mNeedsScroll = TRUE;
1910 if (mCommitOnKeyboardMovement 1920 if (mCommitOnKeyboardMovement
1911 && !mCommitOnSelectionChange) 1921 && !mCommitOnSelectionChange)
1912 { 1922 {
@@ -1945,6 +1955,7 @@ BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask, BOOL called_from_parent
1945 } 1955 }
1946 else if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString), FALSE)) 1956 else if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString), FALSE))
1947 { 1957 {
1958 mNeedsScroll = TRUE;
1948 // update search string only on successful match 1959 // update search string only on successful match
1949 mSearchTimer.reset(); 1960 mSearchTimer.reset();
1950 1961
@@ -1984,6 +1995,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_
1984 if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString + (llwchar)uni_char), FALSE)) 1995 if (selectSimpleItemByPrefix(wstring_to_utf8str(mSearchString + (llwchar)uni_char), FALSE))
1985 { 1996 {
1986 // update search string only on successful match 1997 // update search string only on successful match
1998 mNeedsScroll = TRUE;
1987 mSearchString += uni_char; 1999 mSearchString += uni_char;
1988 mSearchTimer.reset(); 2000 mSearchTimer.reset();
1989 2001
@@ -2029,6 +2041,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_
2029 if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) 2041 if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char)
2030 { 2042 {
2031 selectItem(item); 2043 selectItem(item);
2044 mNeedsScroll = TRUE;
2032 cellp->highlightText(0, 1); 2045 cellp->highlightText(0, 1);
2033 mSearchTimer.reset(); 2046 mSearchTimer.reset();
2034 2047
@@ -2050,8 +2063,6 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_
2050 } 2063 }
2051 } 2064 }
2052 2065
2053 // make sure selected item is on screen
2054 scrollToShowSelected();
2055 return TRUE; 2066 return TRUE;
2056} 2067}
2057 2068
@@ -2203,6 +2214,13 @@ void LLScrollListCtrl::setScrollPos( S32 pos )
2203 2214
2204void LLScrollListCtrl::scrollToShowSelected() 2215void LLScrollListCtrl::scrollToShowSelected()
2205{ 2216{
2217 // don't scroll automatically when capturing mouse input
2218 // as that will change what is currently under the mouse cursor
2219 if (hasMouseCapture())
2220 {
2221 return;
2222 }
2223
2206 S32 index = getFirstSelectedIndex(); 2224 S32 index = getFirstSelectedIndex();
2207 if (index < 0) 2225 if (index < 0)
2208 { 2226 {
@@ -3033,8 +3051,9 @@ LLColumnHeader::LLColumnHeader(const LLString& label, const LLRect &rect, LLScro
3033 const S32 RESIZE_BAR_THICKNESS = 3; 3051 const S32 RESIZE_BAR_THICKNESS = 3;
3034 mResizeBar = new LLResizeBar( 3052 mResizeBar = new LLResizeBar(
3035 "resizebar", 3053 "resizebar",
3054 this,
3036 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), 3055 LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0),
3037 MIN_COLUMN_WIDTH, mRect.getHeight(), LLResizeBar::RIGHT ); 3056 MIN_COLUMN_WIDTH, S32_MAX, LLResizeBar::RIGHT );
3038 addChild(mResizeBar); 3057 addChild(mResizeBar);
3039 3058
3040 mResizeBar->setEnabled(FALSE); 3059 mResizeBar->setEnabled(FALSE);
diff --git a/linden/indra/llui/llscrolllistctrl.h b/linden/indra/llui/llscrolllistctrl.h
index f1bd9bb..809c528 100644
--- a/linden/indra/llui/llscrolllistctrl.h
+++ b/linden/indra/llui/llscrolllistctrl.h
@@ -605,6 +605,7 @@ protected:
605 BOOL mCommitOnKeyboardMovement; 605 BOOL mCommitOnKeyboardMovement;
606 BOOL mCommitOnSelectionChange; 606 BOOL mCommitOnSelectionChange;
607 BOOL mSelectionChanged; 607 BOOL mSelectionChanged;
608 BOOL mNeedsScroll;
608 BOOL mCanSelect; 609 BOOL mCanSelect;
609 BOOL mDisplayColumnHeaders; 610 BOOL mDisplayColumnHeaders;
610 BOOL mCollapseEmptyColumns; 611 BOOL mCollapseEmptyColumns;
diff --git a/linden/indra/llui/llslider.cpp b/linden/indra/llui/llslider.cpp
index 8c0d2a1..e3a3153 100644
--- a/linden/indra/llui/llslider.cpp
+++ b/linden/indra/llui/llslider.cpp
@@ -50,6 +50,7 @@ LLSlider::LLSlider(
50 F32 min_value, 50 F32 min_value,
51 F32 max_value, 51 F32 max_value,
52 F32 increment, 52 F32 increment,
53 BOOL volume,
53 const LLString& control_name) 54 const LLString& control_name)
54 : 55 :
55 LLUICtrl( name, rect, TRUE, on_commit_callback, callback_userdata, 56 LLUICtrl( name, rect, TRUE, on_commit_callback, callback_userdata,
@@ -59,6 +60,7 @@ LLSlider::LLSlider(
59 mMinValue( min_value ), 60 mMinValue( min_value ),
60 mMaxValue( max_value ), 61 mMaxValue( max_value ),
61 mIncrement( increment ), 62 mIncrement( increment ),
63 mVolumeSlider( volume ),
62 mMouseOffset( 0 ), 64 mMouseOffset( 0 ),
63 mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ), 65 mDragStartThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
64 mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ), 66 mThumbRect( 0, mRect.getHeight(), THUMB_WIDTH, 0 ),
@@ -69,7 +71,7 @@ LLSlider::LLSlider(
69 mMouseDownCallback( NULL ), 71 mMouseDownCallback( NULL ),
70 mMouseUpCallback( NULL ) 72 mMouseUpCallback( NULL )
71{ 73{
72 // prperly handle setting the starting thumb rect 74 // properly handle setting the starting thumb rect
73 // do it this way to handle both the operating-on-settings 75 // do it this way to handle both the operating-on-settings
74 // and standalone ways of using this 76 // and standalone ways of using this
75 setControlName(control_name, NULL); 77 setControlName(control_name, NULL);
@@ -94,13 +96,15 @@ void LLSlider::setValue(F32 value, BOOL from_event)
94 value -= mMinValue; 96 value -= mMinValue;
95 value += mIncrement/2.0001f; 97 value += mIncrement/2.0001f;
96 value -= fmod(value, mIncrement); 98 value -= fmod(value, mIncrement);
97 mValue = mMinValue + value; 99 value += mMinValue;
98 100
99 if (!from_event) 101 if (!from_event && mValue != value)
100 { 102 {
101 setControlValue(mValue); 103 setControlValue(value);
102 } 104 }
103 105
106 mValue = value;
107
104 F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue); 108 F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
105 109
106 S32 left_edge = THUMB_WIDTH/2; 110 S32 left_edge = THUMB_WIDTH/2;
@@ -111,6 +115,18 @@ void LLSlider::setValue(F32 value, BOOL from_event)
111 mThumbRect.mRight = x + (THUMB_WIDTH/2); 115 mThumbRect.mRight = x + (THUMB_WIDTH/2);
112} 116}
113 117
118void LLSlider::setValueAndCommit(F32 value)
119{
120 F32 old_value = mValue;
121 setValue(value);
122
123 if (mValue != old_value)
124 {
125 onCommit();
126 }
127}
128
129
114F32 LLSlider::getValueF32() const 130F32 LLSlider::getValueF32() const
115{ 131{
116 return mValue; 132 return mValue;
@@ -127,8 +143,7 @@ BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask)
127 x = llclamp( x, left_edge, right_edge ); 143 x = llclamp( x, left_edge, right_edge );
128 144
129 F32 t = F32(x - left_edge) / (right_edge - left_edge); 145 F32 t = F32(x - left_edge) / (right_edge - left_edge);
130 setValue(t * (mMaxValue - mMinValue) + mMinValue ); 146 setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue );
131 onCommit();
132 147
133 getWindow()->setCursor(UI_CURSOR_ARROW); 148 getWindow()->setCursor(UI_CURSOR_ARROW);
134 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; 149 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
@@ -178,8 +193,7 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
178 193
179 if (MASK_CONTROL & mask) // if CTRL is modifying 194 if (MASK_CONTROL & mask) // if CTRL is modifying
180 { 195 {
181 setValue(mInitialValue); 196 setValueAndCommit(mInitialValue);
182 onCommit();
183 } 197 }
184 else 198 else
185 { 199 {
@@ -216,13 +230,11 @@ BOOL LLSlider::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
216 handled = TRUE; 230 handled = TRUE;
217 break; 231 break;
218 case KEY_LEFT: 232 case KEY_LEFT:
219 setValue(getValueF32() - getIncrement()); 233 setValueAndCommit(getValueF32() - getIncrement());
220 onCommit();
221 handled = TRUE; 234 handled = TRUE;
222 break; 235 break;
223 case KEY_RIGHT: 236 case KEY_RIGHT:
224 setValue(getValueF32() + getIncrement()); 237 setValueAndCommit(getValueF32() + getIncrement());
225 onCommit();
226 handled = TRUE; 238 handled = TRUE;
227 break; 239 break;
228 default: 240 default:
@@ -244,33 +256,93 @@ void LLSlider::draw()
244 LLRect rect(mDragStartThumbRect); 256 LLRect rect(mDragStartThumbRect);
245 257
246 F32 opacity = mEnabled ? 1.f : 0.3f; 258 F32 opacity = mEnabled ? 1.f : 0.3f;
259 LLColor4 center_color = (mThumbCenterColor % opacity);
260 LLColor4 outline_color = (mThumbOutlineColor % opacity);
261 LLColor4 track_color = (mTrackColor % opacity);
247 262
263 LLImageGL* thumb_imagep = NULL;
264
248 // Track 265 // Track
266 if (mVolumeSlider)
267 {
268 LLRect track(0, mRect.getHeight(), mRect.getWidth(), 0);
269
270 track.mBottom += 3;
271 track.mTop -= 1;
272 track.mRight -= 1;
273
274 gl_triangle_2d(track.mLeft, track.mBottom,
275 track.mRight, track.mBottom,
276 track.mRight, track.mTop,
277 center_color,
278 TRUE);
279 gl_triangle_2d(track.mLeft, track.mBottom,
280 track.mRight, track.mBottom,
281 track.mRight, track.mTop,
282 outline_color,
283 FALSE);
284 }
285 else
286 {
287 LLUUID thumb_image_id;
288 thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga"));
289 thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id);
249 290
250 LLUUID thumb_image_id; 291 S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2;
251 thumb_image_id.set(LLUI::sAssetsGroup->getString("rounded_square.tga")); 292 LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset );
252 LLImageGL* thumb_imagep = LLUI::sImageProvider->getUIImageByID(thumb_image_id);
253
254 S32 height_offset = (mRect.getHeight() - TRACK_HEIGHT) / 2;
255 LLRect track_rect(0, mRect.getHeight() - height_offset, mRect.getWidth(), height_offset );
256 293
257 track_rect.stretch(-1); 294 track_rect.stretch(-1);
258 gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(), 295 gl_draw_scaled_image_with_border(track_rect.mLeft, track_rect.mBottom, 16, 16, track_rect.getWidth(), track_rect.getHeight(),
259 thumb_imagep, mTrackColor % opacity); 296 thumb_imagep, track_color);
260 //gl_rect_2d( track_rect, mThumbOutlineColor % opacity ); 297 }
261 298
299 // Thumb
262 if (!thumb_imagep) 300 if (!thumb_imagep)
263 { 301 {
264 gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE); 302 if (mVolumeSlider)
265 if (hasMouseCapture()) 303 {
304 if (hasMouseCapture())
305 {
306 LLRect rect(mDragStartThumbRect);
307 gl_rect_2d( rect, outline_color );
308 rect.stretch(-1);
309 gl_rect_2d( rect, mThumbCenterColor % 0.3f );
310
311 if (hasFocus())
312 {
313 LLRect thumb_rect = mThumbRect;
314 thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())));
315 gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor());
316 }
317 gl_rect_2d( mThumbRect, mThumbOutlineColor );
318 }
319 else
320 {
321 if (hasFocus())
322 {
323 LLRect thumb_rect = mThumbRect;
324 thumb_rect.stretch(llround(lerp(1.f, 3.f, gFocusMgr.getFocusFlashAmt())));
325 gl_rect_2d(thumb_rect, gFocusMgr.getFocusColor());
326 }
327 LLRect rect(mThumbRect);
328 gl_rect_2d(rect, outline_color);
329 rect.stretch(-1);
330 gl_rect_2d( rect, center_color);
331 }
332 }
333 else
266 { 334 {
267 gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE); 335 gl_rect_2d(mThumbRect, mThumbCenterColor, TRUE);
336 if (hasMouseCapture())
337 {
338 gl_rect_2d(mDragStartThumbRect, center_color, FALSE);
339 }
268 } 340 }
269 } 341 }
270 else if( hasMouseCapture() ) 342 else if( hasMouseCapture() )
271 { 343 {
272 gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(), 344 gl_draw_scaled_image_with_border(mDragStartThumbRect.mLeft, mDragStartThumbRect.mBottom, 16, 16, mDragStartThumbRect.getWidth(), mDragStartThumbRect.getHeight(),
273 thumb_imagep, mThumbCenterColor % 0.3f, TRUE); 345 thumb_imagep, mThumbCenterColor % 0.3f, TRUE);
274 346
275 if (hasFocus()) 347 if (hasFocus())
276 { 348 {
@@ -278,20 +350,12 @@ void LLSlider::draw()
278 LLRect highlight_rect = mThumbRect; 350 LLRect highlight_rect = mThumbRect;
279 highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt))); 351 highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
280 gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(), 352 gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
281 thumb_imagep, gFocusMgr.getFocusColor()); 353 thumb_imagep, gFocusMgr.getFocusColor());
282 } 354 }
283 355
284
285 gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), 356 gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
286 thumb_imagep, mThumbOutlineColor, TRUE); 357 thumb_imagep, mThumbOutlineColor, TRUE);
287
288 //// Start Thumb
289 //gl_rect_2d( mDragStartThumbRect, mThumbOutlineColor % 0.3f );
290 //rect.stretch(-1);
291 //gl_rect_2d( rect, mThumbCenterColor % 0.3f );
292 358
293 //// Thumb
294 //gl_rect_2d( mThumbRect, mThumbOutlineColor );
295 } 359 }
296 else 360 else
297 { 361 {
@@ -301,22 +365,12 @@ void LLSlider::draw()
301 LLRect highlight_rect = mThumbRect; 365 LLRect highlight_rect = mThumbRect;
302 highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt))); 366 highlight_rect.stretch(llround(lerp(1.f, 3.f, lerp_amt)));
303 gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(), 367 gl_draw_scaled_image_with_border(highlight_rect.mLeft, highlight_rect.mBottom, 16, 16, highlight_rect.getWidth(), highlight_rect.getHeight(),
304 thumb_imagep, gFocusMgr.getFocusColor()); 368 thumb_imagep, gFocusMgr.getFocusColor());
305 } 369 }
306 370
307 gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(), 371 gl_draw_scaled_image_with_border(mThumbRect.mLeft, mThumbRect.mBottom, 16, 16, mThumbRect.getWidth(), mThumbRect.getHeight(),
308 thumb_imagep, mThumbCenterColor % opacity, TRUE); 372 thumb_imagep, center_color, TRUE);
309 //rect = mThumbRect;
310
311 //gl_rect_2d( mThumbRect, mThumbOutlineColor % opacity );
312 //
313 //rect.stretch(-1);
314
315 //// Thumb
316 //gl_rect_2d( rect, mThumbCenterColor % opacity );
317
318 } 373 }
319
320 LLUICtrl::draw(); 374 LLUICtrl::draw();
321 } 375 }
322} 376}
@@ -330,6 +384,7 @@ LLXMLNodePtr LLSlider::getXML(bool save_children) const
330 node->createChild("min_val", TRUE)->setFloatValue(getMinValue()); 384 node->createChild("min_val", TRUE)->setFloatValue(getMinValue());
331 node->createChild("max_val", TRUE)->setFloatValue(getMaxValue()); 385 node->createChild("max_val", TRUE)->setFloatValue(getMaxValue());
332 node->createChild("increment", TRUE)->setFloatValue(getIncrement()); 386 node->createChild("increment", TRUE)->setFloatValue(getIncrement());
387 node->createChild("volume", TRUE)->setBoolValue(getVolumeSlider());
333 388
334 return node; 389 return node;
335} 390}
@@ -356,6 +411,8 @@ LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
356 F32 increment = 0.1f; 411 F32 increment = 0.1f;
357 node->getAttributeF32("increment", increment); 412 node->getAttributeF32("increment", increment);
358 413
414 BOOL volume = node->hasName("volume_slider") ? TRUE : FALSE;
415 node->getAttributeBOOL("volume", volume);
359 416
360 LLSlider* slider = new LLSlider(name, 417 LLSlider* slider = new LLSlider(name,
361 rect, 418 rect,
@@ -364,7 +421,8 @@ LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
364 initial_value, 421 initial_value,
365 min_value, 422 min_value,
366 max_value, 423 max_value,
367 increment); 424 increment,
425 volume);
368 426
369 slider->initFromXML(node, parent); 427 slider->initFromXML(node, parent);
370 428
diff --git a/linden/indra/llui/llslider.h b/linden/indra/llui/llslider.h
index 4f42a56..8fcd672 100644
--- a/linden/indra/llui/llslider.h
+++ b/linden/indra/llui/llslider.h
@@ -46,6 +46,7 @@ public:
46 F32 min_value, 46 F32 min_value,
47 F32 max_value, 47 F32 max_value,
48 F32 increment, 48 F32 increment,
49 BOOL volume,
49 const LLString& control_name = LLString::null ); 50 const LLString& control_name = LLString::null );
50 51
51 virtual EWidgetType getWidgetType() const; 52 virtual EWidgetType getWidgetType() const;
@@ -66,6 +67,7 @@ public:
66 F32 getMinValue() const { return mMinValue; } 67 F32 getMinValue() const { return mMinValue; }
67 F32 getMaxValue() const { return mMaxValue; } 68 F32 getMaxValue() const { return mMaxValue; }
68 F32 getIncrement() const { return mIncrement; } 69 F32 getIncrement() const { return mIncrement; }
70 BOOL getVolumeSlider() const { return mVolumeSlider; }
69 void setMinValue(F32 min_value) {mMinValue = min_value;} 71 void setMinValue(F32 min_value) {mMinValue = min_value;}
70 void setMaxValue(F32 max_value) {mMaxValue = max_value;} 72 void setMaxValue(F32 max_value) {mMaxValue = max_value;}
71 void setIncrement(F32 increment) {mIncrement = increment;} 73 void setIncrement(F32 increment) {mIncrement = increment;}
@@ -79,12 +81,16 @@ public:
79 virtual void draw(); 81 virtual void draw();
80 82
81protected: 83protected:
84 void setValueAndCommit(F32 value);
85
86protected:
82 F32 mValue; 87 F32 mValue;
83 F32 mInitialValue; 88 F32 mInitialValue;
84 F32 mMinValue; 89 F32 mMinValue;
85 F32 mMaxValue; 90 F32 mMaxValue;
86 F32 mIncrement; 91 F32 mIncrement;
87 92
93 BOOL mVolumeSlider;
88 S32 mMouseOffset; 94 S32 mMouseOffset;
89 LLRect mDragStartThumbRect; 95 LLRect mDragStartThumbRect;
90 96
diff --git a/linden/indra/llui/llsliderctrl.cpp b/linden/indra/llui/llsliderctrl.cpp
index 9a67bca..dff27cc 100644
--- a/linden/indra/llui/llsliderctrl.cpp
+++ b/linden/indra/llui/llsliderctrl.cpp
@@ -57,6 +57,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect,
57 S32 text_left, 57 S32 text_left,
58 BOOL show_text, 58 BOOL show_text,
59 BOOL can_edit_text, 59 BOOL can_edit_text,
60 BOOL volume,
60 void (*commit_callback)(LLUICtrl*, void*), 61 void (*commit_callback)(LLUICtrl*, void*),
61 void* callback_user_data, 62 void* callback_user_data,
62 F32 initial_value, F32 min_value, F32 max_value, F32 increment, 63 F32 initial_value, F32 min_value, F32 max_value, F32 increment,
@@ -65,6 +66,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect,
65 mFont(font), 66 mFont(font),
66 mShowText( show_text ), 67 mShowText( show_text ),
67 mCanEditText( can_edit_text ), 68 mCanEditText( can_edit_text ),
69 mVolumeSlider( volume ),
68 mPrecision( 3 ), 70 mPrecision( 3 ),
69 mLabelBox( NULL ), 71 mLabelBox( NULL ),
70 mLabelWidth( label_width ), 72 mLabelWidth( label_width ),
@@ -104,7 +106,7 @@ LLSliderCtrl::LLSliderCtrl(const LLString& name, const LLRect& rect,
104 "slider", 106 "slider",
105 slider_rect, 107 slider_rect,
106 LLSliderCtrl::onSliderCommit, this, 108 LLSliderCtrl::onSliderCommit, this,
107 initial_value, min_value, max_value, increment, 109 initial_value, min_value, max_value, increment, volume,
108 control_which ); 110 control_which );
109 addChild( mSlider ); 111 addChild( mSlider );
110 112
@@ -443,6 +445,8 @@ LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const
443 445
444 node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText); 446 node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText);
445 447
448 node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider);
449
446 node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision); 450 node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
447 451
448 if (mLabelBox) 452 if (mLabelBox)
@@ -494,6 +498,9 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
494 BOOL can_edit_text = FALSE; 498 BOOL can_edit_text = FALSE;
495 node->getAttributeBOOL("can_edit_text", can_edit_text); 499 node->getAttributeBOOL("can_edit_text", can_edit_text);
496 500
501 BOOL volume = FALSE;
502 node->getAttributeBOOL("volume", volume);
503
497 F32 initial_value = 0.f; 504 F32 initial_value = 0.f;
498 node->getAttributeF32("initial_val", initial_value); 505 node->getAttributeF32("initial_val", initial_value);
499 506
@@ -541,6 +548,7 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
541 rect.getWidth() - text_left, 548 rect.getWidth() - text_left,
542 show_text, 549 show_text,
543 can_edit_text, 550 can_edit_text,
551 volume,
544 callback, 552 callback,
545 NULL, 553 NULL,
546 initial_value, 554 initial_value,
diff --git a/linden/indra/llui/llsliderctrl.h b/linden/indra/llui/llsliderctrl.h
index 26c9dee..6896360 100644
--- a/linden/indra/llui/llsliderctrl.h
+++ b/linden/indra/llui/llsliderctrl.h
@@ -60,6 +60,7 @@ public:
60 S32 text_left, 60 S32 text_left,
61 BOOL show_text, 61 BOOL show_text,
62 BOOL can_edit_text, 62 BOOL can_edit_text,
63 BOOL volume,
63 void (*commit_callback)(LLUICtrl*, void*), 64 void (*commit_callback)(LLUICtrl*, void*),
64 void* callback_userdata, 65 void* callback_userdata,
65 F32 initial_value, F32 min_value, F32 max_value, F32 increment, 66 F32 initial_value, F32 min_value, F32 max_value, F32 increment,
@@ -124,7 +125,8 @@ private:
124 const LLFontGL* mFont; 125 const LLFontGL* mFont;
125 BOOL mShowText; 126 BOOL mShowText;
126 BOOL mCanEditText; 127 BOOL mCanEditText;
127 128 BOOL mVolumeSlider;
129
128 S32 mPrecision; 130 S32 mPrecision;
129 LLTextBox* mLabelBox; 131 LLTextBox* mLabelBox;
130 S32 mLabelWidth; 132 S32 mLabelWidth;
diff --git a/linden/indra/llui/lltabcontainer.cpp b/linden/indra/llui/lltabcontainer.cpp
index 01c06c3..135931d 100644
--- a/linden/indra/llui/lltabcontainer.cpp
+++ b/linden/indra/llui/lltabcontainer.cpp
@@ -70,6 +70,7 @@ LLTabContainerCommon::LLTabContainerCommon(
70 : 70 :
71 LLPanel(name, rect, bordered), 71 LLPanel(name, rect, bordered),
72 mCurrentTabIdx(-1), 72 mCurrentTabIdx(-1),
73 mTabsHidden(FALSE),
73 mScrolled(FALSE), 74 mScrolled(FALSE),
74 mScrollPos(0), 75 mScrollPos(0),
75 mScrollPosPixels(0), 76 mScrollPosPixels(0),
@@ -95,6 +96,7 @@ LLTabContainerCommon::LLTabContainerCommon(
95 : 96 :
96 LLPanel(name, rect_control, bordered), 97 LLPanel(name, rect_control, bordered),
97 mCurrentTabIdx(-1), 98 mCurrentTabIdx(-1),
99 mTabsHidden(FALSE),
98 mScrolled(FALSE), 100 mScrolled(FALSE),
99 mScrollPos(0), 101 mScrollPos(0),
100 mScrollPosPixels(0), 102 mScrollPosPixels(0),
@@ -147,11 +149,11 @@ void LLTabContainerCommon::addPlaceholder(LLPanel* child, const LLString& label)
147 addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); 149 addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE);
148} 150}
149 151
150void LLTabContainerCommon::lockTabs() 152void LLTabContainerCommon::lockTabs(S32 num_tabs)
151{ 153{
152 // count current tabs and ensure no new tabs get 154 // count current tabs or use supplied value and ensure no new tabs get
153 // inserted between them 155 // inserted between them
154 mLockedTabCount = getTabCount(); 156 mLockedTabCount = num_tabs > 0 ? num_tabs : getTabCount();
155} 157}
156 158
157void LLTabContainerCommon::removeTabPanel(LLPanel* child) 159void LLTabContainerCommon::removeTabPanel(LLPanel* child)
@@ -542,12 +544,12 @@ void LLTabContainerCommon::setTabPanelFlashing(LLPanel* child, BOOL state )
542 } 544 }
543} 545}
544 546
545void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name) 547void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name, const LLColor4& color)
546{ 548{
547 LLTabTuple* tuple = getTabByPanel(child); 549 LLTabTuple* tuple = getTabByPanel(child);
548 if( tuple ) 550 if( tuple )
549 { 551 {
550 tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT); 552 tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT, color);
551 } 553 }
552} 554}
553 555
@@ -667,6 +669,8 @@ LLView* LLTabContainerCommon::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtr
667 } 669 }
668 } 670 }
669 671
672 node->getAttributeBOOL("hide_tabs", tab_container->mTabsHidden);
673
670 tab_container->setPanelParameters(node, parent); 674 tab_container->setPanelParameters(node, parent);
671 675
672 if (LLFloater::getFloaterHost()) 676 if (LLFloater::getFloaterHost())
@@ -1036,10 +1040,11 @@ void LLTabContainer::setPanelTitle(S32 index, const LLString& title)
1036{ 1040{
1037 if (index >= 0 && index < (S32)mTabList.size()) 1041 if (index >= 0 && index < (S32)mTabList.size())
1038 { 1042 {
1039 LLButton* tab_button = mTabList[index]->mButton; 1043 LLTabTuple* tuple = mTabList[index];
1044 LLButton* tab_button = tuple->mButton;
1040 const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); 1045 const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL );
1041 mTotalTabWidth -= tab_button->getRect().getWidth(); 1046 mTotalTabWidth -= tab_button->getRect().getWidth();
1042 tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); 1047 tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
1043 mTotalTabWidth += tab_button->getRect().getWidth(); 1048 mTotalTabWidth += tab_button->getRect().getWidth();
1044 tab_button->setLabelSelected(title); 1049 tab_button->setLabelSelected(title);
1045 tab_button->setLabelUnselected(title); 1050 tab_button->setLabelUnselected(title);
@@ -1245,63 +1250,60 @@ void LLTabContainer::draw()
1245 1250
1246 LLPanel::draw(); 1251 LLPanel::draw();
1247 1252
1248 // Show all the buttons 1253 // if tabs are hidden, don't draw them and leave them in the invisible state
1249 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) 1254 if (!mTabsHidden)
1250 { 1255 {
1251 LLTabTuple* tuple = *iter; 1256 // Show all the buttons
1252 tuple->mButton->setVisible( TRUE ); 1257 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
1253 } 1258 {
1254 1259 LLTabTuple* tuple = *iter;
1255 // Draw some of the buttons... 1260 tuple->mButton->setVisible( TRUE );
1261 }
1256 1262
1257 LLGLEnable scissor_test(has_scroll_arrows ? GL_SCISSOR_TEST : GL_FALSE); 1263 // Draw some of the buttons...
1258 if( has_scroll_arrows ) 1264 LLRect clip_rect = getLocalRect();
1259 { 1265 if (has_scroll_arrows)
1260 // ...but clip them.
1261 S32 x1 = mLeftArrowBtn->getRect().mRight;
1262 S32 y1 = 0;
1263 S32 x2 = mRightArrowBtn->getRect().mLeft;
1264 S32 y2 = 1;
1265 if (mTabList.size() > 0)
1266 { 1266 {
1267 y2 = mTabList[0]->mButton->getRect().mTop; 1267 // ...but clip them.
1268 clip_rect.mLeft = mLeftArrowBtn->getRect().mRight;
1269 clip_rect.mRight = mRightArrowBtn->getRect().mLeft;
1268 } 1270 }
1269 LLUI::setScissorRegionLocal(LLRect(x1, y2, x2, y1)); 1271 LLLocalClipRect clip(clip_rect);
1270 }
1271 1272
1272 S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos; 1273 S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos;
1273 S32 idx = 0; 1274 S32 idx = 0;
1274 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) 1275 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
1275 { 1276 {
1276 LLTabTuple* tuple = *iter; 1277 LLTabTuple* tuple = *iter;
1277 1278
1278 tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 ); 1279 tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 );
1279 left += tuple->mButton->getRect().getWidth(); 1280 left += tuple->mButton->getRect().getWidth();
1280 1281
1281 if( idx < mScrollPos ) 1282 if( idx < mScrollPos )
1282 {
1283 if( tuple->mButton->getFlashing() )
1284 { 1283 {
1285 mLeftArrowBtn->setFlashing( TRUE ); 1284 if( tuple->mButton->getFlashing() )
1285 {
1286 mLeftArrowBtn->setFlashing( TRUE );
1287 }
1286 } 1288 }
1287 } 1289 else
1288 else 1290 if( max_scroll_visible < idx )
1289 if( max_scroll_visible < idx )
1290 {
1291 if( tuple->mButton->getFlashing() )
1292 { 1291 {
1293 mRightArrowBtn->setFlashing( TRUE ); 1292 if( tuple->mButton->getFlashing() )
1293 {
1294 mRightArrowBtn->setFlashing( TRUE );
1295 }
1294 } 1296 }
1295 }
1296 1297
1297 LLUI::pushMatrix(); 1298 LLUI::pushMatrix();
1298 { 1299 {
1299 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); 1300 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
1300 tuple->mButton->draw(); 1301 tuple->mButton->draw();
1302 }
1303 LLUI::popMatrix();
1304
1305 idx++;
1301 } 1306 }
1302 LLUI::popMatrix();
1303
1304 idx++;
1305 } 1307 }
1306 1308
1307 mLeftArrowBtn->setFlashing(FALSE); 1309 mLeftArrowBtn->setFlashing(FALSE);
@@ -1628,12 +1630,12 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag
1628 return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); 1630 return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip);
1629} 1631}
1630 1632
1631void LLTabContainer::setTabImage(LLPanel* child, std::string image_name) 1633void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color)
1632{ 1634{
1633 LLTabTuple* tuple = getTabByPanel(child); 1635 LLTabTuple* tuple = getTabByPanel(child);
1634 if( tuple ) 1636 if( tuple )
1635 { 1637 {
1636 tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT); 1638 tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT, color);
1637 1639
1638 const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL ); 1640 const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL );
1639 // remove current width from total tab strip width 1641 // remove current width from total tab strip width
@@ -1642,7 +1644,11 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name)
1642 S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? 1644 S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
1643 tuple->mButton->getImageOverlay()->getWidth(0) : 1645 tuple->mButton->getImageOverlay()->getWidth(0) :
1644 0; 1646 0;
1645 tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + image_overlay_width, mMinTabWidth, mMaxTabWidth), 1647
1648 tuple->mPadding = image_overlay_width;
1649
1650 tuple->mButton->setRightHPad(tuple->mPadding + LLBUTTON_H_PAD);
1651 tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth),
1646 tuple->mButton->getRect().getHeight()); 1652 tuple->mButton->getRect().getHeight());
1647 // add back in button width to total tab strip width 1653 // add back in button width to total tab strip width
1648 mTotalTabWidth += tuple->mButton->getRect().getWidth(); 1654 mTotalTabWidth += tuple->mButton->getRect().getWidth();
diff --git a/linden/indra/llui/lltabcontainer.h b/linden/indra/llui/lltabcontainer.h
index f3365c3..3056c0a 100644
--- a/linden/indra/llui/lltabcontainer.h
+++ b/linden/indra/llui/lltabcontainer.h
@@ -87,7 +87,7 @@ public:
87 BOOL placeholder = FALSE, 87 BOOL placeholder = FALSE,
88 eInsertionPoint insertion_point = END) = 0; 88 eInsertionPoint insertion_point = END) = 0;
89 virtual void addPlaceholder(LLPanel* child, const LLString& label); 89 virtual void addPlaceholder(LLPanel* child, const LLString& label);
90 virtual void lockTabs(); 90 virtual void lockTabs(S32 num_tabs = 0);
91 91
92 virtual void enableTabButton(S32 which, BOOL enable); 92 virtual void enableTabButton(S32 which, BOOL enable);
93 93
@@ -114,7 +114,7 @@ public:
114 114
115 BOOL getTabPanelFlashing(LLPanel* child); 115 BOOL getTabPanelFlashing(LLPanel* child);
116 void setTabPanelFlashing(LLPanel* child, BOOL state); 116 void setTabPanelFlashing(LLPanel* child, BOOL state);
117 virtual void setTabImage(LLPanel* child, std::string img_name); 117 virtual void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white);
118 void setTitle( const LLString& title ); 118 void setTitle( const LLString& title );
119 const LLString getPanelTitle(S32 index); 119 const LLString getPanelTitle(S32 index);
120 120
@@ -155,7 +155,8 @@ protected:
155 mOnChangeCallback( cb ), 155 mOnChangeCallback( cb ),
156 mUserData( userdata ), 156 mUserData( userdata ),
157 mOldState(FALSE), 157 mOldState(FALSE),
158 mPlaceholderText(placeholder) 158 mPlaceholderText(placeholder),
159 mPadding(0)
159 {} 160 {}
160 161
161 LLTabContainerCommon* mTabContainer; 162 LLTabContainerCommon* mTabContainer;
@@ -165,11 +166,13 @@ protected:
165 void* mUserData; 166 void* mUserData;
166 BOOL mOldState; 167 BOOL mOldState;
167 LLTextBox* mPlaceholderText; 168 LLTextBox* mPlaceholderText;
169 S32 mPadding;
168 }; 170 };
169 171
170 typedef std::vector<LLTabTuple*> tuple_list_t; 172 typedef std::vector<LLTabTuple*> tuple_list_t;
171 tuple_list_t mTabList; 173 tuple_list_t mTabList;
172 S32 mCurrentTabIdx; 174 S32 mCurrentTabIdx;
175 BOOL mTabsHidden;
173 176
174 BOOL mScrolled; 177 BOOL mScrolled;
175 LLFrameTimer mScrollTimer; 178 LLFrameTimer mScrollTimer;
@@ -228,7 +231,7 @@ public:
228 /*virtual*/ void removeTabPanel( LLPanel* child ); 231 /*virtual*/ void removeTabPanel( LLPanel* child );
229 232
230 /*virtual*/ void setPanelTitle(S32 index, const LLString& title); 233 /*virtual*/ void setPanelTitle(S32 index, const LLString& title);
231 /*virtual*/ void setTabImage(LLPanel* child, std::string img_name); 234 /*virtual*/ void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white);
232 /*virtual*/ void setRightTabBtnOffset( S32 offset ); 235 /*virtual*/ void setRightTabBtnOffset( S32 offset );
233 236
234 /*virtual*/ void setMinTabWidth(S32 width); 237 /*virtual*/ void setMinTabWidth(S32 width);
diff --git a/linden/indra/llui/lltabcontainervertical.cpp b/linden/indra/llui/lltabcontainervertical.cpp
index 317b7ca..e2d84a5 100644
--- a/linden/indra/llui/lltabcontainervertical.cpp
+++ b/linden/indra/llui/lltabcontainervertical.cpp
@@ -392,49 +392,47 @@ void LLTabContainerVertical::draw()
392 } 392 }
393 393
394 // Draw some of the buttons... 394 // Draw some of the buttons...
395
396 LLGLEnable scissor_test(has_scroll_arrows ? GL_SCISSOR_TEST : GL_FALSE);
397
398 if( has_scroll_arrows )
399 {
400 // ...but clip them.
401 S32 x1 = mRect.mLeft;
402 S32 y1 = mDownArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
403 S32 x2 = mRect.mRight;
404 S32 y2 = mUpArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
405 LLUI::setScissorRegionLocal(LLRect(x1, y2, x2, y1));
406 }
407
408 //S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos;
409 S32 idx = 0;
410 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
411 { 395 {
412 LLTabTuple* tuple = *iter; 396 LLRect clip_rect = getLocalRect();
413 tuple->mButton->translate( 0 , top - tuple->mButton->getRect().mTop); 397 if (has_scroll_arrows)
414 top -= BTN_HEIGHT + TABCNTRV_PAD;
415
416 LLUI::pushMatrix();
417 { 398 {
418 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); 399 // ...but clip them.
419 tuple->mButton->draw(); 400 clip_rect.mBottom = mDownArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
401 clip_rect.mTop = mUpArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
420 } 402 }
421 LLUI::popMatrix(); 403 LLLocalClipRect clip(clip_rect);
422 404
423 idx++; 405 //S32 max_scroll_visible = mTabList.size() - mMaxScrollPos + mScrollPos;
424 } 406 S32 idx = 0;
407 for(std::vector<LLTabTuple*>::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
408 {
409 LLTabTuple* tuple = *iter;
410 tuple->mButton->translate( 0 , top - tuple->mButton->getRect().mTop);
411 top -= BTN_HEIGHT + TABCNTRV_PAD;
425 412
426 if( has_scroll_arrows ) 413 LLUI::pushMatrix();
427 { 414 {
428 // Redraw the arrows so that they appears on top. 415 LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f);
429 glPushMatrix(); 416 tuple->mButton->draw();
430 glTranslatef((F32)mUpArrowBtn->getRect().mLeft, (F32)mUpArrowBtn->getRect().mBottom, 0.f); 417 }
431 mUpArrowBtn->draw(); 418 LLUI::popMatrix();
432 glPopMatrix(); 419
433 420 idx++;
434 glPushMatrix(); 421 }
435 glTranslatef((F32)mDownArrowBtn->getRect().mLeft, (F32)mDownArrowBtn->getRect().mBottom, 0.f); 422
436 mDownArrowBtn->draw(); 423 if( has_scroll_arrows )
437 glPopMatrix(); 424 {
425 // Redraw the arrows so that they appears on top.
426 glPushMatrix();
427 glTranslatef((F32)mUpArrowBtn->getRect().mLeft, (F32)mUpArrowBtn->getRect().mBottom, 0.f);
428 mUpArrowBtn->draw();
429 glPopMatrix();
430
431 glPushMatrix();
432 glTranslatef((F32)mDownArrowBtn->getRect().mLeft, (F32)mDownArrowBtn->getRect().mBottom, 0.f);
433 mDownArrowBtn->draw();
434 glPopMatrix();
435 }
438 } 436 }
439 } 437 }
440} 438}
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp
index 513670b..f49b2db 100644
--- a/linden/indra/llui/lltexteditor.cpp
+++ b/linden/indra/llui/lltexteditor.cpp
@@ -103,9 +103,9 @@ BOOL LLTextCmd::hasExtCharValue( llwchar value )
103} 103}
104 104
105// Utility funcs 105// Utility funcs
106S32 LLTextCmd::insert(LLTextEditor* editor, S32 pos, const LLWString &utf8str) 106S32 LLTextCmd::insert(LLTextEditor* editor, S32 pos, const LLWString &wstr)
107{ 107{
108 return editor->insertStringNoUndo( pos, utf8str ); 108 return editor->insertStringNoUndo( pos, wstr );
109} 109}
110S32 LLTextCmd::remove(LLTextEditor* editor, S32 pos, S32 length) 110S32 LLTextCmd::remove(LLTextEditor* editor, S32 pos, S32 length)
111{ 111{
@@ -122,29 +122,29 @@ class LLTextCmdInsert : public LLTextCmd
122{ 122{
123public: 123public:
124 LLTextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws) 124 LLTextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws)
125 : LLTextCmd(pos, group_with_next), mString(ws) 125 : LLTextCmd(pos, group_with_next), mWString(ws)
126 { 126 {
127 } 127 }
128 virtual BOOL execute( LLTextEditor* editor, S32* delta ) 128 virtual BOOL execute( LLTextEditor* editor, S32* delta )
129 { 129 {
130 *delta = insert(editor, mPos, mString ); 130 *delta = insert(editor, mPos, mWString );
131 LLWString::truncate(mString, *delta); 131 LLWString::truncate(mWString, *delta);
132 //mString = wstring_truncate(mString, *delta); 132 //mWString = wstring_truncate(mWString, *delta);
133 return (*delta != 0); 133 return (*delta != 0);
134 } 134 }
135 virtual S32 undo( LLTextEditor* editor ) 135 virtual S32 undo( LLTextEditor* editor )
136 { 136 {
137 remove(editor, mPos, mString.length() ); 137 remove(editor, mPos, mWString.length() );
138 return mPos; 138 return mPos;
139 } 139 }
140 virtual S32 redo( LLTextEditor* editor ) 140 virtual S32 redo( LLTextEditor* editor )
141 { 141 {
142 insert(editor, mPos, mString ); 142 insert(editor, mPos, mWString );
143 return mPos + mString.length(); 143 return mPos + mWString.length();
144 } 144 }
145 145
146private: 146private:
147 LLWString mString; 147 LLWString mWString;
148}; 148};
149 149
150/////////////////////////////////////////////////////////////////// 150///////////////////////////////////////////////////////////////////
@@ -153,7 +153,7 @@ class LLTextCmdAddChar : public LLTextCmd
153{ 153{
154public: 154public:
155 LLTextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc) 155 LLTextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc)
156 : LLTextCmd(pos, group_with_next), mString(1, wc), mBlockExtensions(FALSE) 156 : LLTextCmd(pos, group_with_next), mWString(1, wc), mBlockExtensions(FALSE)
157 { 157 {
158 } 158 }
159 virtual void blockExtensions() 159 virtual void blockExtensions()
@@ -162,13 +162,13 @@ public:
162 } 162 }
163 virtual BOOL canExtend(S32 pos) 163 virtual BOOL canExtend(S32 pos)
164 { 164 {
165 return !mBlockExtensions && (pos == mPos + (S32)mString.length()); 165 return !mBlockExtensions && (pos == mPos + (S32)mWString.length());
166 } 166 }
167 virtual BOOL execute( LLTextEditor* editor, S32* delta ) 167 virtual BOOL execute( LLTextEditor* editor, S32* delta )
168 { 168 {
169 *delta = insert(editor, mPos, mString); 169 *delta = insert(editor, mPos, mWString);
170 LLWString::truncate(mString, *delta); 170 LLWString::truncate(mWString, *delta);
171 //mString = wstring_truncate(mString, *delta); 171 //mWString = wstring_truncate(mWString, *delta);
172 return (*delta != 0); 172 return (*delta != 0);
173 } 173 }
174 virtual BOOL extendAndExecute( LLTextEditor* editor, S32 pos, llwchar wc, S32* delta ) 174 virtual BOOL extendAndExecute( LLTextEditor* editor, S32 pos, llwchar wc, S32* delta )
@@ -179,23 +179,23 @@ public:
179 *delta = insert(editor, pos, ws); 179 *delta = insert(editor, pos, ws);
180 if( *delta > 0 ) 180 if( *delta > 0 )
181 { 181 {
182 mString += wc; 182 mWString += wc;
183 } 183 }
184 return (*delta != 0); 184 return (*delta != 0);
185 } 185 }
186 virtual S32 undo( LLTextEditor* editor ) 186 virtual S32 undo( LLTextEditor* editor )
187 { 187 {
188 remove(editor, mPos, mString.length() ); 188 remove(editor, mPos, mWString.length() );
189 return mPos; 189 return mPos;
190 } 190 }
191 virtual S32 redo( LLTextEditor* editor ) 191 virtual S32 redo( LLTextEditor* editor )
192 { 192 {
193 insert(editor, mPos, mString ); 193 insert(editor, mPos, mWString );
194 return mPos + mString.length(); 194 return mPos + mWString.length();
195 } 195 }
196 196
197private: 197private:
198 LLWString mString; 198 LLWString mWString;
199 BOOL mBlockExtensions; 199 BOOL mBlockExtensions;
200 200
201}; 201};
@@ -242,14 +242,14 @@ public:
242 } 242 }
243 virtual BOOL execute( LLTextEditor* editor, S32* delta ) 243 virtual BOOL execute( LLTextEditor* editor, S32* delta )
244 { 244 {
245 mString = editor->getWSubString(mPos, mLen); 245 mWString = editor->getWSubString(mPos, mLen);
246 *delta = remove(editor, mPos, mLen ); 246 *delta = remove(editor, mPos, mLen );
247 return (*delta != 0); 247 return (*delta != 0);
248 } 248 }
249 virtual S32 undo( LLTextEditor* editor ) 249 virtual S32 undo( LLTextEditor* editor )
250 { 250 {
251 insert(editor, mPos, mString ); 251 insert(editor, mPos, mWString );
252 return mPos + mString.length(); 252 return mPos + mWString.length();
253 } 253 }
254 virtual S32 redo( LLTextEditor* editor ) 254 virtual S32 redo( LLTextEditor* editor )
255 { 255 {
@@ -257,7 +257,7 @@ public:
257 return mPos; 257 return mPos;
258 } 258 }
259private: 259private:
260 LLWString mString; 260 LLWString mWString;
261 S32 mLen; 261 S32 mLen;
262}; 262};
263 263
@@ -3013,8 +3013,7 @@ void LLTextEditor::draw()
3013 if( getVisible() ) 3013 if( getVisible() )
3014 { 3014 {
3015 { 3015 {
3016 LLGLEnable scissor_test(GL_SCISSOR_TEST); 3016 LLLocalClipRect clip(LLRect(0, mRect.getHeight(), mRect.getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0));
3017 LLUI::setScissorRegionLocal(LLRect(0, mRect.getHeight(), mRect.getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0));
3018 3017
3019 bindEmbeddedChars( mGLFont ); 3018 bindEmbeddedChars( mGLFont );
3020 3019
diff --git a/linden/indra/llui/lltexteditor.h b/linden/indra/llui/lltexteditor.h
index ebe8ac3..68c1d4a 100644
--- a/linden/indra/llui/lltexteditor.h
+++ b/linden/indra/llui/lltexteditor.h
@@ -329,7 +329,7 @@ protected:
329 S32 append(const LLWString &wstr, const BOOL group_with_next_op); 329 S32 append(const LLWString &wstr, const BOOL group_with_next_op);
330 330
331 // direct operations 331 // direct operations
332 S32 insertStringNoUndo(S32 pos, const LLWString &utf8str); // returns num of chars actually inserted 332 S32 insertStringNoUndo(S32 pos, const LLWString &wstr); // returns num of chars actually inserted
333 S32 removeStringNoUndo(S32 pos, S32 length); 333 S32 removeStringNoUndo(S32 pos, S32 length);
334 S32 overwriteCharNoUndo(S32 pos, llwchar wc); 334 S32 overwriteCharNoUndo(S32 pos, llwchar wc);
335 335
@@ -495,7 +495,7 @@ public:
495 virtual BOOL hasExtCharValue( llwchar value ); 495 virtual BOOL hasExtCharValue( llwchar value );
496 496
497 // Define these here so they can access LLTextEditor through the friend relationship 497 // Define these here so they can access LLTextEditor through the friend relationship
498 S32 insert(LLTextEditor* editor, S32 pos, const LLWString &utf8str); 498 S32 insert(LLTextEditor* editor, S32 pos, const LLWString &wstr);
499 S32 remove(LLTextEditor* editor, S32 pos, S32 length); 499 S32 remove(LLTextEditor* editor, S32 pos, S32 length);
500 S32 overwrite(LLTextEditor* editor, S32 pos, llwchar wc); 500 S32 overwrite(LLTextEditor* editor, S32 pos, llwchar wc);
501 501
diff --git a/linden/indra/llui/llui.cpp b/linden/indra/llui/llui.cpp
index a725281..d0815a7 100644
--- a/linden/indra/llui/llui.cpp
+++ b/linden/indra/llui/llui.cpp
@@ -77,6 +77,8 @@ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f);
77LLWindow* LLUI::sWindow = NULL; 77LLWindow* LLUI::sWindow = NULL;
78LLHtmlHelp* LLUI::sHtmlHelp = NULL; 78LLHtmlHelp* LLUI::sHtmlHelp = NULL;
79BOOL LLUI::sShowXUINames = FALSE; 79BOOL LLUI::sShowXUINames = FALSE;
80std::stack<LLRect> LLUI::sClipRectStack;
81
80// 82//
81// Functions 83// Functions
82// 84//
@@ -110,7 +112,7 @@ void make_ui_sound(const LLString& name)
110 { 112 {
111 llinfos << "ui sound name: " << name << llendl; 113 llinfos << "ui sound name: " << name << llendl;
112 } 114 }
113 LLUI::sAudioCallback(uuid, LLUI::sConfigGroup->getF32("AudioLevelUI")); 115 LLUI::sAudioCallback(uuid);
114 } 116 }
115 } 117 }
116} 118}
@@ -1811,3 +1813,59 @@ void LLUI::setHtmlHelp(LLHtmlHelp* html_help)
1811{ 1813{
1812 LLUI::sHtmlHelp = html_help; 1814 LLUI::sHtmlHelp = html_help;
1813} 1815}
1816
1817//static
1818void LLUI::pushClipRect(const LLRect& rect)
1819{
1820 LLRect combined_clip_rect = rect;
1821 if (!sClipRectStack.empty())
1822 {
1823 combined_clip_rect.intersectWith(sClipRectStack.top());
1824 }
1825 sClipRectStack.push(combined_clip_rect);
1826 setScissorRegionScreen(combined_clip_rect);
1827}
1828
1829//static
1830void LLUI::popClipRect()
1831{
1832 sClipRectStack.pop();
1833 if (!sClipRectStack.empty())
1834 {
1835 setScissorRegionScreen(sClipRectStack.top());
1836 }
1837}
1838
1839LLClipRect::LLClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled)
1840{
1841 if (mEnabled)
1842 {
1843 LLUI::pushClipRect(rect);
1844 }
1845}
1846
1847LLClipRect::~LLClipRect()
1848{
1849 if (mEnabled)
1850 {
1851 LLUI::popClipRect();
1852 }
1853}
1854
1855LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST, enabled), mEnabled(enabled)
1856{
1857 if (mEnabled)
1858 {
1859 LLRect scissor_rect = rect;
1860 scissor_rect.translate(LLFontGL::sCurOrigin.mX, LLFontGL::sCurOrigin.mY);
1861 LLUI::pushClipRect(scissor_rect);
1862 }
1863}
1864
1865LLLocalClipRect::~LLLocalClipRect()
1866{
1867 if (mEnabled)
1868 {
1869 LLUI::popClipRect();
1870 }
1871}
diff --git a/linden/indra/llui/llui.h b/linden/indra/llui/llui.h
index 3085bd9..201d88f 100644
--- a/linden/indra/llui/llui.h
+++ b/linden/indra/llui/llui.h
@@ -36,6 +36,8 @@
36#include "llrect.h" 36#include "llrect.h"
37#include "llcoord.h" 37#include "llcoord.h"
38#include "llhtmlhelp.h" 38#include "llhtmlhelp.h"
39#include "llgl.h"
40#include <stack>
39 41
40class LLColor4; 42class LLColor4;
41class LLVector3; 43class LLVector3;
@@ -143,7 +145,7 @@ extern BOOL gShowTextEditCursor;
143extern LLString gLanguage; 145extern LLString gLanguage;
144 146
145class LLImageProviderInterface; 147class LLImageProviderInterface;
146typedef void (*LLUIAudioCallback)(const LLUUID& uuid, F32 volume); 148typedef void (*LLUIAudioCallback)(const LLUUID& uuid);
147 149
148class LLUI 150class LLUI
149{ 151{
@@ -164,8 +166,8 @@ public:
164 166
165 //helper functions (should probably move free standing rendering helper functions here) 167 //helper functions (should probably move free standing rendering helper functions here)
166 static LLString locateSkin(const LLString& filename); 168 static LLString locateSkin(const LLString& filename);
167 static void setScissorRegionScreen(const LLRect& rect); 169 static void pushClipRect(const LLRect& rect);
168 static void setScissorRegionLocal(const LLRect& rect); // works assuming LLUI::translate has been called 170 static void popClipRect();
169 static void setCursorPositionScreen(S32 x, S32 y); 171 static void setCursorPositionScreen(S32 x, S32 y);
170 static void setCursorPositionLocal(LLView* viewp, S32 x, S32 y); 172 static void setCursorPositionLocal(LLView* viewp, S32 x, S32 y);
171 static void setScaleFactor(const LLVector2& scale_factor); 173 static void setScaleFactor(const LLVector2& scale_factor);
@@ -173,6 +175,11 @@ public:
173 static LLUUID findAssetUUIDByName(const LLString& name); 175 static LLUUID findAssetUUIDByName(const LLString& name);
174 static LLVector2 getWindowSize(); 176 static LLVector2 getWindowSize();
175 static void setHtmlHelp(LLHtmlHelp* html_help); 177 static void setHtmlHelp(LLHtmlHelp* html_help);
178
179private:
180 static void setScissorRegionScreen(const LLRect& rect);
181 static void setScissorRegionLocal(const LLRect& rect); // works assuming LLUI::translate has been called
182
176public: 183public:
177 static LLControlGroup* sConfigGroup; 184 static LLControlGroup* sConfigGroup;
178 static LLControlGroup* sColorsGroup; 185 static LLControlGroup* sColorsGroup;
@@ -183,6 +190,8 @@ public:
183 static LLWindow* sWindow; 190 static LLWindow* sWindow;
184 static BOOL sShowXUINames; 191 static BOOL sShowXUINames;
185 static LLHtmlHelp* sHtmlHelp; 192 static LLHtmlHelp* sHtmlHelp;
193 static std::stack<LLRect> sClipRectStack;
194
186}; 195};
187 196
188// UI widgets 197// UI widgets
@@ -271,6 +280,7 @@ typedef enum e_widget_type
271 WIDGET_TYPE_TEXTURE_VIEW, 280 WIDGET_TYPE_TEXTURE_VIEW,
272 WIDGET_TYPE_MEMORY_VIEW, 281 WIDGET_TYPE_MEMORY_VIEW,
273 WIDGET_TYPE_FRAME_STAT_VIEW, 282 WIDGET_TYPE_FRAME_STAT_VIEW,
283 WIDGET_TYPE_LAYOUT_STACK,
274 WIDGET_TYPE_DONTCARE, 284 WIDGET_TYPE_DONTCARE,
275 WIDGET_TYPE_COUNT 285 WIDGET_TYPE_COUNT
276} EWidgetType; 286} EWidgetType;
@@ -292,38 +302,38 @@ public:
292 } 302 }
293 303
294 // default show and hide methods 304 // default show and hide methods
295 static T* showInstance(const LLSD& seed) 305 static T* showInstance(const LLSD& seed = LLSD())
296 { 306 {
297 T* instance = INSTANCE_ADAPTOR::getInstance(seed); 307 T* instance = INSTANCE_ADAPTOR::getInstance(seed);
298 INSTANCE_ADAPTOR::show(instance); 308 INSTANCE_ADAPTOR::show(instance);
299 return instance; 309 return instance;
300 } 310 }
301 311
302 static void hideInstance(const LLSD& seed) 312 static void hideInstance(const LLSD& seed = LLSD())
303 { 313 {
304 T* instance = INSTANCE_ADAPTOR::getInstance(seed); 314 T* instance = INSTANCE_ADAPTOR::getInstance(seed);
305 INSTANCE_ADAPTOR::hide(instance); 315 INSTANCE_ADAPTOR::hide(instance);
306 } 316 }
307 317
308 static void toggleInstance(const LLSD& seed) 318 static void toggleInstance(const LLSD& seed = LLSD())
309 { 319 {
310 if (!INSTANCE_ADAPTOR::instanceVisible(seed)) 320 if (INSTANCE_ADAPTOR::instanceVisible(seed))
311 { 321 {
312 INSTANCE_ADAPTOR::showInstance(seed); 322 INSTANCE_ADAPTOR::hideInstance(seed);
313 } 323 }
314 else 324 else
315 { 325 {
316 INSTANCE_ADAPTOR::hideInstance(seed); 326 INSTANCE_ADAPTOR::showInstance(seed);
317 } 327 }
318 } 328 }
319 329
320 static BOOL instanceVisible(const LLSD& seed) 330 static BOOL instanceVisible(const LLSD& seed = LLSD())
321 { 331 {
322 T* instance = INSTANCE_ADAPTOR::findInstance(seed); 332 T* instance = INSTANCE_ADAPTOR::findInstance(seed);
323 return instance != NULL && INSTANCE_ADAPTOR::visible(instance); 333 return instance != NULL && INSTANCE_ADAPTOR::visible(instance);
324 } 334 }
325 335
326 static T* getInstance(const LLSD& seed) 336 static T* getInstance(const LLSD& seed = LLSD())
327 { 337 {
328 T* instance = INSTANCE_ADAPTOR::findInstance(seed); 338 T* instance = INSTANCE_ADAPTOR::findInstance(seed);
329 if (instance == NULL) 339 if (instance == NULL)
@@ -332,6 +342,7 @@ public:
332 } 342 }
333 return instance; 343 return instance;
334 } 344 }
345
335}; 346};
336 347
337// Creates a UI singleton by ignoring the identifying parameter 348// Creates a UI singleton by ignoring the identifying parameter
@@ -346,12 +357,12 @@ public:
346 LLUISingleton() : LLUIInstanceMgr<T, INSTANCE_ADAPTOR>() { sInstance = (T*)this; } 357 LLUISingleton() : LLUIInstanceMgr<T, INSTANCE_ADAPTOR>() { sInstance = (T*)this; }
347 ~LLUISingleton() { sInstance = NULL; } 358 ~LLUISingleton() { sInstance = NULL; }
348 359
349 static T* findInstance(const LLSD& seed) 360 static T* findInstance(const LLSD& seed = LLSD())
350 { 361 {
351 return sInstance; 362 return sInstance;
352 } 363 }
353 364
354 static T* createInstance(const LLSD& seed) 365 static T* createInstance(const LLSD& seed = LLSD())
355 { 366 {
356 if (sInstance == NULL) 367 if (sInstance == NULL)
357 { 368 {
@@ -366,4 +377,24 @@ protected:
366 377
367template <class T, class U> T* LLUISingleton<T,U>::sInstance = NULL; 378template <class T, class U> T* LLUISingleton<T,U>::sInstance = NULL;
368 379
380class LLClipRect
381{
382public:
383 LLClipRect(const LLRect& rect, BOOL enabled = TRUE);
384 virtual ~LLClipRect();
385protected:
386 LLGLState mScissorState;
387 BOOL mEnabled;
388};
389
390class LLLocalClipRect
391{
392public:
393 LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
394 virtual ~LLLocalClipRect();
395protected:
396 LLGLState mScissorState;
397 BOOL mEnabled;
398};
399
369#endif 400#endif
diff --git a/linden/indra/llui/lluictrl.cpp b/linden/indra/llui/lluictrl.cpp
index 1762d7c..0ac3916 100644
--- a/linden/indra/llui/lluictrl.cpp
+++ b/linden/indra/llui/lluictrl.cpp
@@ -256,7 +256,7 @@ public:
256 /*virtual*/ void operator() (LLView * parent, viewList_t &children) const 256 /*virtual*/ void operator() (LLView * parent, viewList_t &children) const
257 { 257 {
258 children.sort(CompareByDefaultTabGroup(parent->getCtrlOrder(), parent->getDefaultTabGroup())); 258 children.sort(CompareByDefaultTabGroup(parent->getCtrlOrder(), parent->getDefaultTabGroup()));
259 } 259 }
260}; 260};
261 261
262BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields) 262BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields)
diff --git a/linden/indra/llui/lluictrl.h b/linden/indra/llui/lluictrl.h
index 5056319..2060a0d 100644
--- a/linden/indra/llui/lluictrl.h
+++ b/linden/indra/llui/lluictrl.h
@@ -148,6 +148,9 @@ public:
148 } 148 }
149 }; 149 };
150 150
151 // Returns TRUE if the user has modified this control. Editable controls should override this.
152 virtual BOOL isDirty() { return FALSE; };
153
151protected: 154protected:
152 virtual void onFocusReceived(); 155 virtual void onFocusReceived();
153 virtual void onFocusLost(); 156 virtual void onFocusLost();
diff --git a/linden/indra/llui/lluictrlfactory.cpp b/linden/indra/llui/lluictrlfactory.cpp
index 79f7313..70f1e3e 100644
--- a/linden/indra/llui/lluictrlfactory.cpp
+++ b/linden/indra/llui/lluictrlfactory.cpp
@@ -89,7 +89,7 @@ const LLString LLUICtrlFactory::sUICtrlNames[WIDGET_TYPE_COUNT] =
89 LLString("web_browser"), //WIDGET_TYPE_WEBBROWSER 89 LLString("web_browser"), //WIDGET_TYPE_WEBBROWSER
90 LLString("slider"), //WIDGET_TYPE_SLIDER, actually LLSliderCtrl 90 LLString("slider"), //WIDGET_TYPE_SLIDER, actually LLSliderCtrl
91 LLString("slider_bar"), //WIDGET_TYPE_SLIDER_BAR, actually LLSlider 91 LLString("slider_bar"), //WIDGET_TYPE_SLIDER_BAR, actually LLSlider
92 LLString("volume_slider"), //WIDGET_TYPE_VOLUME_SLIDER, actually LLVolumeSliderCtrl 92 LLString("volume_slider"), //WIDGET_TYPE_VOLUME_SLIDER, actually LLSlider + "volume" param
93 LLString("spinner"), //WIDGET_TYPE_SPINNER, actually LLSpinCtrl 93 LLString("spinner"), //WIDGET_TYPE_SPINNER, actually LLSpinCtrl
94 LLString("text_editor"), //WIDGET_TYPE_TEXT_EDITOR 94 LLString("text_editor"), //WIDGET_TYPE_TEXT_EDITOR
95 LLString("texture_picker"),//WIDGET_TYPE_TEXTURE_PICKER 95 LLString("texture_picker"),//WIDGET_TYPE_TEXTURE_PICKER
@@ -155,6 +155,7 @@ const LLString LLUICtrlFactory::sUICtrlNames[WIDGET_TYPE_COUNT] =
155 LLString("texture_view"), //WIDGET_TYPE_TEXTURE_VIEW 155 LLString("texture_view"), //WIDGET_TYPE_TEXTURE_VIEW
156 LLString("memory_view"), //WIDGET_TYPE_MEMORY_VIEW 156 LLString("memory_view"), //WIDGET_TYPE_MEMORY_VIEW
157 LLString("frame_stat_view"), //WIDGET_TYPE_FRAME_STAT_VIEW 157 LLString("frame_stat_view"), //WIDGET_TYPE_FRAME_STAT_VIEW
158 LLString("layout_stack"), //WIDGET_TYPE_LAYOUT_STACK
158 LLString("DONT_CARE"), //WIDGET_TYPE_DONTCARE 159 LLString("DONT_CARE"), //WIDGET_TYPE_DONTCARE
159}; 160};
160 161
@@ -197,6 +198,7 @@ LLUICtrlFactory::LLUICtrlFactory()
197 LLUICtrlCreator<LLScrollListCtrl>::registerCreator(LL_SCROLL_LIST_CTRL_TAG, this); 198 LLUICtrlCreator<LLScrollListCtrl>::registerCreator(LL_SCROLL_LIST_CTRL_TAG, this);
198 LLUICtrlCreator<LLSliderCtrl>::registerCreator(LL_SLIDER_CTRL_TAG, this); 199 LLUICtrlCreator<LLSliderCtrl>::registerCreator(LL_SLIDER_CTRL_TAG, this);
199 LLUICtrlCreator<LLSlider>::registerCreator(LL_SLIDER_TAG, this); 200 LLUICtrlCreator<LLSlider>::registerCreator(LL_SLIDER_TAG, this);
201 LLUICtrlCreator<LLSlider>::registerCreator(LL_VOLUME_SLIDER_CTRL_TAG, this);
200 LLUICtrlCreator<LLSpinCtrl>::registerCreator(LL_SPIN_CTRL_TAG, this); 202 LLUICtrlCreator<LLSpinCtrl>::registerCreator(LL_SPIN_CTRL_TAG, this);
201 LLUICtrlCreator<LLTextBox>::registerCreator(LL_TEXT_BOX_TAG, this); 203 LLUICtrlCreator<LLTextBox>::registerCreator(LL_TEXT_BOX_TAG, this);
202 LLUICtrlCreator<LLRadioGroup>::registerCreator(LL_RADIO_GROUP_TAG, this); 204 LLUICtrlCreator<LLRadioGroup>::registerCreator(LL_RADIO_GROUP_TAG, this);
@@ -210,6 +212,7 @@ LLUICtrlFactory::LLUICtrlFactory()
210 LLUICtrlCreator<LLMenuGL>::registerCreator(LL_MENU_GL_TAG, this); 212 LLUICtrlCreator<LLMenuGL>::registerCreator(LL_MENU_GL_TAG, this);
211 LLUICtrlCreator<LLMenuBarGL>::registerCreator(LL_MENU_BAR_GL_TAG, this); 213 LLUICtrlCreator<LLMenuBarGL>::registerCreator(LL_MENU_BAR_GL_TAG, this);
212 LLUICtrlCreator<LLScrollingPanelList>::registerCreator(LL_SCROLLING_PANEL_LIST_TAG, this); 214 LLUICtrlCreator<LLScrollingPanelList>::registerCreator(LL_SCROLLING_PANEL_LIST_TAG, this);
215 LLUICtrlCreator<LLLayoutStack>::registerCreator(LL_LAYOUT_STACK_TAG, this);
213 216
214 setupPaths(); 217 setupPaths();
215 218
@@ -765,6 +768,37 @@ LLScrollingPanelList* LLUICtrlFactory::getScrollingPanelList(LLPanel* panelp, co
765 return (LLScrollingPanelList*)panelp->getCtrlByNameAndType(name, WIDGET_TYPE_SCROLLING_PANEL_LIST); 768 return (LLScrollingPanelList*)panelp->getCtrlByNameAndType(name, WIDGET_TYPE_SCROLLING_PANEL_LIST);
766} 769}
767 770
771
772LLCtrlListInterface* LLUICtrlFactory::getListInterfaceByName(LLPanel* panelp, const LLString& name)
773{
774 LLView* viewp = panelp->getCtrlByNameAndType(name, WIDGET_TYPE_DONTCARE);
775 if (viewp && viewp->isCtrl())
776 {
777 return ((LLUICtrl*)viewp)->getListInterface();
778 }
779 return NULL;
780}
781
782LLCtrlSelectionInterface* LLUICtrlFactory::getSelectionInterfaceByName(LLPanel* panelp, const LLString& name)
783{
784 LLView* viewp = panelp->getCtrlByNameAndType(name, WIDGET_TYPE_DONTCARE);
785 if (viewp && viewp->isCtrl())
786 {
787 return ((LLUICtrl*)viewp)->getSelectionInterface();
788 }
789 return NULL;
790}
791
792LLCtrlScrollInterface* LLUICtrlFactory::getScrollInterfaceByName(LLPanel* panelp, const LLString& name)
793{
794 LLView* viewp = panelp->getCtrlByNameAndType(name, WIDGET_TYPE_DONTCARE);
795 if (viewp && viewp->isCtrl())
796 {
797 return ((LLUICtrl*)viewp)->getScrollInterface();
798 }
799 return NULL;
800}
801
768void LLUICtrlFactory::registerCreator(LLString ctrlname, creator_function_t function) 802void LLUICtrlFactory::registerCreator(LLString ctrlname, creator_function_t function)
769{ 803{
770 LLString::toLower(ctrlname); 804 LLString::toLower(ctrlname);
diff --git a/linden/indra/llui/lluictrlfactory.h b/linden/indra/llui/lluictrlfactory.h
index eaae754..e12017d 100644
--- a/linden/indra/llui/lluictrlfactory.h
+++ b/linden/indra/llui/lluictrlfactory.h
@@ -65,6 +65,9 @@ class LLWebBrowserCtrl;
65class LLViewBorder; 65class LLViewBorder;
66class LLColorSwatchCtrl; 66class LLColorSwatchCtrl;
67class LLScrollingPanelList; 67class LLScrollingPanelList;
68class LLCtrlListInterface;
69class LLCtrlSelectionInterface;
70class LLCtrlScrollInterface;
68 71
69// Widget 72// Widget
70 73
@@ -123,6 +126,11 @@ public:
123 static LLMenuItemCallGL* getMenuItemCallByName(LLPanel* panelp, const LLString& name); 126 static LLMenuItemCallGL* getMenuItemCallByName(LLPanel* panelp, const LLString& name);
124 static LLScrollingPanelList* getScrollingPanelList(LLPanel* panelp, const LLString& name); 127 static LLScrollingPanelList* getScrollingPanelList(LLPanel* panelp, const LLString& name);
125 128
129 // interface getters
130 static LLCtrlListInterface* getListInterfaceByName(LLPanel* panelp, const LLString& name);
131 static LLCtrlSelectionInterface* getSelectionInterfaceByName(LLPanel* panelp, const LLString& name);
132 static LLCtrlScrollInterface* getScrollInterfaceByName(LLPanel* panelp, const LLString& name);
133
126 LLPanel* createFactoryPanel(LLString name); 134 LLPanel* createFactoryPanel(LLString name);
127 135
128 virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node); 136 virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node);
diff --git a/linden/indra/llui/lluistring.cpp b/linden/indra/llui/lluistring.cpp
index 49b6fca..cf1b0e0 100644
--- a/linden/indra/llui/lluistring.cpp
+++ b/linden/indra/llui/lluistring.cpp
@@ -30,6 +30,9 @@
30 30
31#include "lluistring.h" 31#include "lluistring.h"
32 32
33const LLString::format_map_t LLUIString::sNullArgs;
34
35
33// public 36// public
34 37
35LLUIString::LLUIString(const LLString& instring, const LLString::format_map_t& args) 38LLUIString::LLUIString(const LLString& instring, const LLString::format_map_t& args)
diff --git a/linden/indra/llui/lluistring.h b/linden/indra/llui/lluistring.h
index 37792aa..c5d9152 100644
--- a/linden/indra/llui/lluistring.h
+++ b/linden/indra/llui/lluistring.h
@@ -95,6 +95,8 @@ public:
95 void insert(S32 charidx, const LLWString& wchars); 95 void insert(S32 charidx, const LLWString& wchars);
96 void replace(S32 charidx, llwchar wc); 96 void replace(S32 charidx, llwchar wc);
97 97
98 static const LLString::format_map_t sNullArgs;
99
98private: 100private:
99 void format(); 101 void format();
100 102
diff --git a/linden/indra/llui/lluixmltags.h b/linden/indra/llui/lluixmltags.h
index 08c5f67..7728d73 100644
--- a/linden/indra/llui/lluixmltags.h
+++ b/linden/indra/llui/lluixmltags.h
@@ -116,4 +116,5 @@
116#define LL_JOYSTICK_SLIDE "joystick_slide" 116#define LL_JOYSTICK_SLIDE "joystick_slide"
117#define LL_JOYSTICK_TURN "joystick_turn" 117#define LL_JOYSTICK_TURN "joystick_turn"
118#define LL_GROUP_DROP_TARGET_TAG "group_drop_target" 118#define LL_GROUP_DROP_TARGET_TAG "group_drop_target"
119#define LL_LAYOUT_STACK_TAG "layout_stack"
119#endif 120#endif
diff --git a/linden/indra/llui/llview.cpp b/linden/indra/llui/llview.cpp
index 0b04213..2a62602 100644
--- a/linden/indra/llui/llview.cpp
+++ b/linden/indra/llui/llview.cpp
@@ -325,6 +325,10 @@ void LLView::moveChildToFrontOfTabGroup(LLUICtrl* child)
325 325
326void LLView::addChild(LLView* child, S32 tab_group) 326void LLView::addChild(LLView* child, S32 tab_group)
327{ 327{
328 if (mParentView == child)
329 {
330 llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
331 }
328 // remove from current parent 332 // remove from current parent
329 if (child->mParentView) 333 if (child->mParentView)
330 { 334 {
@@ -348,6 +352,10 @@ void LLView::addChild(LLView* child, S32 tab_group)
348 352
349void LLView::addChildAtEnd(LLView* child, S32 tab_group) 353void LLView::addChildAtEnd(LLView* child, S32 tab_group)
350{ 354{
355 if (mParentView == child)
356 {
357 llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
358 }
351 // remove from current parent 359 // remove from current parent
352 if (child->mParentView) 360 if (child->mParentView)
353 { 361 {
@@ -752,18 +760,22 @@ void LLView::setEnabled(BOOL enabled)
752// virtual 760// virtual
753void LLView::setVisible(BOOL visible) 761void LLView::setVisible(BOOL visible)
754{ 762{
755 if( !visible && (gFocusMgr.getTopCtrl() == this) )
756 {
757 gFocusMgr.setTopCtrl( NULL );
758 }
759
760 if ( mVisible != visible ) 763 if ( mVisible != visible )
761 { 764 {
762 // tell all children of this view that the visibility may have changed 765 if( !visible && (gFocusMgr.getTopCtrl() == this) )
763 onVisibilityChange ( visible ); 766 {
764 } 767 gFocusMgr.setTopCtrl( NULL );
768 }
765 769
766 mVisible = visible; 770 mVisible = visible;
771
772 // notify children of visibility change if root, or part of visible hierarchy
773 if (!getParent() || getParent()->isInVisibleChain())
774 {
775 // tell all children of this view that the visibility may have changed
776 onVisibilityChange( visible );
777 }
778 }
767} 779}
768 780
769// virtual 781// virtual
@@ -778,7 +790,7 @@ BOOL LLView::setLabelArg(const LLString& key, const LLString& text)
778 return FALSE; 790 return FALSE;
779} 791}
780 792
781void LLView::onVisibilityChange ( BOOL curVisibilityIn ) 793void LLView::onVisibilityChange ( BOOL new_visibility )
782{ 794{
783 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) 795 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
784 { 796 {
@@ -786,7 +798,7 @@ void LLView::onVisibilityChange ( BOOL curVisibilityIn )
786 // only views that are themselves visible will have their overall visibility affected by their ancestors 798 // only views that are themselves visible will have their overall visibility affected by their ancestors
787 if (viewp->getVisible()) 799 if (viewp->getVisible())
788 { 800 {
789 viewp->onVisibilityChange ( curVisibilityIn ); 801 viewp->onVisibilityChange ( new_visibility );
790 } 802 }
791 } 803 }
792} 804}
@@ -1390,64 +1402,61 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
1390 1402
1391void LLView::draw() 1403void LLView::draw()
1392{ 1404{
1393 if (getVisible()) 1405 if (sDebugRects)
1394 { 1406 {
1395 if (sDebugRects) 1407 drawDebugRect();
1396 {
1397 drawDebugRect();
1398 1408
1399 // Check for bogus rectangle 1409 // Check for bogus rectangle
1400 if (mRect.mRight <= mRect.mLeft 1410 if (mRect.mRight <= mRect.mLeft
1401 || mRect.mTop <= mRect.mBottom) 1411 || mRect.mTop <= mRect.mBottom)
1402 { 1412 {
1403 llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl; 1413 llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
1404 }
1405 } 1414 }
1415 }
1406 1416
1407 LLRect rootRect = getRootView()->getRect(); 1417 LLRect rootRect = getRootView()->getRect();
1408 LLRect screenRect; 1418 LLRect screenRect;
1409 1419
1410 // draw focused control on top of everything else 1420 // draw focused control on top of everything else
1411 LLView* focus_view = gFocusMgr.getKeyboardFocus(); 1421 LLView* focus_view = gFocusMgr.getKeyboardFocus();
1412 if (focus_view && focus_view->getParent() != this) 1422 if (focus_view && focus_view->getParent() != this)
1413 { 1423 {
1414 focus_view = NULL; 1424 focus_view = NULL;
1415 } 1425 }
1416 1426
1417 for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) 1427 for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
1418 { 1428 {
1419 LLView *viewp = *child_iter; 1429 LLView *viewp = *child_iter;
1420 ++sDepth; 1430 ++sDepth;
1421 1431
1422 if (viewp->getVisible() && viewp != focus_view) 1432 if (viewp->getVisible() && viewp != focus_view)
1433 {
1434 // Only draw views that are within the root view
1435 localRectToScreen(viewp->getRect(),&screenRect);
1436 if ( rootRect.rectInRect(&screenRect) )
1423 { 1437 {
1424 // Only draw views that are within the root view 1438 glMatrixMode(GL_MODELVIEW);
1425 localRectToScreen(viewp->getRect(),&screenRect); 1439 LLUI::pushMatrix();
1426 if ( rootRect.rectInRect(&screenRect) )
1427 { 1440 {
1428 glMatrixMode(GL_MODELVIEW); 1441 LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
1429 LLUI::pushMatrix(); 1442 viewp->draw();
1430 {
1431 LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
1432 viewp->draw();
1433 }
1434 LLUI::popMatrix();
1435 } 1443 }
1444 LLUI::popMatrix();
1436 } 1445 }
1437
1438 --sDepth;
1439 } 1446 }
1440 1447
1441 if (focus_view && focus_view->getVisible()) 1448 --sDepth;
1442 { 1449 }
1443 drawChild(focus_view);
1444 }
1445 1450
1446 // HACK 1451 if (focus_view && focus_view->getVisible())
1447 if (sEditingUI && this == sEditingUIView) 1452 {
1448 { 1453 drawChild(focus_view);
1449 drawDebugRect(); 1454 }
1450 } 1455
1456 // HACK
1457 if (sEditingUI && this == sEditingUIView)
1458 {
1459 drawDebugRect();
1451 } 1460 }
1452} 1461}
1453 1462
@@ -1500,13 +1509,13 @@ void LLView::drawDebugRect()
1500 } 1509 }
1501} 1510}
1502 1511
1503void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset) 1512void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw)
1504{ 1513{
1505 if (childp && childp->getParent() == this) 1514 if (childp && childp->getParent() == this)
1506 { 1515 {
1507 ++sDepth; 1516 ++sDepth;
1508 1517
1509 if (childp->getVisible()) 1518 if (childp->getVisible() || force_draw)
1510 { 1519 {
1511 glMatrixMode(GL_MODELVIEW); 1520 glMatrixMode(GL_MODELVIEW);
1512 LLUI::pushMatrix(); 1521 LLUI::pushMatrix();
@@ -1636,7 +1645,7 @@ void LLView::updateRect()
1636 LLView* viewp = *child_it; 1645 LLView* viewp = *child_it;
1637 if (viewp->getVisible()) 1646 if (viewp->getVisible())
1638 { 1647 {
1639 child_spanning_rect |= viewp->mRect; 1648 child_spanning_rect.unionWith(viewp->mRect);
1640 } 1649 }
1641 } 1650 }
1642 1651
diff --git a/linden/indra/llui/llview.h b/linden/indra/llui/llview.h
index c7664eb..053ef82 100644
--- a/linden/indra/llui/llview.h
+++ b/linden/indra/llui/llview.h
@@ -379,7 +379,7 @@ public:
379 virtual void draw(); 379 virtual void draw();
380 380
381 void drawDebugRect(); 381 void drawDebugRect();
382 void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0); 382 void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);
383 383
384 virtual const LLString& getName() const; 384 virtual const LLString& getName() const;
385 385