From a4000c3744e42fcbb638e742f3b63fa31a0dee15 Mon Sep 17 00:00:00 2001
From: Steven Bennetts <steve@lindenlab.com>
Date: Fri, 8 May 2009 07:43:08 +0000
Subject: merge trunk@116587 skinning-7@119389 -> viewer-2.0.0-skinning-7

---
 indra/llui/CMakeLists.txt           |   48 +-
 indra/llui/llbutton.cpp             |  680 ++++----
 indra/llui/llbutton.h               |  195 ++-
 indra/llui/llcallbackmap.h          |   19 +-
 indra/llui/llcheckboxctrl.cpp       |  278 +--
 indra/llui/llcheckboxctrl.h         |   73 +-
 indra/llui/llcombobox.cpp           |  555 ++----
 indra/llui/llcombobox.h             |  126 +-
 indra/llui/llconsole.cpp            |  393 +++++
 indra/llui/llconsole.h              |  162 ++
 indra/llui/llcontainerview.cpp      |  301 ++++
 indra/llui/llcontainerview.h        |   92 +
 indra/llui/lldraghandle.cpp         |  105 +-
 indra/llui/lldraghandle.h           |   44 +-
 indra/llui/llf32uictrl.cpp          |   57 +
 indra/llui/llf32uictrl.h            |   83 +
 indra/llui/llfloater.cpp            | 1649 ++++++------------
 indra/llui/llfloater.h              |  297 ++--
 indra/llui/llfloaterreg.cpp         |  423 +++++
 indra/llui/llfloaterreg.h           |  149 ++
 indra/llui/llflyoutbutton.cpp       |   94 +
 indra/llui/llflyoutbutton.h         |   71 +
 indra/llui/llfocusmgr.cpp           |   20 +-
 indra/llui/llfunctorregistry.h      |    2 +-
 indra/llui/lliconctrl.cpp           |  126 +-
 indra/llui/lliconctrl.h             |   32 +-
 indra/llui/llkeywords.cpp           |    4 +-
 indra/llui/lllayoutstack.cpp        |  718 ++++++++
 indra/llui/lllayoutstack.h          |  102 ++
 indra/llui/lllazyvalue.h            |   83 +
 indra/llui/lllineeditor.cpp         |  690 ++------
 indra/llui/lllineeditor.h           |  177 +-
 indra/llui/llmenugl.cpp             | 3256 ++++++++++++-----------------------
 indra/llui/llmenugl.h               |  583 ++++---
 indra/llui/llmodaldialog.cpp        |   48 +-
 indra/llui/llmodaldialog.h          |    2 +-
 indra/llui/llmultifloater.cpp       |  510 ++++++
 indra/llui/llmultifloater.h         |  107 ++
 indra/llui/llmultislider.cpp        |  218 +--
 indra/llui/llmultislider.h          |   97 +-
 indra/llui/llmultisliderctrl.cpp    |  392 ++---
 indra/llui/llmultisliderctrl.h      |   71 +-
 indra/llui/llnotifications.cpp      |  164 +-
 indra/llui/llnotifications.h        |   97 +-
 indra/llui/llpanel.cpp              | 1133 ++----------
 indra/llui/llpanel.h                |  164 +-
 indra/llui/llprogressbar.cpp        |  135 +-
 indra/llui/llprogressbar.h          |   45 +-
 indra/llui/llradiogroup.cpp         |  248 +--
 indra/llui/llradiogroup.h           |   74 +-
 indra/llui/llresizebar.cpp          |   37 +-
 indra/llui/llresizebar.h            |   26 +-
 indra/llui/llresizehandle.cpp       |   57 +-
 indra/llui/llresizehandle.h         |   13 +-
 indra/llui/llresmgr.cpp             |  147 +-
 indra/llui/llresmgr.h               |   25 +-
 indra/llui/llscrollbar.cpp          |  237 ++-
 indra/llui/llscrollbar.h            |   72 +-
 indra/llui/llscrollcontainer.cpp    |  303 ++--
 indra/llui/llscrollcontainer.h      |   36 +-
 indra/llui/llscrollingpanellist.cpp |   62 +-
 indra/llui/llscrollingpanellist.h   |   30 +-
 indra/llui/llscrolllistcell.cpp     |  413 +++++
 indra/llui/llscrolllistcell.h       |  223 +++
 indra/llui/llscrolllistcolumn.cpp   |  320 ++++
 indra/llui/llscrolllistcolumn.h     |  189 ++
 indra/llui/llscrolllistctrl.cpp     | 1884 ++++----------------
 indra/llui/llscrolllistctrl.h       |  433 ++---
 indra/llui/llscrolllistitem.cpp     |  157 ++
 indra/llui/llscrolllistitem.h       |  129 ++
 indra/llui/llsdparam.cpp            |  158 ++
 indra/llui/llsdparam.h              |  107 ++
 indra/llui/llsearcheditor.cpp       |  124 ++
 indra/llui/llsearcheditor.h         |   98 ++
 indra/llui/llslider.cpp             |  155 +-
 indra/llui/llslider.h               |   71 +-
 indra/llui/llsliderctrl.cpp         |  339 ++--
 indra/llui/llsliderctrl.h           |  119 +-
 indra/llui/llspinctrl.cpp           |  371 ++--
 indra/llui/llspinctrl.h             |   74 +-
 indra/llui/llstatbar.cpp            |  295 ++++
 indra/llui/llstatbar.h              |  108 ++
 indra/llui/llstatgraph.cpp          |  163 ++
 indra/llui/llstatgraph.h            |   76 +
 indra/llui/llstatview.cpp           |   66 +
 indra/llui/llstatview.h             |   63 +
 indra/llui/llstyle.cpp              |   32 +-
 indra/llui/llstyle.h                |    9 +-
 indra/llui/lltabcontainer.cpp       |  790 ++++-----
 indra/llui/lltabcontainer.h         |  119 +-
 indra/llui/lltextbox.cpp            |  245 ++-
 indra/llui/lltextbox.h              |   81 +-
 indra/llui/lltexteditor.cpp         |  572 +++---
 indra/llui/lltexteditor.h           |  110 +-
 indra/llui/lltextparser.cpp         |   55 +-
 indra/llui/lltextparser.h           |   34 +-
 indra/llui/llui.cpp                 |  386 +++--
 indra/llui/llui.h                   |  312 ++--
 indra/llui/lluictrl.cpp             |  354 +++-
 indra/llui/lluictrl.h               |  179 +-
 indra/llui/lluictrlfactory.cpp      |  984 ++++++++---
 indra/llui/lluictrlfactory.h        |  320 +++-
 indra/llui/lluifwd.h                |    1 -
 indra/llui/lluiimage.cpp            |  158 ++
 indra/llui/lluiimage.h              |  113 ++
 indra/llui/lluistring.cpp           |    7 +-
 indra/llui/llview.cpp               | 1226 +++++--------
 indra/llui/llview.h                 |  345 ++--
 indra/llui/llviewborder.cpp         |  139 +-
 indra/llui/llviewborder.h           |   57 +-
 indra/llui/llviewmodel.cpp          |  163 ++
 indra/llui/llviewmodel.h            |  219 +++
 indra/llui/llviewquery.h            |    2 +-
 113 files changed, 15755 insertions(+), 13629 deletions(-)
 create mode 100644 indra/llui/llconsole.cpp
 create mode 100644 indra/llui/llconsole.h
 create mode 100644 indra/llui/llcontainerview.cpp
 create mode 100644 indra/llui/llcontainerview.h
 create mode 100644 indra/llui/llf32uictrl.cpp
 create mode 100644 indra/llui/llf32uictrl.h
 create mode 100644 indra/llui/llfloaterreg.cpp
 create mode 100644 indra/llui/llfloaterreg.h
 create mode 100644 indra/llui/llflyoutbutton.cpp
 create mode 100644 indra/llui/llflyoutbutton.h
 create mode 100644 indra/llui/lllayoutstack.cpp
 create mode 100644 indra/llui/lllayoutstack.h
 create mode 100644 indra/llui/lllazyvalue.h
 create mode 100644 indra/llui/llmultifloater.cpp
 create mode 100644 indra/llui/llmultifloater.h
 create mode 100644 indra/llui/llscrolllistcell.cpp
 create mode 100644 indra/llui/llscrolllistcell.h
 create mode 100644 indra/llui/llscrolllistcolumn.cpp
 create mode 100644 indra/llui/llscrolllistcolumn.h
 create mode 100644 indra/llui/llscrolllistitem.cpp
 create mode 100644 indra/llui/llscrolllistitem.h
 create mode 100644 indra/llui/llsdparam.cpp
 create mode 100644 indra/llui/llsdparam.h
 create mode 100644 indra/llui/llsearcheditor.cpp
 create mode 100644 indra/llui/llsearcheditor.h
 create mode 100644 indra/llui/llstatbar.cpp
 create mode 100644 indra/llui/llstatbar.h
 create mode 100644 indra/llui/llstatgraph.cpp
 create mode 100644 indra/llui/llstatgraph.h
 create mode 100644 indra/llui/llstatview.cpp
 create mode 100644 indra/llui/llstatview.h
 create mode 100644 indra/llui/lluiimage.cpp
 create mode 100644 indra/llui/lluiimage.h
 create mode 100644 indra/llui/llviewmodel.cpp
 create mode 100644 indra/llui/llviewmodel.h

(limited to 'indra/llui')

diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 5de8dc76af..f3595a7b05 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -31,17 +31,25 @@ set(llui_SOURCE_FILES
     llcheckboxctrl.cpp
     llclipboard.cpp
     llcombobox.cpp
+    llconsole.cpp
+    llcontainerview.cpp
     llctrlselectioninterface.cpp
     lldraghandle.cpp
     lleditmenuhandler.cpp
+    llf32uictrl.cpp
     llfloater.cpp
+    llfloaterreg.cpp
+    llflyoutbutton.cpp 
     llfocusmgr.cpp
     llfunctorregistry.cpp
     lliconctrl.cpp
+    llinitparam.cpp
     llkeywords.cpp
+    lllayoutstack.cpp
     lllineeditor.cpp
     llmenugl.cpp
     llmodaldialog.cpp
+    llmultifloater.cpp 
     llmultislider.cpp
     llmultisliderctrl.cpp
     llnotifications.cpp
@@ -51,27 +59,35 @@ set(llui_SOURCE_FILES
     llresizebar.cpp
     llresizehandle.cpp
     llresmgr.cpp
-    llrootview.cpp
     llscrollbar.cpp
     llscrollcontainer.cpp
     llscrollingpanellist.cpp
+    llscrolllistcell.cpp
+    llscrolllistcolumn.cpp
     llscrolllistctrl.cpp
+    llscrolllistitem.cpp
+    llsdparam.cpp
+    llsearcheditor.cpp 
     llslider.cpp
     llsliderctrl.cpp
     llspinctrl.cpp
+    llstatbar.cpp
+    llstatgraph.cpp
+    llstatview.cpp
     llstyle.cpp
     lltabcontainer.cpp
-    lltabcontainervertical.cpp
     lltextbox.cpp
     lltexteditor.cpp
     lltextparser.cpp
+    lltrans.cpp
     llui.cpp
     lluictrl.cpp
     lluictrlfactory.cpp
+    lluiimage.cpp
     lluistring.cpp
-    lluitrans.cpp
     llundo.cpp
     llviewborder.cpp
+    llviewmodel.cpp
     llview.cpp
     llviewquery.cpp
     )
@@ -85,52 +101,68 @@ set(llui_HEADER_FILES
     llcheckboxctrl.h
     llclipboard.h
     llcombobox.h
+    llconsole.h
+    llcontainerview.h
     llctrlselectioninterface.h
     lldraghandle.h
     lleditmenuhandler.h
+    llf32uictrl.h
     llfloater.h
+    llfloaterreg.h
+    llflyoutbutton.h 
     llfocusmgr.h
     llfunctorregistry.h
     llhtmlhelp.h
     lliconctrl.h
+    llinitparam.h
     llkeywords.h
+    lllayoutstack.h
+    lllazyvalue.h
     lllineeditor.h
-    llmemberlistener.h
     llmenugl.h
     llmodaldialog.h
+    llmultifloater.h 
     llmultisliderctrl.h
     llmultislider.h
     llnotifications.h
     llpanel.h
     llprogressbar.h
     llradiogroup.h
+    llregistry.h
     llresizebar.h
     llresizehandle.h
     llresmgr.h
-    llrootview.h
+    llsearcheditor.h 
     llscrollbar.h
     llscrollcontainer.h
     llscrollingpanellist.h
+    llscrolllistcell.h
+    llscrolllistcolumn.h
     llscrolllistctrl.h
+    llscrolllistitem.h
+    llsdparam.h
     llsliderctrl.h
     llslider.h
     llspinctrl.h
+    llstatbar.h
+    llstatgraph.h
+    llstatview.h
     llstyle.h
     lltabcontainer.h
-    lltabcontainervertical.h
     lltextbox.h
     lltexteditor.h
     lltextparser.h
+    lltrans.h
     lluiconstants.h
     lluictrlfactory.h
     lluictrl.h
     lluifwd.h
     llui.h
+    lluiimage.h
     lluistring.h
-    lluitrans.h
-    lluixmltags.h
     llundo.h
     llviewborder.h
+    llviewmodel.h
     llview.h
     llviewquery.h
     )
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 2c2c1c25d8..1f6cd6ddf9 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -32,6 +32,7 @@
 
 #include "linden_common.h"
 
+#define INSTANTIATE_GETCHILD_BUTTON
 #include "llbutton.h"
 
 // Linden library includes
@@ -45,183 +46,167 @@
 #include "lluiconstants.h"
 #include "llresmgr.h"
 #include "llcriticaldamp.h"
+#include "llfloater.h"
+#include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llwindow.h"
 #include "llrender.h"
+#include "lluictrlfactory.h"
 
 static LLRegisterWidget<LLButton> r("button");
 
 // globals loaded from settings.xml
-S32	LLBUTTON_ORIG_H_PAD	= 6; // Pre-zoomable UI
 S32	LLBUTTON_H_PAD	= 0;
 S32	LLBUTTON_V_PAD	= 0;
 S32 BTN_HEIGHT_SMALL= 0;
 S32 BTN_HEIGHT		= 0;
 
-S32 BTN_GRID		= 12;
-S32 BORDER_SIZE = 1;
-
-LLButton::LLButton(	const std::string& name, const LLRect& rect, const std::string& control_name, void (*click_callback)(void*), void *callback_data)
-:	LLUICtrl(name, rect, TRUE, NULL, NULL),
-	mClickedCallback( click_callback ),
-	mMouseDownCallback( NULL ),
-	mMouseUpCallback( NULL ),
-	mHeldDownCallback( NULL ),
-	mGLFont( NULL ),
-	mMouseDownFrame( 0 ),
-	mHeldDownDelay( 0.5f ),			// seconds until held-down callback is called
-	mHeldDownFrameDelay( 0 ),
-	mImageUnselected( NULL ),
-	mImageSelected( NULL ),
-	mImageHoverSelected( NULL ),
-	mImageHoverUnselected( NULL ),
-	mImageDisabled( NULL ),
-	mImageDisabledSelected( NULL ),
-	mToggleState( FALSE ),
-	mIsToggle( FALSE ),
-	mScaleImage( TRUE ),
-	mDropShadowedText( TRUE ),
-	mBorderEnabled( FALSE ),
-	mFlashing( FALSE ),
-	mHAlign( LLFontGL::HCENTER ),
-	mLeftHPad( LLBUTTON_H_PAD ),
-	mRightHPad( LLBUTTON_H_PAD ),
-	mHoverGlowStrength(0.15f),
-	mCurGlowStrength(0.f),
-	mNeedsHighlight(FALSE),
-	mCommitOnReturn(TRUE),
-	mImagep( NULL )
+template LLButton* LLView::getChild<LLButton>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+
+LLButton::Params::Params()
+:	label_selected("label_selected"),				// requires is_toggle true
+	label_dropshadow("label_shadow", true),
+	auto_resize("auto_resize", false),
+	image_unselected("image_unselected"),
+	image_selected("image_selected"),
+	image_hover_selected("image_hover_selected"),
+	image_hover_unselected("image_hover_unselected"),
+	image_disabled_selected("image_disabled_selected"),
+	image_disabled("image_disabled"),
+	image_overlay("image_overlay"),
+	image_overlay_alignment("image_overlay_alignment", std::string("center")),
+	label_color("label_color"),
+	label_color_selected("label_color_selected"),	// requires is_toggle true
+	label_color_disabled("label_color_disabled"),
+	label_color_disabled_selected("label_color_disabled_selected"),
+	highlight_color("highlight_color"),
+	image_color("image_color"),
+	image_color_disabled("image_color_disabled"),
+	image_overlay_color("image_overlay_color", LLColor4::white),
+	flash_color("flash_color"),
+	pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
+	pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")),
+	click_callback("click_callback"),
+	mouse_down_callback("mouse_down_callback"),
+	mouse_up_callback("mouse_up_callback"),
+	mouse_held_callback("mouse_held_callback"),
+	mouse_held_once_callback("mouse_held_once_callback"),
+	is_toggle("is_toggle", false),
+	scale_image("scale_image", true),
+	help_url("help_url"),
+	hover_glow_amount("hover_glow_amount"),
+	commit_on_return("commit_on_return", true),
+	picture_style("picture_style", false)
 {
-	mUnselectedLabel = name;
-	mSelectedLabel = name;
-
-	setImageUnselected(std::string("button_enabled_32x128.tga"));
-	setImageSelected(std::string("button_enabled_selected_32x128.tga"));
-	setImageDisabled(std::string("button_disabled_32x128.tga"));
-	setImageDisabledSelected(std::string("button_disabled_32x128.tga"));
-
-	mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
-	mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
-
-	init(click_callback, callback_data, NULL, control_name);
+	addSynonym(is_toggle, "toggle");
+	held_down_delay.seconds = 0.5f;
+	initial_value.set(LLSD(false), false);
 }
 
 
-LLButton::LLButton(const std::string& name, const LLRect& rect, 
-				   const std::string &unselected_image_name, 
-				   const std::string &selected_image_name, 
-				   const std::string& control_name,
-				   void (*click_callback)(void*),
-				   void *callback_data,
-				   const LLFontGL *font,
-				   const std::string& unselected_label, 
-				   const std::string& selected_label )
-:	LLUICtrl(name, rect, TRUE, NULL, NULL),
-	mClickedCallback( click_callback ),
-	mMouseDownCallback( NULL ),
-	mMouseUpCallback( NULL ),
-	mHeldDownCallback( NULL ),
-	mGLFont( NULL ),
-	mMouseDownFrame( 0 ),
-	mHeldDownDelay( 0.5f ),			// seconds until held-down callback is called
-	mHeldDownFrameDelay( 0 ),
-	mImageUnselected( NULL ),
-	mImageSelected( NULL ),
-	mImageHoverSelected( NULL ),
-	mImageHoverUnselected( NULL ),
-	mImageDisabled( NULL ),
-	mImageDisabledSelected( NULL ),
-	mToggleState( FALSE ),
-	mIsToggle( FALSE ),
-	mScaleImage( TRUE ),
-	mDropShadowedText( TRUE ),
+LLButton::LLButton(const LLButton::Params& p)
+:	LLUICtrl(p),
+	mMouseDownFrame(0),
+	mMouseHeldDownCount(0),
 	mBorderEnabled( FALSE ),
 	mFlashing( FALSE ),
-	mHAlign( LLFontGL::HCENTER ),
-	mLeftHPad( LLBUTTON_H_PAD ), 
-	mRightHPad( LLBUTTON_H_PAD ),
-	mHoverGlowStrength(0.25f),
 	mCurGlowStrength(0.f),
 	mNeedsHighlight(FALSE),
-	mCommitOnReturn(TRUE),
-	mImagep( NULL )
+	mImagep( NULL ),
+	mUnselectedLabel(p.label()),
+	mSelectedLabel(p.label_selected()),
+	mGLFont(p.font),
+	mHeldDownDelay(p.held_down_delay.seconds),			// seconds until held-down callback is called
+	mHeldDownFrameDelay(p.held_down_delay.frames),
+	mImageUnselected(p.image_unselected),
+	mImageSelected(p.image_selected),
+	mImageDisabled(p.image_disabled),
+	mImageDisabledSelected(p.image_disabled_selected),
+	mImageHoverSelected(p.image_hover_selected),
+	mImageHoverUnselected(p.image_hover_unselected),
+	mUnselectedLabelColor(p.label_color()),
+	mSelectedLabelColor(p.label_color_selected()),
+	mDisabledLabelColor(p.label_color_disabled()),
+	mDisabledSelectedLabelColor(p.label_color_disabled_selected()),
+	mHighlightColor(p.highlight_color()),
+	mImageColor(p.image_color()),
+	mFlashBgColor(p.flash_color()),
+	mDisabledImageColor(p.image_color_disabled()),
+	mImageOverlay(p.image_overlay()),
+	mImageOverlayColor(p.image_overlay_color()),
+	mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)),
+	mIsToggle(p.is_toggle),
+	mScaleImage(p.scale_image),
+	mDropShadowedText(p.label_dropshadow),
+	mAutoResize(p.auto_resize),
+	mHAlign(p.font_halign),
+	mLeftHPad(p.pad_left),
+	mRightHPad(p.pad_right),
+	mHoverGlowStrength(p.hover_glow_amount),
+	mCommitOnReturn(p.commit_on_return),
+	mFadeWhenDisabled(FALSE)
 {
-	mUnselectedLabel = unselected_label;
-	mSelectedLabel = selected_label;
+	static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
+	static LLButton::Params default_params(LLUICtrlFactory::getDefaultParams<LLButton::Params>());
 
-	// by default, disabled color is same as enabled
-	mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
-	mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" );
-
-	if( unselected_image_name != "" )
-	{
-		// user-specified image - don't use fixed borders unless requested
-		setImageUnselected(unselected_image_name);
-		setImageDisabled(unselected_image_name);
-		
-		mDisabledImageColor.mV[VALPHA] = 0.5f;
-		mScaleImage = FALSE;
-	}
-	else
+	//if we aren't a picture_style button set label as name if not provided
+	if (!p.picture_style.isProvided() || !p.picture_style)
 	{
-		setImageUnselected(std::string("button_enabled_32x128.tga"));
-		setImageDisabled(std::string("button_disabled_32x128.tga"));
-	}
-
-	if( selected_image_name != "" )
-	{
-		// user-specified image - don't use fixed borders unless requested
-		setImageSelected(selected_image_name);
-		setImageDisabledSelected(selected_image_name);
-
-		mDisabledImageColor.mV[VALPHA] = 0.5f;
-		mScaleImage = FALSE;
-	}
-	else
-	{
-		setImageSelected(std::string("button_enabled_selected_32x128.tga"));
-		setImageDisabledSelected(std::string("button_disabled_32x128.tga"));
+		if (!p.label.isProvided()) 
+		{
+			mUnselectedLabel = p.name();
+		}
+		if (!p.label_selected.isProvided())	
+		{
+			mSelectedLabel = mUnselectedLabel.getString();
+		}
 	}
 
-	init(click_callback, callback_data, font, control_name);
-}
-
-void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name)
-{
-	mGLFont = ( font ? font : LLFontGL::getFontSansSerif());
-
 	// Hack to make sure there is space for at least one character
 	if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" ")))
 	{
 		// Use old defaults
-		mLeftHPad = LLBUTTON_ORIG_H_PAD;
-		mRightHPad = LLBUTTON_ORIG_H_PAD;
+		mLeftHPad = llbutton_orig_h_pad;
+		mRightHPad = llbutton_orig_h_pad;
 	}
 	
-	mCallbackUserData = callback_data;
 	mMouseDownTimer.stop();
 
-	setControlName(control_name, NULL);
-
-	mUnselectedLabelColor = (			LLUI::sColorsGroup->getColor( "ButtonLabelColor" ) );
-	mSelectedLabelColor = (			LLUI::sColorsGroup->getColor( "ButtonLabelSelectedColor" ) );
-	mDisabledLabelColor = (			LLUI::sColorsGroup->getColor( "ButtonLabelDisabledColor" ) );
-	mDisabledSelectedLabelColor = (	LLUI::sColorsGroup->getColor( "ButtonLabelSelectedDisabledColor" ) );
-	mHighlightColor = (				LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) );
-	mUnselectedBgColor = (				LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) );
-	mSelectedBgColor = (				LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) );
-	mFlashBgColor = (				LLUI::sColorsGroup->getColor( "ButtonFlashBgColor" ) );
+	if (p.help_url.isProvided())
+	{
+		setHelpURLCallback(p.help_url);
+	}
 
-	mImageOverlayAlignment = LLFontGL::HCENTER;
-	mImageOverlayColor = LLColor4::white;
-}
+	// if custom unselected button image provided...
+	if (p.image_unselected != default_params.image_unselected)
+	{
+		//...fade it out for disabled image by default...
+		if (p.image_disabled() == default_params.image_disabled() )
+		{
+			mImageDisabled = p.image_unselected;
+			mFadeWhenDisabled = TRUE;
+		}
+	}
 
-LLButton::~LLButton()
-{
- 	if( hasMouseCapture() )
+	// if custom selected button image provided...
+	if (p.image_selected != default_params.image_selected)
 	{
-		gFocusMgr.setMouseCapture( NULL );
+		//...fade it out for disabled image by default...
+		if (p.image_disabled_selected() == default_params.image_disabled_selected())
+		{
+			mImageDisabledSelected = p.image_selected;
+			mFadeWhenDisabled = TRUE;
+		}
 	}
+	
+	if (p.click_callback.isProvided())
+		initCommitCallback(p.click_callback, mCommitSignal); // alias -> commit_callback
+	if (p.mouse_down_callback.isProvided())
+		initCommitCallback(p.mouse_down_callback, mMouseDownSignal);
+	if (p.mouse_up_callback.isProvided())
+		initCommitCallback(p.mouse_up_callback, mMouseUpSignal);
+	if (p.mouse_held_callback.isProvided())
+		initCommitCallback(p.mouse_held_callback, mHeldDownSignal);
 }
 
 // HACK: Committing a button is the same as instantly clicking it.
@@ -229,19 +214,12 @@ LLButton::~LLButton()
 void LLButton::onCommit()
 {
 	// WARNING: Sometimes clicking a button destroys the floater or
-	// panel containing it.  Therefore we need to call mClickedCallback
+	// panel containing it.  Therefore we need to call 	LLUICtrl::onCommit()
 	// LAST, otherwise this becomes deleted memory.
-	LLUICtrl::onCommit();
 
-	if (mMouseDownCallback)
-	{
-		(*mMouseDownCallback)(mCallbackUserData);
-	}
+	mMouseDownSignal(this, LLSD());
 	
-	if (mMouseUpCallback)
-	{
-		(*mMouseUpCallback)(mCallbackUserData);
-	}
+	mMouseUpSignal(this, LLSD());
 
 	if (getSoundFlags() & MOUSE_DOWN)
 	{
@@ -259,14 +237,49 @@ void LLButton::onCommit()
 	}
 
 	// do this last, as it can result in destroying this button
-	if (mClickedCallback)
-	{
-		(*mClickedCallback)( mCallbackUserData );
-	}
+	LLUICtrl::onCommit();
 }
 
+boost::signals::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
+{
+	return mCommitSignal.connect(cb);
+}
+boost::signals::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
+{
+	return mMouseDownSignal.connect(cb);
+}
+boost::signals::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
+{
+	return mMouseUpSignal.connect(cb);
+}
+boost::signals::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
+{
+	return mHeldDownSignal.connect(cb);
+}
 
+// *TODO: Deprecate (for backwards compatability only)
+boost::signals::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
+{
+	return setClickedCallback(boost::bind(cb, data));
+}
+boost::signals::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
+{
+	return setMouseDownCallback(boost::bind(cb, data));
+}
+boost::signals::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
+{
+	return setMouseUpCallback(boost::bind(cb, data));
+}
+boost::signals::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data )
+{
+	return setHeldDownCallback(boost::bind(cb, data));
+}
 
+BOOL LLButton::postBuild()
+{
+	autoResize();
+	return TRUE;
+}
 BOOL LLButton::handleUnicodeCharHere(llwchar uni_char)
 {
 	BOOL handled = FALSE;
@@ -278,10 +291,8 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char)
 			toggleState();
 		}
 
-		if (mClickedCallback)
-		{
-			(*mClickedCallback)( mCallbackUserData );
-		}
+		LLUICtrl::onCommit();
+		
 		handled = TRUE;		
 	}
 	return handled;	
@@ -299,10 +310,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask )
 
 		handled = TRUE;
 
-		if (mClickedCallback)
-		{
-			(*mClickedCallback)( mCallbackUserData );
-		}
+		LLUICtrl::onCommit();
 	}
 	return handled;
 }
@@ -318,13 +326,11 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask)
 		setFocus(TRUE);
 	}
 
-	if (mMouseDownCallback)
-	{
-		(*mMouseDownCallback)(mCallbackUserData);
-	}
+	mMouseDownSignal(this, LLSD());
 
 	mMouseDownTimer.start();
 	mMouseDownFrame = (S32) LLFrameTimer::getFrameCount();
+	mMouseHeldDownCount = 0;
 	
 	if (getSoundFlags() & MOUSE_DOWN)
 	{
@@ -344,13 +350,9 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 		gFocusMgr.setMouseCapture( NULL );
 
 		// Regardless of where mouseup occurs, handle callback
-		if (mMouseUpCallback)
-		{
-			(*mMouseUpCallback)(mCallbackUserData);
-		}
+		mMouseUpSignal(this, LLSD());
 
-		mMouseDownTimer.stop();
-		mMouseDownTimer.reset();
+		resetMouseDownTimer();
 
 		// DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked.
 		// If mouseup in the widget, it's been clicked
@@ -366,10 +368,7 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 				toggleState();
 			}
 
-			if (mClickedCallback)
-			{
-				(*mClickedCallback)( mCallbackUserData );
-			}			
+			LLUICtrl::onCommit();
 		}
 	}
 
@@ -377,20 +376,27 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
 }
 
 
-BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
+void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
 {
-	LLMouseHandler* other_captor = gFocusMgr.getMouseCapture();
-	mNeedsHighlight = other_captor == NULL || 
-				other_captor == this ||
-				// this following bit is to support modal dialogs
-				(other_captor->isView() && hasAncestor((LLView*)other_captor));
+	if (getEnabled())
+		mNeedsHighlight = TRUE;
+}
 
-	if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback)
+void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+	mNeedsHighlight = FALSE;
+}
+
+BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
+{
+	if (mMouseDownTimer.getStarted())
 	{
 		F32 elapsed = getHeldDownTime();
 		if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame)
 		{
-			mHeldDownCallback( mCallbackUserData );		
+			LLSD param;
+			param["count"] = mMouseHeldDownCount++;
+			mHeldDownSignal(this, param);
 		}
 	}
 
@@ -406,12 +412,15 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
 void LLButton::draw()
 {
 	BOOL flash = FALSE;
+	static LLUICachedControl<F32> button_flash_rate("ButtonFlashRate", 0);
+	static LLUICachedControl<S32> button_flash_count("ButtonFlashCount", 0);
+
 	if( mFlashing )
 	{
 		F32 elapsed = mFlashingTimer.getElapsedTimeF32();
-		S32 flash_count = S32(elapsed * LLUI::sConfigGroup->getF32("ButtonFlashRate") * 2.f);
+		S32 flash_count = S32(elapsed * button_flash_rate * 2.f);
 		// flash on or off?
-		flash = (flash_count % 2 == 0) || flash_count > S32((F32)LLUI::sConfigGroup->getS32("ButtonFlashCount") * 2.f);
+		flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f);
 	}
 
 	BOOL pressed_by_keyboard = FALSE;
@@ -427,7 +436,7 @@ void LLButton::draw()
 
 	BOOL pressed = pressed_by_keyboard 
 					|| (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)) 
-					|| mToggleState;
+                    || getToggleState();
 	
 	BOOL use_glow_effect = FALSE;
 	LLColor4 glow_color = LLColor4::white;
@@ -470,12 +479,14 @@ void LLButton::draw()
 
 	if (mFlashing)
 	{
+		LLColor4 flash_color = mFlashBgColor.get();
 		use_glow_effect = TRUE;
 		glow_type = LLRender::BT_ALPHA; // blend the glow
+
 		if (mNeedsHighlight) // highlighted AND flashing
-			glow_color = (glow_color*0.5f + mFlashBgColor*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
+			glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
 		else
-			glow_color = mFlashBgColor;
+			glow_color = flash_color;
 	}
 
 	// Override if more data is available
@@ -508,31 +519,31 @@ void LLButton::draw()
 	// label changes when button state changes, not when pressed
 	if ( getEnabled() )
 	{
-		if ( mToggleState )
+		if ( getToggleState() )
 		{
-			label_color = mSelectedLabelColor;
+			label_color = mSelectedLabelColor.get();
 		}
 		else
 		{
-			label_color = mUnselectedLabelColor;
+			label_color = mUnselectedLabelColor.get();
 		}
 	}
 	else
 	{
-		if ( mToggleState )
+		if ( getToggleState() )
 		{
-			label_color = mDisabledSelectedLabelColor;
+			label_color = mDisabledSelectedLabelColor.get();
 		}
 		else
 		{
-			label_color = mDisabledLabelColor;
+			label_color = mDisabledLabelColor.get();
 		}
 	}
 
 	// Unselected label assignments
 	LLWString label;
 
-	if( mToggleState )
+	if( getToggleState() )
 	{
 		if( getEnabled() || mDisabledSelectedLabel.empty() )
 		{
@@ -578,9 +589,11 @@ void LLButton::draw()
 	// Otherwise draw basic rectangular button.
 	if (mImagep.notNull())
 	{
+		// apply automatic 50% alpha fade to disabled image
+		LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get();
 		if ( mScaleImage)
 		{
-			mImagep->draw(getLocalRect(), getEnabled() ? mImageColor : mDisabledImageColor  );
+			mImagep->draw(getLocalRect(), getEnabled() ? mImageColor.get() : disabled_color  );
 			if (mCurGlowStrength > 0.01f)
 			{
 				gGL.setSceneBlendType(glow_type);
@@ -590,7 +603,7 @@ void LLButton::draw()
 		}
 		else
 		{
-			mImagep->draw(0, 0, getEnabled() ? mImageColor : mDisabledImageColor );
+			mImagep->draw(0, 0, getEnabled() ? mImageColor.get() : disabled_color );
 			if (mCurGlowStrength > 0.01f)
 			{
 				gGL.setSceneBlendType(glow_type);
@@ -634,7 +647,7 @@ void LLButton::draw()
 		}
 
 		// fade out overlay images on disabled buttons
-		LLColor4 overlay_color = mImageOverlayColor;
+		LLColor4 overlay_color = mImageOverlayColor.get();
 		if (!getEnabled())
 		{
 			overlay_color.mV[VALPHA] = 0.5f;
@@ -707,23 +720,18 @@ void LLButton::draw()
 		mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset), 
 			label_color,
 			mHAlign, LLFontGL::BOTTOM,
-			mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL,
+			LLFontGL::NORMAL,
+			mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
 			U32_MAX, text_width,
 			NULL, FALSE, FALSE);
 	}
 
-	if (sDebugRects	
-		|| (LLView::sEditingUI && this == LLView::sEditingUIView))
-	{
-		drawDebugRect();
-	}
-
-	// reset hover status for next frame
-	mNeedsHighlight = FALSE;
+	LLView::draw();
 }
 
 void LLButton::drawBorder(const LLColor4& color, S32 size)
 {
+	if (mImagep.isNull()) return;
 	if (mScaleImage)
 	{
 		mImagep->drawBorder(getLocalRect(), color, size);
@@ -734,22 +742,19 @@ void LLButton::drawBorder(const LLColor4& color, S32 size)
 	}
 }
 
-void LLButton::setClickedCallback(void (*cb)(void*), void* userdata)
+BOOL LLButton::getToggleState() const
 {
-	mClickedCallback = cb;
-	if (userdata)
-	{
-		mCallbackUserData = userdata;
-	}
+    return getValue().asBoolean();
 }
 
-
 void LLButton::setToggleState(BOOL b)
 {
-	if( b != mToggleState )
+	if( b != getToggleState() )
 	{
 		setControlValue(b); // will fire LLControlVariable callbacks (if any)
-		mToggleState = b; // may or may not be redundant
+		setValue(b);        // may or may not be redundant
+		// Unselected label assignments
+		autoResize();
 	}
 }
 
@@ -764,19 +769,11 @@ void LLButton::setFlashing( BOOL b )
 
 
 BOOL LLButton::toggleState()			
-{ 
-	setToggleState( !mToggleState ); 
-	return mToggleState; 
-}
-
-void LLButton::setValue(const LLSD& value )
 {
-	mToggleState = value.asBoolean();
-}
+    bool flipped = ! getToggleState();
+	setToggleState(flipped); 
 
-LLSD LLButton::getValue() const
-{
-	return mToggleState == TRUE;
+	return flipped; 
 }
 
 void LLButton::setLabel( const LLStringExplicit& label )
@@ -818,6 +815,49 @@ void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
 	mImageUnselected = image;
 }
 
+void LLButton::autoResize()
+{
+	LLUIString label;
+	if(getToggleState())
+	{
+		if( getEnabled() || mDisabledSelectedLabel.empty() )
+		{
+			label = mSelectedLabel;
+		}
+		else
+		{
+			label = mDisabledSelectedLabel;
+		}
+	}
+	else
+	{
+		if( getEnabled() || mDisabledLabel.empty() )
+		{
+			label = mUnselectedLabel;
+		}
+		else
+		{
+			label = mDisabledLabel;
+		}
+	}
+	resize(label);
+}
+
+void LLButton::resize(LLUIString label)
+{
+	// get label length 
+	S32 label_width = mGLFont->getWidth(label.getString());
+	// get current btn length 
+	S32 btn_width =getRect().getWidth();
+    // check if it need resize 
+	if (mAutoResize == TRUE)
+	{ 
+		if (btn_width - (mRightHPad + mLeftHPad) < label_width)
+		{
+			setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight+ label_width + mLeftHPad + mRightHPad , getRect().mBottom));
+		}
+	} 
+}
 void LLButton::setImages( const std::string &image_name, const std::string &selected_name )
 {
 	setImageUnselected(image_name);
@@ -845,14 +885,20 @@ void LLButton::setImageDisabled(LLPointer<LLUIImage> image)
 {
 	mImageDisabled = image;
 	mDisabledImageColor = mImageColor;
-	mDisabledImageColor.mV[VALPHA] *= 0.5f;
+	mFadeWhenDisabled = TRUE;
 }
 
 void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
 {
 	mImageDisabledSelected = image;
 	mDisabledImageColor = mImageColor;
-	mDisabledImageColor.mV[VALPHA] *= 0.5f;
+	mFadeWhenDisabled = TRUE;
+}
+
+void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name)
+{
+	setDisabledImages( image_name, selected_name, mImageColor.get());
+	mFadeWhenDisabled = TRUE;
 }
 
 void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name, const LLColor4& c )
@@ -867,13 +913,6 @@ void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image)
 	mImageHoverSelected = image;
 }
 
-void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name)
-{
-	LLColor4 clr = mImageColor;
-	clr.mV[VALPHA] *= .5f;
-	setDisabledImages( image_name, selected_name, clr );
-}
-
 void LLButton::setImageHoverUnselected(LLPointer<LLUIImage> image)
 {
 	mImageHoverUnselected = image;
@@ -899,11 +938,9 @@ void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign a
 	}
 }
 
-
 void LLButton::onMouseCaptureLost()
 {
-	mMouseDownTimer.stop();
-	mMouseDownTimer.reset();
+	resetMouseDownTimer();
 }
 
 //-------------------------------------------------------------------------
@@ -975,28 +1012,6 @@ void LLButton::addImageAttributeToXML(LLXMLNodePtr node,
 	}
 }
 
-// virtual
-LLXMLNodePtr LLButton::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("label", TRUE)->setStringValue(getLabelUnselected());
-	node->createChild("label_selected", TRUE)->setStringValue(getLabelSelected());
-	node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont));
-	node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
-
-	addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,std::string("image_unselected"));
-	addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,std::string("image_selected"));
-	addImageAttributeToXML(node,mImageHoverSelectedName,mImageHoverSelectedID,std::string("image_hover_selected"));
-	addImageAttributeToXML(node,mImageHoverUnselectedName,mImageHoverUnselectedID,std::string("image_hover_unselected"));
-	addImageAttributeToXML(node,mImageDisabledName,mImageDisabledID,std::string("image_disabled"));
-	addImageAttributeToXML(node,mImageDisabledSelectedName,mImageDisabledSelectedID,std::string("image_disabled_selected"));
-
-	node->createChild("scale_image", TRUE)->setBoolValue(mScaleImage);
-
-	return node;
-}
-
 void clicked_help(void* data)
 {
 	LLButton* self = (LLButton*)data;
@@ -1010,114 +1025,53 @@ void clicked_help(void* data)
 	LLUI::sHtmlHelp->show(self->getHelpURL());
 }
 
-// static
-LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+void LLButton::setHelpURLCallback(const std::string &help_url)
 {
-	std::string name("button");
-	node->getAttributeString("name", name);
-
-	std::string label = name;
-	node->getAttributeString("label", label);
-
-	std::string label_selected = label;
-	node->getAttributeString("label_selected", label_selected);
-
-	LLFontGL* font = selectFont(node);
-
-	std::string	image_unselected;
-	if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected);
-	
-	std::string	image_selected;
-	if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected);
-	
-	std::string	image_hover_selected;
-	if (node->hasAttribute("image_hover_selected")) node->getAttributeString("image_hover_selected",image_hover_selected);
-	
-	std::string	image_hover_unselected;
-	if (node->hasAttribute("image_hover_unselected")) node->getAttributeString("image_hover_unselected",image_hover_unselected);
-	
-	std::string	image_disabled_selected;
-	if (node->hasAttribute("image_disabled_selected")) node->getAttributeString("image_disabled_selected",image_disabled_selected);
-	
-	std::string	image_disabled;
-	if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled);
-
-	std::string	image_overlay;
-	node->getAttributeString("image_overlay", image_overlay);
-
-	LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER;
-	std::string image_overlay_alignment_string;
-	if (node->hasAttribute("image_overlay_alignment"))
-	{
-		node->getAttributeString("image_overlay_alignment", image_overlay_alignment_string);
-		image_overlay_alignment = LLFontGL::hAlignFromName(image_overlay_alignment_string);
-	}
-
-
-	LLButton *button = new LLButton(name, 
-			LLRect(),
-			image_unselected,
-			image_selected,
-			LLStringUtil::null, 
-			NULL, 
-			parent,
-			font,
-			label,
-			label_selected);
-
-	node->getAttributeS32("pad_right", button->mRightHPad);
-	node->getAttributeS32("pad_left", button->mLeftHPad);
+	mHelpURL = help_url;
+	setClickedCallback(clicked_help,this);
+}
 
-	BOOL is_toggle = button->getIsToggle();
-	node->getAttributeBOOL("toggle", is_toggle);
-	button->setIsToggle(is_toggle);
+// static
+void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname)
+{
+	bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString());
+	LLButton* button = dynamic_cast<LLButton*>(ctrl);
+	if (button)
+		button->setToggleState(floater_vis);
+}
 
-	if(image_hover_selected != LLStringUtil::null) button->setImageHoverSelected(image_hover_selected);
-	
-	if(image_hover_unselected != LLStringUtil::null) button->setImageHoverUnselected(image_hover_unselected);
-	
-	if(image_disabled_selected != LLStringUtil::null) button->setImageDisabledSelected(image_disabled_selected );
-	
-	if(image_disabled != LLStringUtil::null) button->setImageDisabled(image_disabled);
-	
-	if(image_overlay != LLStringUtil::null) button->setImageOverlay(image_overlay, image_overlay_alignment);
+// static
+// Gets called once
+void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname)
+{
+	LLButton* button = dynamic_cast<LLButton*>(ctrl);
+	if (!button)
+		return;
+	// Get the visibility control name for the floater
+	std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
+	// Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
+	button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
+	// Set the clicked callback to toggle the floater
+	button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname));
+}
 
-	if (node->hasAttribute("halign"))
-	{
-		LLFontGL::HAlign halign = selectFontHAlign(node);
-		button->setHAlign(halign);
-	}
+void LLButton::resetMouseDownTimer()
+{
+	mMouseDownTimer.stop();
+	mMouseDownTimer.reset();
+}
 
-	if (node->hasAttribute("scale_image"))
-	{
-		BOOL	needsScale = FALSE;
-		node->getAttributeBOOL("scale_image",needsScale);
-		button->setScaleImage( needsScale );
-	}
 
-	if(label.empty())
-	{
-		button->setLabelUnselected(node->getTextContents());
-	}
-	if (label_selected.empty())
-	{
-		button->setLabelSelected(node->getTextContents());
-	}
-		
-	if (node->hasAttribute("help_url")) 
+// *TODO: Remove this function after the initial XUI XML re-export pass.
+// static
+void LLButton::setupParamsForExport(Params& p, LLView* parent)
+{
+	std::string label = p.label;
+	if (label.empty())
 	{
-		std::string	help_url;
-		node->getAttributeString("help_url",help_url);
-		button->setHelpURLCallback(help_url);
+		//if our label is empty this is a picture style button
+		p.picture_style = true;
 	}
 
-	button->initFromXML(node, parent);
-	
-	return button;
-}
-
-void LLButton::setHelpURLCallback(const std::string &help_url)
-{
-	mHelpURL = help_url;
-	setClickedCallback(clicked_help,this);
+	LLUICtrl::setupParamsForExport(p, parent);
 }
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 724b77541a..f146ef9dc2 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -39,7 +39,7 @@
 #include "v4color.h"
 #include "llframetimer.h"
 #include "llfontgl.h"
-#include "llimage.h"
+#include "lluiimage.h"
 #include "lluistring.h"
 
 //
@@ -53,9 +53,6 @@ extern S32	LLBUTTON_V_PAD;
 extern S32	BTN_HEIGHT_SMALL;
 extern S32	BTN_HEIGHT;
 
-// All button widths should be rounded up to this size
-extern S32	BTN_GRID;
-
 //
 // Helpful functions
 //
@@ -72,36 +69,80 @@ class LLButton
 : public LLUICtrl
 {
 public:
-	// simple button with text label
-	LLButton(const std::string& name, const LLRect &rect, const std::string& control_name = std::string(), 
-			 void (*on_click)(void*) = NULL, void *data = NULL);
-
-	LLButton(const std::string& name, const LLRect& rect, 
-			 const std::string &unselected_image,
-			 const std::string &selected_image,
-			 const std::string& control_name,	
-			 void (*click_callback)(void*),
-			 void *callback_data = NULL,
-			 const LLFontGL* mGLFont = NULL,
-			 const std::string& unselected_label = LLStringUtil::null,
-			 const std::string& selected_label = LLStringUtil::null );
-
-	virtual ~LLButton();
-	void init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name);
-
+	struct Params 
+	:	public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		// text label
+		Optional<std::string>	label_selected;
+		Optional<bool>			label_dropshadow;
+		Optional<bool>			auto_resize;
+
+		// images
+		Optional<LLUIImage*>	image_unselected,
+								image_selected,
+								image_hover_selected,
+								image_hover_unselected,
+								image_disabled_selected,
+								image_disabled,
+								image_overlay;
+
+		Optional<std::string>	image_overlay_alignment;
+		
+		// colors
+		Optional<LLUIColor>		label_color,
+								label_color_selected,
+								label_color_disabled,
+								label_color_disabled_selected,
+								highlight_color,
+								image_color,
+								image_color_disabled,
+								image_overlay_color,
+								flash_color;
+
+		// layout
+		Optional<S32>			pad_right;
+		Optional<S32>			pad_left;
+		
+		// callbacks
+		Optional<CommitCallbackParam>	click_callback, // alias -> commit_callback
+															mouse_down_callback,
+															mouse_up_callback,
+															mouse_held_callback,
+															mouse_held_once_callback;
+		
+		// misc
+		Optional<bool>			is_toggle,
+								scale_image,
+								commit_on_return,
+								picture_style;      //if true, don't display label
+		
+		Optional<std::string>		help_url;
+		Optional<F32>				hover_glow_amount;
+		Optional<TimeIntervalParam>	held_down_delay;
+
+		Params();
+	};
 	
+protected:
+	friend class LLUICtrlFactory;
+	LLButton(const Params&);
+
+public:
+	// For backward compatability only
+	typedef boost::function<void(void*)> button_callback_t;
+
 	void			addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName,
 										const LLUUID&	imageID,const std::string&	xmlTagName) const;
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 	virtual BOOL	handleKeyHere(KEY key, MASK mask);
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual void	draw();
+	/*virtual*/ BOOL postBuild();
 
+	virtual void	onMouseEnter(S32 x, S32 y, MASK mask);
+	virtual void	onMouseLeave(S32 x, S32 y, MASK mask);
 	virtual void	onMouseCaptureLost();
 
 	virtual void	onCommit();
@@ -109,18 +150,24 @@ public:
 	void			setUnselectedLabelColor( const LLColor4& c )		{ mUnselectedLabelColor = c; }
 	void			setSelectedLabelColor( const LLColor4& c )			{ mSelectedLabelColor = c; }
 
-	void			setClickedCallback( void (*cb)(void *data), void* data = NULL ); // mouse down and up within button
-	void			setMouseDownCallback( void (*cb)(void *data) )		{ mMouseDownCallback = cb; }	// mouse down within button
-	void			setMouseUpCallback( void (*cb)(void *data) )		{ mMouseUpCallback = cb; }		// mouse up, EVEN IF NOT IN BUTTON
-	void			setHeldDownCallback( void (*cb)(void *data) )		{ mHeldDownCallback = cb; }		// Mouse button held down and in button
+	boost::signals::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button
+	boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
+	boost::signals::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON
+	// Passes a 'count' parameter in the commit param payload, i.e. param["count"])
+	boost::signals::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button
+	
+	// *TODO: Deprecate (for backwards compatability only)
+	boost::signals::connection setClickedCallback( button_callback_t cb, void* data );
+	boost::signals::connection setMouseDownCallback( button_callback_t cb, void* data );
+	boost::signals::connection setMouseUpCallback( button_callback_t cb, void* data );
+	boost::signals::connection setHeldDownCallback( button_callback_t cb, void* data );
+		
 	void			setHeldDownDelay( F32 seconds, S32 frames = 0)		{ mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; }
-
+	
 	F32				getHeldDownTime() const								{ return mMouseDownTimer.getElapsedTimeF32(); }
 
-	BOOL			getIsToggle() const { return mIsToggle; }
-	void			setIsToggle(BOOL is_toggle) { mIsToggle = is_toggle; }
 	BOOL			toggleState();
-	BOOL			getToggleState() const	{ return mToggleState; }
+	BOOL			getToggleState() const;
 	void			setToggleState(BOOL b);
 
 	void			setFlashing( BOOL b );
@@ -150,11 +197,9 @@ public:
 
 	void			setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
 	LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; }
-	
-
-	virtual void	setValue(const LLSD& value );
-	virtual LLSD	getValue() const;
 
+	void            autoResize();	// resize with label of current btn state 
+	void            resize(LLUIString label); // resize with label input
 	void			setLabel( const LLStringExplicit& label);
 	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
 	void			setLabelUnselected(const LLStringExplicit& label);
@@ -172,8 +217,6 @@ public:
 
 	void			setBorderEnabled(BOOL b)					{ mBorderEnabled = b; }
 
-	static void		onHeldDown(void *userdata);  // to be called by gIdleCallbacks
-
 	void			setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
 
 	void			setImageUnselected(const std::string &image_name);
@@ -198,6 +241,10 @@ public:
 	void			setHelpURLCallback(const std::string &help_url);
 	const std::string&	getHelpURL() const { return mHelpURL; }
 
+	static void		onHeldDown(void *userdata);  // to be called by gIdleCallbacks
+	static void		toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname);
+	static void		setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
+	
 protected:
 
 	virtual void	drawBorder(const LLColor4& color, S32 size);
@@ -212,45 +259,48 @@ protected:
 	void			setImageDisabledSelectedID(const LLUUID &image_id);
 	const LLPointer<LLUIImage>&	getImageUnselected() const	{ return mImageUnselected; }
 	const LLPointer<LLUIImage>& getImageSelected() const	{ return mImageSelected; }
+	void			resetMouseDownTimer();
 
 	LLFrameTimer	mMouseDownTimer;
 
-private:
-
-	void			(*mClickedCallback)(void* data );
-	void			(*mMouseDownCallback)(void *data);
-	void			(*mMouseUpCallback)(void *data);
-	void			(*mHeldDownCallback)(void *data);
+	// If the label is empty, set the picture_style attribute
+	static void setupParamsForExport(Params& p, LLView* parent);
 
+private:
+	commit_signal_t mMouseDownSignal;
+	commit_signal_t mMouseUpSignal;
+	commit_signal_t mHeldDownSignal;
+	
 	const LLFontGL	*mGLFont;
 	
 	S32				mMouseDownFrame;
-	F32				mHeldDownDelay;		// seconds, after which held-down callbacks get called
+	S32 			mMouseHeldDownCount; 	// Counter for parameter passed to held-down callback
+	F32				mHeldDownDelay;			// seconds, after which held-down callbacks get called
 	S32				mHeldDownFrameDelay;	// frames, after which held-down callbacks get called
 
-	LLPointer<LLUIImage>	mImageOverlay;
-	LLFontGL::HAlign		mImageOverlayAlignment;
-	LLColor4				mImageOverlayColor;
+	LLPointer<LLUIImage>		mImageOverlay;
+	LLFontGL::HAlign			mImageOverlayAlignment;
+	LLUIColor	mImageOverlayColor;
 
-	LLPointer<LLUIImage>	mImageUnselected;
-	LLUIString				mUnselectedLabel;
-	LLColor4				mUnselectedLabelColor;
+	LLPointer<LLUIImage>		mImageUnselected;
+	LLUIString					mUnselectedLabel;
+	LLUIColor	mUnselectedLabelColor;
 
-	LLPointer<LLUIImage>	mImageSelected;
-	LLUIString				mSelectedLabel;
-	LLColor4				mSelectedLabelColor;
+	LLPointer<LLUIImage>		mImageSelected;
+	LLUIString					mSelectedLabel;
+	LLUIColor	mSelectedLabelColor;
 
-	LLPointer<LLUIImage>	mImageHoverSelected;
+	LLPointer<LLUIImage>		mImageHoverSelected;
 
-	LLPointer<LLUIImage>	mImageHoverUnselected;
+	LLPointer<LLUIImage>		mImageHoverUnselected;
 
-	LLPointer<LLUIImage>	mImageDisabled;
-	LLUIString				mDisabledLabel;
-	LLColor4				mDisabledLabelColor;
+	LLPointer<LLUIImage>		mImageDisabled;
+	LLUIString					mDisabledLabel;
+	LLUIColor	mDisabledLabelColor;
 
-	LLPointer<LLUIImage>	mImageDisabledSelected;
-	LLUIString				mDisabledSelectedLabel;
-	LLColor4				mDisabledSelectedLabelColor;
+	LLPointer<LLUIImage>		mImageDisabledSelected;
+	LLUIString					mDisabledSelectedLabel;
+	LLUIColor	mDisabledSelectedLabelColor;
 
 	LLUUID			mImageUnselectedID;
 	LLUUID			mImageSelectedID;
@@ -265,20 +315,17 @@ private:
 	std::string		mImageDisabledName;
 	std::string		mImageDisabledSelectedName;
 
-	LLColor4		mHighlightColor;
-	LLColor4		mUnselectedBgColor;
-	LLColor4		mSelectedBgColor;
-	LLColor4		mFlashBgColor;
+	LLUIColor	mHighlightColor;
+	LLUIColor		mFlashBgColor;
 
-	LLColor4		mImageColor;
-	LLColor4		mDisabledImageColor;
+	LLUIColor	mImageColor;
+	LLUIColor	mDisabledImageColor;
 
 	BOOL			mIsToggle;
-	BOOL			mToggleState;
 	BOOL			mScaleImage;
 
 	BOOL			mDropShadowedText;
-
+	BOOL			mAutoResize;
 	BOOL			mBorderEnabled;
 
 	BOOL			mFlashing;
@@ -292,6 +339,7 @@ private:
 
 	BOOL			mNeedsHighlight;
 	BOOL			mCommitOnReturn;
+	BOOL			mFadeWhenDisabled;
 
 	std::string		mHelpURL;
 
@@ -300,4 +348,11 @@ private:
 	LLFrameTimer	mFlashingTimer;
 };
 
+#ifdef LL_WINDOWS
+#ifndef INSTANTIATE_GETCHILD_BUTTON
+#pragma warning (disable : 4231)
+extern template LLButton* LLView::getChild<LLButton>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+#endif
+#endif
+
 #endif  // LL_LLBUTTON_H
diff --git a/indra/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h
index eadb9c98f3..97b1e2fc50 100644
--- a/indra/llui/llcallbackmap.h
+++ b/indra/llui/llcallbackmap.h
@@ -30,11 +30,11 @@
  * $/LicenseInfo$
  */
 
-#ifndef LL_CALLBACK_MAP_H
-#define LL_CALLBACK_MAP_H
+#ifndef LLCALLBACKMAP_H
+#define LLCALLBACKMAP_H
 
 #include <map>
-#include "llstring.h"
+#include <string>
 
 class LLCallbackMap
 {
@@ -45,12 +45,19 @@ public:
 	typedef std::map<std::string, LLCallbackMap> map_t;
 	typedef map_t::iterator map_iter_t;
 	typedef map_t::const_iterator map_const_iter_t;
-
+	
+	template <class T>
+	static void* buildPanel(void* data)
+	{
+		T* panel = new T();
+		return (void*)panel;
+	}
+	
 	LLCallbackMap() : mCallback(NULL), mData(NULL) { }
-	LLCallbackMap(callback_t callback, void* data) : mCallback(callback), mData(data) { }
+	LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { }
 
 	callback_t	mCallback;
 	void*		mData;
 };
 
-#endif // LL_CALLBACK_MAP_H
+#endif // LLCALLBACKMAP_H
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index eda9467d87..7b37344db7 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -31,6 +31,7 @@
  */
 
 // The mutants are coming!
+#define INSTANTIATE_GETCHILD_CHECKBOX
 
 #include "linden_common.h"
 
@@ -49,101 +50,88 @@
 
 const U32 MAX_STRING_LENGTH = 10;
 
+template LLCheckBoxCtrl* LLView::getChild<LLCheckBoxCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+
 static LLRegisterWidget<LLCheckBoxCtrl> r("check_box");
 
- 
-LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect, 
-							    const std::string& label, 
-								const LLFontGL* font,
-								void (*commit_callback)(LLUICtrl* ctrl, void* userdata),
-								void* callback_user_data,
-								BOOL initial_value,
-								BOOL use_radio_style,
-								const std::string& control_which)
-:	LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data, FOLLOWS_LEFT | FOLLOWS_TOP),
-	mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
-	mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
-	mRadioStyle( use_radio_style ),
-	mInitialValue( initial_value ),
-	mSetValue( initial_value )
+LLCheckBoxCtrl::Params::Params()
+:	text_enabled_color("text_enabled_color"),
+	text_disabled_color("text_disabled_color"),
+	initial_value("initial_value", false),
+	label_text("label_text"),
+	check_button("check_button"),
+	radio_style("radio_style")
+{}
+
+
+LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
+:	LLUICtrl(p),
+	mTextEnabledColor(p.text_enabled_color()),
+	mTextDisabledColor(p.text_disabled_color()),
+	mFont(p.font())
 {
-	if (font)
-	{
-		mFont = font;
-	}
-	else
-	{
-		mFont = LLFontGL::getFontSansSerifSmall();
-	}
+	mViewModel->setValue(LLSD(p.initial_value));
+	mViewModel->resetDirty();
+	static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0);
+	static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0);
+	static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0);
+	static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0);
 
 	// must be big enough to hold all children
 	setUseBoundingRect(TRUE);
 
-	mKeyboardFocusOnClick = TRUE;
-
 	// Label (add a little space to make sure text actually renders)
 	const S32 FUDGE = 10;
-	S32 text_width = mFont->getWidth( label ) + FUDGE;
+	S32 text_width = mFont->getWidth( p.label ) + FUDGE;
 	S32 text_height = llround(mFont->getLineHeight());
 	LLRect label_rect;
 	label_rect.setOriginAndSize(
-		LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING,
-		LLCHECKBOXCTRL_VPAD + 1, // padding to get better alignment
-		text_width + LLCHECKBOXCTRL_HPAD,
+		llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing,
+		llcheckboxctrl_vpad + 1, // padding to get better alignment
+		text_width + llcheckboxctrl_hpad,
 		text_height );
 
 	// *HACK Get rid of this with SL-55508... 
 	// this allows blank check boxes and radio boxes for now
-	std::string local_label = label;
+	std::string local_label = p.label;
 	if(local_label.empty())
 	{
 		local_label = " ";
 	}
 
-	mLabel = new LLTextBox( std::string("CheckboxCtrl Label"), label_rect, local_label, mFont );
-	mLabel->setFollowsLeft();
-	mLabel->setFollowsBottom();
+	LLTextBox::Params tbparams = p.label_text;
+	tbparams.rect(label_rect);
+	tbparams.text(local_label);
+	if (p.font.isProvided())
+	{
+		tbparams.font(p.font);
+	}
+	mLabel = LLUICtrlFactory::create<LLTextBox> (tbparams);
+
 	addChild(mLabel);
 
 	// Button
 	// Note: button cover the label by extending all the way to the right.
 	LLRect btn_rect;
 	btn_rect.setOriginAndSize(
-		LLCHECKBOXCTRL_HPAD,
-		LLCHECKBOXCTRL_VPAD,
-		LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING + text_width + LLCHECKBOXCTRL_HPAD,
-		llmax( text_height, LLCHECKBOXCTRL_BTN_SIZE ) + LLCHECKBOXCTRL_VPAD);
+		llcheckboxctrl_hpad,
+		llcheckboxctrl_vpad,
+		llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width + llcheckboxctrl_hpad,
+		llmax( text_height, llcheckboxctrl_btn_size() ) + llcheckboxctrl_vpad);
 	std::string active_true_id, active_false_id;
 	std::string inactive_true_id, inactive_false_id;
-	if (mRadioStyle)
-	{
-		active_true_id = "UIImgRadioActiveSelectedUUID";
-		active_false_id = "UIImgRadioActiveUUID";
-		inactive_true_id = "UIImgRadioInactiveSelectedUUID";
-		inactive_false_id = "UIImgRadioInactiveUUID";
-		mButton = new LLButton(std::string("Radio control button"), btn_rect,
-							   active_false_id, active_true_id, control_which,
-							   &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); 
-		mButton->setDisabledImages( inactive_false_id, inactive_true_id );
-		mButton->setHoverGlowStrength(0.35f);
-	}
-	else
-	{
-		active_false_id = "UIImgCheckboxActiveUUID";
-		active_true_id = "UIImgCheckboxActiveSelectedUUID";
-		inactive_true_id = "UIImgCheckboxInactiveSelectedUUID";
-		inactive_false_id = "UIImgCheckboxInactiveUUID";
-		mButton = new LLButton(std::string("Checkbox control button"), btn_rect,
-							   active_false_id, active_true_id, control_which,
-							   &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); 
-		mButton->setDisabledImages( inactive_false_id, inactive_true_id );
-		mButton->setHoverGlowStrength(0.35f);
-	}
-	mButton->setIsToggle(TRUE);
-	mButton->setToggleState( initial_value );
-	mButton->setFollowsLeft();
-	mButton->setFollowsBottom();
-	mButton->setCommitOnReturn(FALSE);
+
+	LLButton::Params params = p.check_button;
+	params.rect(btn_rect);
+	//params.control_name(p.control_name);
+	params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onButtonPress, this, _2));
+	params.commit_on_return(false);
+	// Checkboxes only allow boolean initial values, but buttons can
+	// take any LLSD.
+	params.initial_value(LLSD(p.initial_value));
+	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+
+	mButton = LLUICtrlFactory::create<LLButton>(params);
 	addChild(mButton);
 }
 
@@ -154,24 +142,14 @@ LLCheckBoxCtrl::~LLCheckBoxCtrl()
 
 
 // static
-void LLCheckBoxCtrl::onButtonPress( void *userdata )
+void LLCheckBoxCtrl::onButtonPress( const LLSD& data )
 {
-	LLCheckBoxCtrl* self = (LLCheckBoxCtrl*) userdata;
+	//if (mRadioStyle)
+	//{
+	//	setValue(TRUE);
+	//}
 
-	if (self->mRadioStyle)
-	{
-		self->setValue(TRUE);
-	}
-
-	self->setControlValue(self->getValue());
-	// HACK: because buttons don't normally commit
-	self->onCommit();
-
-	if (self->mKeyboardFocusOnClick)
-	{
-		self->setFocus( TRUE );
-		self->onFocusReceived();
-	}
+	onCommit();
 }
 
 void LLCheckBoxCtrl::onCommit()
@@ -179,6 +157,7 @@ void LLCheckBoxCtrl::onCommit()
 	if( getEnabled() )
 	{
 		setTentative(FALSE);
+		setControlValue(getValue());
 		LLUICtrl::onCommit();
 	}
 }
@@ -187,6 +166,15 @@ void LLCheckBoxCtrl::setEnabled(BOOL b)
 {
 	LLView::setEnabled(b);
 	mButton->setEnabled(b);
+
+	if (b)
+	{
+		mLabel->setColor( mTextEnabledColor.get() );
+	}
+	else
+	{
+		mLabel->setColor( mTextDisabledColor.get() );
+	}
 }
 
 void LLCheckBoxCtrl::clear()
@@ -197,43 +185,33 @@ void LLCheckBoxCtrl::clear()
 void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
 	//stretch or shrink bounding rectangle of label when rebuilding UI at new scale
+	static LLUICachedControl<S32> llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0);
+	static LLUICachedControl<S32> llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0);
+	static LLUICachedControl<S32> llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0);
+	static LLUICachedControl<S32> llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0);
+
 	const S32 FUDGE = 10;
 	S32 text_width = mFont->getWidth( mLabel->getText() ) + FUDGE;
 	S32 text_height = llround(mFont->getLineHeight());
 	LLRect label_rect;
 	label_rect.setOriginAndSize(
-		LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING,
-		LLCHECKBOXCTRL_VPAD,
+		llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing,
+		llcheckboxctrl_vpad,
 		text_width,
 		text_height );
 	mLabel->setRect(label_rect);
 
 	LLRect btn_rect;
 	btn_rect.setOriginAndSize(
-		LLCHECKBOXCTRL_HPAD,
-		LLCHECKBOXCTRL_VPAD,
-		LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING + text_width,
-		llmax( text_height, LLCHECKBOXCTRL_BTN_SIZE ) );
+		llcheckboxctrl_hpad,
+		llcheckboxctrl_vpad,
+		llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width,
+		llmax( text_height, llcheckboxctrl_btn_size() ) );
 	mButton->setRect( btn_rect );
 	
 	LLUICtrl::reshape(width, height, called_from_parent);
 }
 
-void LLCheckBoxCtrl::draw()
-{
-	if (getEnabled())
-	{
-		mLabel->setColor( mTextEnabledColor );
-	}
-	else
-	{
-		mLabel->setColor( mTextDisabledColor );
-	}
-
-	// Draw children
-	LLUICtrl::draw();
-}
-
 //virtual
 void LLCheckBoxCtrl::setValue(const LLSD& value )
 {
@@ -246,6 +224,18 @@ LLSD LLCheckBoxCtrl::getValue() const
 	return mButton->getValue();
 }
 
+//virtual
+void LLCheckBoxCtrl::setTentative(BOOL b)
+{
+	mButton->setTentative(b);
+}
+
+//virtual
+BOOL LLCheckBoxCtrl::getTentative() const
+{
+	return mButton->getTentative();
+}
+
 void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label )
 {
 	mLabel->setText( label );
@@ -264,12 +254,6 @@ BOOL LLCheckBoxCtrl::setLabelArg( const std::string& key, const LLStringExplicit
 	return res;
 }
 
-//virtual
-std::string LLCheckBoxCtrl::getControlName() const
-{
-	return mButton->getControlName();
-}
-
 // virtual
 void LLCheckBoxCtrl::setControlName(const std::string& control_name, LLView* context)
 {
@@ -282,7 +266,7 @@ BOOL	 LLCheckBoxCtrl::isDirty() const
 {
 	if ( mButton )
 	{
-		return (mSetValue != mButton->getToggleState());
+		return mButton->isDirty();
 	}
 	return FALSE;		// Shouldn't get here
 }
@@ -293,78 +277,6 @@ void	LLCheckBoxCtrl::resetDirty()
 {
 	if ( mButton )
 	{
-		mSetValue = mButton->getToggleState();
-	}
-}
-
-
-
-// virtual
-LLXMLNodePtr LLCheckBoxCtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("label", TRUE)->setStringValue(mLabel->getText());
-
-	std::string control_name = mButton->getControlName();
-	
-	node->createChild("initial_value", TRUE)->setBoolValue(mInitialValue);
-
-	node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mFont));
-
-	node->createChild("radio_style", TRUE)->setBoolValue(mRadioStyle);
-
-	return node;
-}
-
-// static
-LLView* LLCheckBoxCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("checkbox");
-	node->getAttributeString("name", name);
-
-	std::string label("");
-	node->getAttributeString("label", label);
-
-	LLFontGL* font = LLView::selectFont(node);
-
-	BOOL radio_style = FALSE;
-	node->getAttributeBOOL("radio_style", radio_style);
-
-	LLUICtrlCallback callback = NULL;
-
-	if (label.empty())
-	{
-		label.assign(node->getTextContents());
+		mButton->resetDirty();
 	}
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	LLCheckBoxCtrl* checkbox = new LLCheckboxCtrl(name, 
-		rect, 
-		label,
-		font,
-		callback,
-		NULL,
-		FALSE,
-		radio_style); // if true, draw radio button style icons
-
-	BOOL initial_value = checkbox->getValue().asBoolean();
-	node->getAttributeBOOL("initial_value", initial_value);
-
-	LLColor4 color;
-	color = LLUI::sColorsGroup->getColor( "LabelTextColor" );
-	LLUICtrlFactory::getAttributeColor(node,"text_enabled_color", color);
-	checkbox->setEnabledColor(color);
-
-	color = LLUI::sColorsGroup->getColor( "LabelDisabledColor" );
-	LLUICtrlFactory::getAttributeColor(node,"text_disabled_color", color);
-	checkbox->setDisabledColor(color);
-
-	checkbox->setValue(initial_value);
-
-	checkbox->initFromXML(node, parent);
-
-	return checkbox;
 }
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index ff867f5193..fe719e3b6a 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -33,24 +33,14 @@
 #ifndef LL_LLCHECKBOXCTRL_H
 #define LL_LLCHECKBOXCTRL_H
 
-
-#include "stdtypes.h"
 #include "lluictrl.h"
 #include "llbutton.h"
+#include "lltextbox.h"
 #include "v4color.h"
-#include "llrect.h"
 
 //
 // Constants
 //
-const S32 LLCHECKBOXCTRL_BTN_SIZE = 13;
-const S32 LLCHECKBOXCTRL_VPAD = 2;
-const S32 LLCHECKBOXCTRL_HPAD = 2;
-const S32 LLCHECKBOXCTRL_SPACING = 5;
-const S32 LLCHECKBOXCTRL_HEIGHT = 16;
-
-// Deprecated, don't use.
-#define CHECKBOXCTRL_HEIGHT LLCHECKBOXCTRL_HEIGHT
 
 const BOOL	RADIO_STYLE = TRUE;
 const BOOL	CHECK_STYLE = FALSE;
@@ -59,30 +49,38 @@ const BOOL	CHECK_STYLE = FALSE;
 // Classes
 //
 class LLFontGL;
-class LLTextBox;
 class LLViewBorder;
 
 class LLCheckBoxCtrl
 : public LLUICtrl
 {
 public:
-	LLCheckBoxCtrl(const std::string& name, const LLRect& rect, const std::string& label,	
-		const LLFontGL* font = NULL,
-		void (*commit_callback)(LLUICtrl*, void*) = NULL,
-		void* callback_userdata = NULL,
-		BOOL initial_value = FALSE,
-		BOOL use_radio_style = FALSE, // if true, draw radio button style icons
-		const std::string& control_which = LLStringUtil::null);
+	struct Params 
+	:	public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<LLUIColor>		text_enabled_color;
+		Optional<LLUIColor>		text_disabled_color;
+		Optional<bool>			initial_value;	// override LLUICtrl initial_value
+
+		Optional<LLTextBox::Params> label_text;
+		Optional<LLButton::Params> check_button;
+
+		Deprecated	radio_style;
+
+		Params();
+	};
+
 	virtual ~LLCheckBoxCtrl();
 
-	// LLView interface
+protected:
+	LLCheckBoxCtrl(const Params&);
+	friend class LLUICtrlFactory;
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+public:
+	// LLView interface
 
 	virtual void		setEnabled( BOOL b );
 
-	virtual void		draw();
 	virtual void		reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
 	// LLUICtrl interface
@@ -91,8 +89,8 @@ public:
 			BOOL		get() { return (BOOL)getValue().asBoolean(); }
 			void		set(BOOL value) { setValue(value); }
 
-	virtual void		setTentative(BOOL b)	{ mButton->setTentative(b); }
-	virtual BOOL		getTentative() const	{ return mButton->getTentative(); }
+	virtual void		setTentative(BOOL b);
+	virtual BOOL		getTentative() const;
 
 	virtual BOOL		setLabelArg( const std::string& key, const LLStringExplicit& text );
 
@@ -108,10 +106,11 @@ public:
 	void				setLabel( const LLStringExplicit& label );
 	std::string			getLabel() const;
 
+	void				setFont( const LLFontGL* font ) { mFont = font; }
+	
 	virtual void		setControlName(const std::string& control_name, LLView* context);
-	virtual std::string 	getControlName() const;
 
-	static void			onButtonPress(void *userdata);
+	void				onButtonPress(const LLSD& data);
 
 	virtual BOOL		isDirty()	const;		// Returns TRUE if the user has modified this control.
 	virtual void		resetDirty();			// Clear dirty state
@@ -121,19 +120,17 @@ protected:
 	LLButton*		mButton;
 	LLTextBox*		mLabel;
 	const LLFontGL* mFont;
-	LLColor4		mTextEnabledColor;
-	LLColor4		mTextDisabledColor;
-	BOOL			mRadioStyle;
-	BOOL			mInitialValue;			// Value set in constructor
-	BOOL			mSetValue;				// Value set programmatically
-	BOOL			mKeyboardFocusOnClick;
-	LLViewBorder*	mBorder;
-};
 
+	LLUIColor		mTextEnabledColor;
+	LLUIColor		mTextDisabledColor;
+};
 
-// HACK: fix old capitalization problem
-//typedef LLCheckBoxCtrl LLCheckboxCtrl;
-#define LLCheckboxCtrl LLCheckBoxCtrl
 
+#ifdef LL_WINDOWS
+#ifndef INSTANTIATE_GETCHILD_CHECKBOX
+#pragma warning (disable : 4231)
+extern template LLCheckBoxCtrl* LLView::getChild<LLCheckBoxCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+#endif
+#endif
 
 #endif  // LL_LLCHECKBOXCTRL_H
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 28a05c13f5..09f7a6c813 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -33,6 +33,8 @@
 // A control that displays the name of the chosen item, which when
 // clicked shows a scrolling box of options.
 
+#define INSTANTIATE_GETCHILD_COMBOBOX
+
 #include "linden_common.h"
 
 // file includes
@@ -48,167 +50,128 @@
 #include "llwindow.h"
 #include "llfloater.h"
 #include "llscrollbar.h"
+#include "llscrolllistcell.h"
+#include "llscrolllistitem.h"
 #include "llcontrol.h"
 #include "llfocusmgr.h"
 #include "lllineeditor.h"
 #include "v2math.h"
+#include "lluictrlfactory.h"
 
 // Globals
 S32 LLCOMBOBOX_HEIGHT = 0;
 S32 LLCOMBOBOX_WIDTH = 0;
 S32 MAX_COMBO_WIDTH = 500;
 
-static LLRegisterWidget<LLComboBox> r1("combo_box");
+template LLComboBox* LLView::getChild<LLComboBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
 
-LLComboBox::LLComboBox(	const std::string& name, const LLRect &rect, const std::string& label,
-	void (*commit_callback)(LLUICtrl*,void*),
-	void *callback_userdata
-	)
-:	LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata, 
-			 FOLLOWS_LEFT | FOLLOWS_TOP),
-	mTextEntry(NULL),
-	mArrowImage(NULL),
-	mAllowTextEntry(FALSE),
-	mMaxChars(20),
-	mTextEntryTentative(TRUE),
-	mListPosition(BELOW),
-	mPrearrangeCallback( NULL ),
-	mTextEntryCallback( NULL ),
-	mLabel(label)
-{
-	// Always use text box 
-	// Text label button
-	mButton = new LLButton(mLabel,
-								LLRect(), 
-								LLStringUtil::null,
-								NULL, this);
-	mButton->setImageUnselected(std::string("square_btn_32x128.tga"));
-	mButton->setImageSelected(std::string("square_btn_selected_32x128.tga"));
-	mButton->setImageDisabled(std::string("square_btn_32x128.tga"));
-	mButton->setImageDisabledSelected(std::string("square_btn_selected_32x128.tga"));
-	mButton->setScaleImage(TRUE);
-
-	mButton->setMouseDownCallback(onButtonDown);
-	mButton->setFont(LLFontGL::getFontSansSerifSmall());
-	mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
-	mButton->setHAlign( LLFontGL::LEFT );
-	mButton->setRightHPad(2);
-	addChild(mButton);
+static LLRegisterWidget<LLComboBox> register_combo_box("combo_box");
 
-	// disallow multiple selection
-	mList = new LLScrollListCtrl(std::string("ComboBox"), LLRect(), 
-								 &LLComboBox::onItemSelected, this, FALSE);
-	mList->setVisible(FALSE);
-	mList->setBgWriteableColor( LLColor4(1,1,1,1) );
-	mList->setCommitOnKeyboardMovement(FALSE);
-	addChild(mList);
-
-	mArrowImage = LLUI::sImageProvider->getUIImage("combobox_arrow.tga");
-	mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT);
+void LLComboBox::PreferredPositionValues::declareValues()
+{
+	declare("above", ABOVE);
+	declare("below", BELOW);
+}
 
-	updateLayout();
+LLComboBox::ItemParams::ItemParams()
+:	label("label")
+{
 }
 
 
-LLComboBox::~LLComboBox()
+LLComboBox::Params::Params()
+:	allow_text_entry("allow_text_entry", false),
+	show_text_as_tentative("show_text_as_tentative", true),
+	max_chars("max_chars", 20),
+	arrow_image("arrow_image"),
+	list_position("list_position", BELOW),
+	items("item"),
+	combo_button("combo_button"),
+	combo_list("combo_list"),
+	combo_editor("combo_editor")
 {
-	// children automatically deleted, including mMenu, mButton
+	addSynonym(items, "combo_item");
 }
 
-// virtual
-LLXMLNodePtr LLComboBox::getXML(bool save_children) const
+
+LLComboBox::LLComboBox(const LLComboBox::Params& p)
+:	LLUICtrl(p),
+	mTextEntry(NULL),
+	mTextEntryTentative(p.show_text_as_tentative),
+	mAllowTextEntry(p.allow_text_entry),
+	mMaxChars(p.max_chars),
+	mPrearrangeCallback(p.prearrange_callback()),
+	mTextEntryCallback(p.text_entry_callback()),
+	mSelectionCallback(p.selection_callback()),
+	mArrowImage(p.arrow_image),
+	mListPosition(p.list_position)
 {
-	LLXMLNodePtr node = LLUICtrl::getXML();
+	// Text label button
 
-	// Attributes
+	LLButton::Params button_params = p.combo_button;
+	button_params.mouse_down_callback.function(boost::bind(&LLComboBox::onButtonDown, this));
+	button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT);
+	button_params.rect(p.rect);
+	button_params.pad_right(2);
 
-	node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry);
+	mButton = LLUICtrlFactory::create<LLButton>(button_params);
+	mButton->setRightHPad(2);  //redo to compensate for button hack that leaves space for a character
+	addChild(mButton);
 
-	node->createChild("max_chars", TRUE)->setIntValue(mMaxChars);
+	LLScrollListCtrl::Params params = p.combo_list;
+	params.name("ComboBox");
+	params.commit_callback.function(boost::bind(&LLComboBox::onItemSelected, this, _2));
+	params.visible(false);
+	params.commit_on_keyboard_movement(false);
 
-	// Contents
+	mList = LLUICtrlFactory::create<LLScrollListCtrl>(params);
+	addChild(mList);
 
-	std::vector<LLScrollListItem*> data_list = mList->getAllData();
-	std::vector<LLScrollListItem*>::iterator data_itor;
-	for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
+	for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
+		it != p.items().end();
+		++it)
 	{
-		LLScrollListItem* item = *data_itor;
-		LLScrollListCell* cell = item->getColumn(0);
-		if (cell)
+		LLScrollListItem::Params item_params = *it;
+		if (it->label.isProvided())
 		{
-			LLXMLNodePtr item_node = node->createChild("combo_item", FALSE);
-			LLSD value = item->getValue();
-			item_node->createChild("value", TRUE)->setStringValue(value.asString());
-			item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
-			item_node->setStringValue(cell->getValue().asString());
+			item_params.cells.add().value(it->label());
 		}
+
+		mList->addRow(item_params);
 	}
 
-	return node;
+	createLineEditor(p);
+
+	setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
 }
 
-// static
-LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+void LLComboBox::initFromParams(const LLComboBox::Params& p)
 {
-	std::string name("combo_box");
-	node->getAttributeString("name", name);
-
-	std::string label("");
-	node->getAttributeString("label", label);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	BOOL allow_text_entry = FALSE;
-	node->getAttributeBOOL("allow_text_entry", allow_text_entry);
-
-	S32 max_chars = 20;
-	node->getAttributeS32("max_chars", max_chars);
-
-	LLUICtrlCallback callback = NULL;
-
-	LLComboBox* combo_box = new LLComboBox(name,
-							rect, 
-							label,
-							callback,
-							NULL);
-	combo_box->setAllowTextEntry(allow_text_entry, max_chars);
+	LLUICtrl::initFromParams(p);
 
-	combo_box->initFromXML(node, parent);
-
-	const std::string& contents = node->getValue();
-
-	if (contents.find_first_not_of(" \n\t") != contents.npos)
-	{
-		llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl;
-	}
-	else
+	if (!acceptsTextInput() && mLabel.empty())
 	{
-		LLXMLNodePtr child;
-		for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-		{
-			if (child->hasName("combo_item"))
-			{
-				std::string label = child->getTextContents();
-
-				std::string value = label;
-				child->getAttributeString("value", value);
-
-				combo_box->add(label, LLSD(value) );
-			}
-		}
+		selectFirstItem();
 	}
+}
 
-	// if providing user text entry or descriptive label
-	// don't select an item under the hood
-	if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty())
+// virtual
+BOOL LLComboBox::postBuild()
+{
+	if (mControlVariable)
 	{
-		combo_box->selectFirstItem();
+		setValue(mControlVariable->getValue()); // selects the appropriate item
 	}
+	return TRUE;
+}
+
 
-	return combo_box;
+LLComboBox::~LLComboBox()
+{
+	// children automatically deleted, including mMenu, mButton
 }
 
+
 void LLComboBox::setEnabled(BOOL enabled)
 {
 	LLView::setEnabled(enabled);
@@ -237,6 +200,7 @@ void LLComboBox::onCommit()
 		mTextEntry->setValue(getSimple());
 		mTextEntry->setTentative(FALSE);
 	}
+	setControlValue(getValue());
 	LLUICtrl::onCommit();
 }
 
@@ -431,6 +395,7 @@ BOOL LLComboBox::remove(S32 index)
 	if (index < mList->getItemCount())
 	{
 		mList->deleteSingleItem(index);
+		setLabel(mList->getSelectedItemLabel());
 		return TRUE;
 	}
 	return FALSE;
@@ -448,21 +413,17 @@ void LLComboBox::onFocusLost()
 	LLUICtrl::onFocusLost();
 }
 
-void LLComboBox::onLostTop()
-{
-	hideList();
-}
-
-
 void LLComboBox::setButtonVisible(BOOL visible)
 {
+	static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
+
 	mButton->setVisible(visible);
 	if (mTextEntry)
 	{
 		LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
 		if (visible)
 		{
-			text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
+			text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * drop_shadow_button;
 		}
 		//mTextEntry->setRect(text_entry_rect);
 		mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -498,54 +459,48 @@ S32 LLComboBox::getCurrentIndex() const
 }
 
 
-void LLComboBox::updateLayout()
+void LLComboBox::createLineEditor(const LLComboBox::Params& p)
 {
+	static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
 	LLRect rect = getLocalRect();
 	if (mAllowTextEntry)
 	{
-		S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
+		S32 shadow_size = drop_shadow_button;
 		mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size,
 								rect.mTop, rect.mRight, rect.mBottom));
 		mButton->setTabStop(FALSE);
+		mButton->setHAlign(LLFontGL::HCENTER);
 
-		if (!mTextEntry)
-		{
-			LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
-			text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
-			// clear label on button
-			std::string cur_label = mButton->getLabelSelected();
-			mTextEntry = new LLLineEditor(std::string("combo_text_entry"),
-										text_entry_rect,
-										LLStringUtil::null,
-										LLFontGL::getFontSansSerifSmall(),
-										mMaxChars,
-										onTextCommit,
-										onTextEntry,
-										NULL,
-										this);
-			mTextEntry->setSelectAllonFocusReceived(TRUE);
-			mTextEntry->setHandleEditKeysDirectly(TRUE);
-			mTextEntry->setCommitOnFocusLost(FALSE);
-			mTextEntry->setText(cur_label);
-			mTextEntry->setIgnoreTab(TRUE);
-			mTextEntry->setFollowsAll();
-			addChild(mTextEntry);
-		}
-		else
-		{
-			mTextEntry->setVisible(TRUE);
-			mTextEntry->setMaxTextLength(mMaxChars);
-		}
+		LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
+		text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * drop_shadow_button;
+		// clear label on button
+		std::string cur_label = mButton->getLabelSelected();
+		LLLineEditor::Params params = p.combo_editor;
+		params.rect(text_entry_rect);
+		params.default_text(LLStringUtil::null);
+		params.max_length_bytes(mMaxChars);
+		params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));
+		params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
+		params.focus_lost_callback(NULL);
+		params.select_on_focus(true);
+		params.handle_edit_keys_directly(true);
+		params.commit_on_focus_lost(false);
+		params.follows.flags(FOLLOWS_ALL);
+		mTextEntry = LLUICtrlFactory::create<LLLineEditor> (params);
+		mTextEntry->setText(cur_label);
+		mTextEntry->setIgnoreTab(TRUE);
+		addChild(mTextEntry);
 
 		// clear label on button
 		setLabel(LLStringUtil::null);
 
 		mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
 	}
-	else if (!mAllowTextEntry)
+	else
 	{
 		mButton->setRect(rect);
 		mButton->setTabStop(TRUE);
+		mButton->setHAlign(LLFontGL::LEFT);
 
 		if (mTextEntry)
 		{
@@ -672,7 +627,7 @@ void LLComboBox::hideList()
 
 	mButton->setToggleState(FALSE);
 	mList->setVisible(FALSE);
-	mList->highlightNthItem(-1);
+	mList->mouseOverHighlightNthItem(-1);
 
 	setUseBoundingRect(FALSE);
 	if( gFocusMgr.getTopCtrl() == this )
@@ -681,74 +636,74 @@ void LLComboBox::hideList()
 	}
 }
 
-//------------------------------------------------------------------
-// static functions
-//------------------------------------------------------------------
-
-// static
-void LLComboBox::onButtonDown(void *userdata)
+void LLComboBox::onButtonDown()
 {
-	LLComboBox *self = (LLComboBox *)userdata;
-
-	if (!self->mList->getVisible())
+	if (!mList->getVisible())
 	{
-		LLScrollListItem* last_selected_item = self->mList->getLastSelectedItem();
+		LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
 		if (last_selected_item)
 		{
 			// highlight the original selection before potentially selecting a new item
-			self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item));
+			mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
 		}
 
-		if( self->mPrearrangeCallback )
+		if( mPrearrangeCallback )
 		{
-			self->mPrearrangeCallback( self, self->mCallbackUserData );
+			mPrearrangeCallback( this, LLSD() );
 		}
 
-		if (self->mList->getItemCount() != 0)
+		if (mList->getItemCount() != 0)
 		{
-			self->showList();
+			showList();
 		}
 
-		self->setFocus( TRUE );
+		setFocus( TRUE );
 
 		// pass mouse capture on to list if button is depressed
-		if (self->mButton->hasMouseCapture())
+		if (mButton->hasMouseCapture())
 		{
-			gFocusMgr.setMouseCapture(self->mList);
+			gFocusMgr.setMouseCapture(mList);
 		}
 	}
 	else
 	{
-		self->hideList();
+		hideList();
 	} 
 
 }
 
-// static
-void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
-{
-	// Note: item is the LLScrollListCtrl
-	LLComboBox *self = (LLComboBox *) userdata;
 
-	const std::string name = self->mList->getSelectedItemLabel();
+//------------------------------------------------------------------
+// static functions
+//------------------------------------------------------------------
 
-	S32 cur_id = self->getCurrentIndex();
+void LLComboBox::onItemSelected(const LLSD& data)
+{
+	const std::string name = mList->getSelectedItemLabel();
+
+	S32 cur_id = getCurrentIndex();
 	if (cur_id != -1)
 	{
-		self->setLabel(name);
+		setLabel(name);
 
-		if (self->mAllowTextEntry)
+		if (mAllowTextEntry)
 		{
-			gFocusMgr.setKeyboardFocus(self->mTextEntry);
-			self->mTextEntry->selectAll();
+			gFocusMgr.setKeyboardFocus(mTextEntry);
+			mTextEntry->selectAll();
 		}
 	}
 
 	// hiding the list reasserts the old value stored in the text editor/dropdown button
-	self->hideList();
+	hideList();
 
 	// commit does the reverse, asserting the value in the list
-	self->onCommit();
+	onCommit();
+
+	// call the callback if it exists
+	if(mSelectionCallback)
+	{
+		mSelectionCallback(this, data);
+	}
 }
 
 BOOL LLComboBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen)
@@ -804,7 +759,7 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)
 		if (last_selected_item)
 		{
 			// highlight the original selection before potentially selecting a new item
-			mList->highlightNthItem(mList->getItemIndex(last_selected_item));
+			mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
 		}
 		result = mList->handleKeyHere(key, mask);
 
@@ -838,7 +793,7 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char)
 			if (last_selected_item)
 			{
 				// highlight the original selection before potentially selecting a new item
-				mList->highlightNthItem(mList->getItemIndex(last_selected_item));
+				mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
 			}
 			result = mList->handleUnicodeCharHere(uni_char);
 			if (mList->getLastSelectedItem() != last_selected_item)
@@ -850,15 +805,6 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char)
 	return result;
 }
 
-void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
-{
-	mAllowTextEntry = allow;
-	mTextEntryTentative = set_tentative;
-	mMaxChars = max_chars;
-
-	updateLayout();
-}
-
 void LLComboBox::setTextEntry(const LLStringExplicit& text)
 {
 	if (mTextEntry)
@@ -868,28 +814,25 @@ void LLComboBox::setTextEntry(const LLStringExplicit& text)
 	}
 }
 
-//static 
-void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
+void LLComboBox::onTextEntry(LLLineEditor* line_editor)
 {
-	LLComboBox* self = (LLComboBox*)user_data;
-
-	if (self->mTextEntryCallback)
+	if (mTextEntryCallback != NULL)
 	{
-		(*self->mTextEntryCallback)(line_editor, self->mCallbackUserData);
+		(mTextEntryCallback)(line_editor, LLSD());
 	}
 
 	KEY key = gKeyboard->currentKey();
 	if (key == KEY_BACKSPACE || 
 		key == KEY_DELETE)
 	{
-		if (self->mList->selectItemByLabel(line_editor->getText(), FALSE))
+		if (mList->selectItemByLabel(line_editor->getText(), FALSE))
 		{
 			line_editor->setTentative(FALSE);
 		}
 		else
 		{
-			line_editor->setTentative(self->mTextEntryTentative);
-			self->mList->deselectAllItems();
+			line_editor->setTentative(mTextEntryTentative);
+			mList->deselectAllItems();
 		}
 		return;
 	}
@@ -902,17 +845,17 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
 
 	if (key == KEY_DOWN)
 	{
-		self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1));
-		if (!self->mList->getVisible())
+		setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1));
+		if (!mList->getVisible())
 		{
-			if( self->mPrearrangeCallback )
+			if( mPrearrangeCallback )
 			{
-				self->mPrearrangeCallback( self, self->mCallbackUserData );
+				mPrearrangeCallback( this, LLSD() );
 			}
 
-			if (self->mList->getItemCount() != 0)
+			if (mList->getItemCount() != 0)
 			{
-				self->showList();
+				showList();
 			}
 		}
 		line_editor->selectAll();
@@ -920,17 +863,17 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
 	}
 	else if (key == KEY_UP)
 	{
-		self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1));
-		if (!self->mList->getVisible())
+		setCurrentByIndex(llmax(0, getCurrentIndex() - 1));
+		if (!mList->getVisible())
 		{
-			if( self->mPrearrangeCallback )
+			if( mPrearrangeCallback )
 			{
-				self->mPrearrangeCallback( self, self->mCallbackUserData );
+				mPrearrangeCallback( this, LLSD() );
 			}
 
-			if (self->mList->getItemCount() != 0)
+			if (mList->getItemCount() != 0)
 			{
-				self->showList();
+				showList();
 			}
 		}
 		line_editor->selectAll();
@@ -939,7 +882,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
 	else
 	{
 		// RN: presumably text entry
-		self->updateSelection();
+		updateSelection();
 	}
 }
 
@@ -958,7 +901,7 @@ void LLComboBox::updateSelection()
 	{
 		if (mPrearrangeCallback)
 		{
-			mPrearrangeCallback( this, mCallbackUserData );
+			mPrearrangeCallback( this, LLSD() );
 		}
 	}
 
@@ -983,14 +926,12 @@ void LLComboBox::updateSelection()
 	}
 }
 
-//static 
-void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data)
+void LLComboBox::onTextCommit(const LLSD& data)
 {
-	LLComboBox* self = (LLComboBox*)user_data;
-	std::string text = self->mTextEntry->getText();
-	self->setSimple(text);
-	self->onCommit();
-	self->mTextEntry->selectAll();
+	std::string text = mTextEntry->getText();
+	setSimple(text);
+	onCommit();
+	mTextEntry->selectAll();
 }
 
 void LLComboBox::setFocus(BOOL b)
@@ -1114,155 +1055,3 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last )
 {
 	return mList->selectItemRange(first, last);
 }
-
-
-//
-// LLFlyoutButton
-//
-
-static LLRegisterWidget<LLFlyoutButton> r2("flyout_button");
-
-const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
-
-LLFlyoutButton::LLFlyoutButton(
-		const std::string& name, 
-		const LLRect &rect,
-		const std::string& label,
-		void (*commit_callback)(LLUICtrl*, void*) ,
-		void *callback_userdata)
-:		LLComboBox(name, rect, LLStringUtil::null, commit_callback, callback_userdata),
-		mToggleState(FALSE),
-		mActionButton(NULL)
-{
-	// Always use text box 
-	// Text label button
-	mActionButton = new LLButton(label,
-					LLRect(), LLStringUtil::null, NULL, this);
-	mActionButton->setScaleImage(TRUE);
-
-	mActionButton->setClickedCallback(onActionButtonClick);
-	mActionButton->setFollowsAll();
-	mActionButton->setHAlign( LLFontGL::HCENTER );
-	mActionButton->setLabel(label);
-	addChild(mActionButton);
-
-	mActionButtonImage = LLUI::getUIImage("flyout_btn_left.tga");
-	mExpanderButtonImage = LLUI::getUIImage("flyout_btn_right.tga");
-	mActionButtonImageSelected = LLUI::getUIImage("flyout_btn_left_selected.tga");
-	mExpanderButtonImageSelected = LLUI::getUIImage("flyout_btn_right_selected.tga");
-	mActionButtonImageDisabled = LLUI::getUIImage("flyout_btn_left_disabled.tga");
-	mExpanderButtonImageDisabled = LLUI::getUIImage("flyout_btn_right_disabled.tga");
-
-	mActionButton->setImageSelected(mActionButtonImageSelected);
-	mActionButton->setImageUnselected(mActionButtonImage);
-	mActionButton->setImageDisabled(mActionButtonImageDisabled);
-	mActionButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
-
-	mButton->setImageSelected(mExpanderButtonImageSelected);
-	mButton->setImageUnselected(mExpanderButtonImage);
-	mButton->setImageDisabled(mExpanderButtonImageDisabled);
-	mButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
-	mButton->setRightHPad(6);
-
-	updateLayout();
-}
-
-//static 
-LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name = "flyout_button";
-	node->getAttributeString("name", name);
-
-	std::string label("");
-	node->getAttributeString("label", label);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	LLUICtrlCallback callback = NULL;
-
-	LLFlyoutButton* flyout_button = new LLFlyoutButton(name,
-							rect, 
-							label,
-							callback,
-							NULL);
-
-	std::string list_position;
-	node->getAttributeString("list_position", list_position);
-	if (list_position == "below")
-	{
-		flyout_button->mListPosition = BELOW;
-	}
-	else if (list_position == "above")
-	{
-		flyout_button->mListPosition = ABOVE;
-	}
-	
-
-	flyout_button->initFromXML(node, parent);
-
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		if (child->hasName("flyout_button_item"))
-		{
-			std::string label = child->getTextContents();
-
-			std::string value = label;
-			child->getAttributeString("value", value);
-
-			flyout_button->add(label, LLSD(value) );
-		}
-	}
-
-	flyout_button->updateLayout();
-
-	return flyout_button;
-}
-
-void LLFlyoutButton::updateLayout()
-{
-	LLComboBox::updateLayout();
-
-	mButton->setOrigin(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
-	mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
-	mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
-	mButton->setTabStop(FALSE);
-	mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
-
-	mActionButton->setOrigin(0, 0);
-	mActionButton->reshape(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
-}
-
-//static 
-void LLFlyoutButton::onActionButtonClick(void *user_data)
-{
-	LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data;
-	// remember last list selection?
-	buttonp->mList->deselect();
-	buttonp->onCommit();
-}
-
-void LLFlyoutButton::draw()
-{
-	mActionButton->setToggleState(mToggleState);
-	mButton->setToggleState(mToggleState);
-
-	//FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
-	// the label reflects the last selected item, for now we have to manually remove the label
-	mButton->setLabel(LLStringUtil::null);
-	LLComboBox::draw();	
-}
-
-void LLFlyoutButton::setEnabled(BOOL enabled)
-{
-	mActionButton->setEnabled(enabled);
-	LLComboBox::setEnabled(enabled);
-}
-
-
-void LLFlyoutButton::setToggleState(BOOL state)
-{
-	mToggleState = state;
-}
-
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 33e1baa748..e7a864eb82 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -41,14 +41,13 @@
 #include "llctrlselectioninterface.h"
 #include "llimagegl.h"
 #include "llrect.h"
+#include "llscrolllistctrl.h"
+#include "lllineeditor.h"
+#include <boost/function.hpp>
 
 // Classes
 
 class LLFontGL;
-class LLButton;
-class LLSquareButton;
-class LLScrollListCtrl;
-class LLLineEditor;
 class LLViewBorder;
 
 extern S32 LLCOMBOBOX_HEIGHT;
@@ -57,30 +56,61 @@ extern S32 LLCOMBOBOX_WIDTH;
 class LLComboBox
 :	public LLUICtrl, public LLCtrlListInterface
 {
-public:
+public:	
 	typedef enum e_preferred_position
 	{
 		ABOVE,
 		BELOW
 	} EPreferredPosition;
 
-	LLComboBox(
-		const std::string& name, 
-		const LLRect &rect,
-		const std::string& label,
-		void (*commit_callback)(LLUICtrl*, void*) = NULL,
-		void *callback_userdata = NULL
-		);
-	virtual ~LLComboBox(); 
+	struct PreferredPositionValues : public LLInitParam::TypeValuesHelper<EPreferredPosition, PreferredPositionValues>
+	{
+		static void declareValues();
+	};
 
-	// LLView interface
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	struct ItemParams : public LLInitParam::Block<ItemParams, LLScrollListItem::Params>
+	{
+		Optional<std::string>	label;
+		ItemParams();
+	};
+
+	struct Params 
+	:	public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<bool>						allow_text_entry,
+											show_text_as_tentative;
+		Optional<S32>						max_chars;
+		Optional<commit_callback_t> 		prearrange_callback,
+											text_entry_callback,
+											selection_callback;
+		Optional<LLUIImage*>				arrow_image;
+
+		Optional<EPreferredPosition, PreferredPositionValues>	list_position;
+		
+		// components
+		Optional<LLButton::Params>			combo_button;
+		Optional<LLScrollListCtrl::Params>	combo_list;
+		Optional<LLLineEditor::Params>		combo_editor;
+
+		Multiple<ItemParams>				items;
+		
+		Params();
+	};
+
 
+	virtual ~LLComboBox(); 
+	/*virtual*/ BOOL postBuild();
+	
+protected:
+	friend class LLUICtrlFactory;
+	LLComboBox(const Params&);
+	void	initFromParams(const Params&);
+
+public:
+	// LLView interface
 	virtual void	draw();
 	virtual void	onFocusLost();
-	virtual void	onLostTop();
 
 	virtual void	setEnabled(BOOL enabled);
 
@@ -105,7 +135,6 @@ public:
 	// items, this is just the label.
 	virtual LLSD	getValue() const;
 
-	void			setAllowTextEntry(BOOL allow, S32 max_chars = 50, BOOL make_tentative = TRUE);
 	void			setTextEntry(const LLStringExplicit& text);
 
 	LLScrollListItem*	add(const std::string& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);	// add item "name" to menu
@@ -134,7 +163,7 @@ public:
 	BOOL			setCurrentByIndex( S32 index );
 	S32				getCurrentIndex() const;
 
-	virtual void	updateLayout();
+	void			createLineEditor(const Params&);
 
 	//========================================================================
 	LLCtrlSelectionInterface* getSelectionInterface()	{ return (LLCtrlSelectionInterface*)this; };
@@ -170,26 +199,28 @@ public:
 	
 	void*			getCurrentUserdata();
 
-	void			setPrearrangeCallback( void (*cb)(LLUICtrl*,void*) ) { mPrearrangeCallback = cb; }
-	void			setTextEntryCallback( void (*cb)(LLLineEditor*, void*) ) { mTextEntryCallback = cb; }
+	void			setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; }
+	void			setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }
+	void			setSelectionCallback( commit_callback_t cb ) { mSelectionCallback = cb; }
 
 	void			setButtonVisible(BOOL visible);
 
-	static void		onButtonDown(void *userdata);
-	static void		onItemSelected(LLUICtrl* item, void *userdata);
-	static void		onTextEntry(LLLineEditor* line_editor, void* user_data);
-	static void		onTextCommit(LLUICtrl* caller, void* user_data);
+	void			onButtonDown();
+	void			onItemSelected(const LLSD& data);
+	void			onTextCommit(const LLSD& data);
 
 	void			updateSelection();
 	virtual void	showList();
 	virtual void	hideList();
-
+	
+	void			onTextEntry(LLLineEditor* line_editor);
+	
 protected:
 	LLButton*			mButton;
 	LLScrollListCtrl*	mList;
 	EPreferredPosition	mListPosition;
 	LLPointer<LLUIImage>	mArrowImage;
-	std::string			mLabel;
+	LLUIString			mLabel;
 
 private:
 	S32					mButtonPadding;
@@ -197,39 +228,16 @@ private:
 	BOOL				mAllowTextEntry;
 	S32					mMaxChars;
 	BOOL				mTextEntryTentative;
-	void				(*mPrearrangeCallback)(LLUICtrl*,void*);
-	void				(*mTextEntryCallback)(LLLineEditor*, void*);
+	commit_callback_t	mPrearrangeCallback;
+	commit_callback_t	mTextEntryCallback;
+	commit_callback_t	mSelectionCallback;
 };
 
-class LLFlyoutButton : public LLComboBox
-{
-public:
-	LLFlyoutButton(
-		const std::string& name, 
-		const LLRect &rect,
-		const std::string& label,
-		void (*commit_callback)(LLUICtrl*, void*) = NULL,
-		void *callback_userdata = NULL);
-
-	virtual void	updateLayout();
-	virtual void	draw();
-	virtual void	setEnabled(BOOL enabled);
-
-	void setToggleState(BOOL state);
-
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-	static void		onActionButtonClick(void *userdata);
-	static void		onSelectAction(LLUICtrl* ctrl, void *userdata);
-
-protected:
-	LLButton*				mActionButton;
-	LLPointer<LLUIImage>	mActionButtonImage;
-	LLPointer<LLUIImage>	mExpanderButtonImage;
-	LLPointer<LLUIImage>	mActionButtonImageSelected;
-	LLPointer<LLUIImage>	mExpanderButtonImageSelected;
-	LLPointer<LLUIImage>	mActionButtonImageDisabled;
-	LLPointer<LLUIImage>	mExpanderButtonImageDisabled;
-	BOOL					mToggleState;
-};
+#ifdef LL_WINDOWS
+#ifndef INSTANTIATE_GETCHILD_COMBOBOX
+#pragma warning (disable : 4231)
+extern template LLComboBox* LLView::getChild<LLComboBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+#endif
+#endif
 
 #endif
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
new file mode 100644
index 0000000000..f1fc3d8f43
--- /dev/null
+++ b/indra/llui/llconsole.cpp
@@ -0,0 +1,393 @@
+/** 
+ * @file llconsole.cpp
+ * @brief a scrolling console output device
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+//#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+#include "llconsole.h"
+
+// linden library includes
+#include "llmath.h"
+//#include "llviewercontrol.h"
+#include "llcriticaldamp.h"
+#include "llfontgl.h"
+#include "llgl.h"
+#include "llui.h"
+#include "lluiimage.h"
+//#include "llviewerimage.h"
+//#include "llviewerimagelist.h"
+//#include "llviewerwindow.h"
+#include "llsd.h"
+#include "llfontgl.h"
+#include "llmath.h"
+
+//#include "llstartup.h"
+
+// Used for LCD display
+extern void AddNewDebugConsoleToLCD(const LLWString &newLine);
+
+LLConsole* gConsole = NULL;  // Created and destroyed in LLViewerWindow.
+
+const F32 FADE_DURATION = 2.f;
+const S32 MIN_CONSOLE_WIDTH = 200;
+ 
+LLConsole::LLConsole(const LLConsole::Params& p) 
+:	LLView(p),
+	LLFixedBuffer(p.max_lines),
+	mLinePersistTime(p.persist_time), // seconds
+	mFont(p.font)
+{
+	if (p.font_size_index.isProvided())
+	{
+		setFontSize(p.font_size_index);
+	}
+	mFadeTime = mLinePersistTime - FADE_DURATION;
+	setMaxLines(LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines"));
+}
+
+void LLConsole::setLinePersistTime(F32 seconds)
+{
+	mLinePersistTime = seconds;
+	mFadeTime = mLinePersistTime - FADE_DURATION;
+}
+
+void LLConsole::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	S32 new_width = llmax(50, llmin(getRect().getWidth(), width));
+	S32 new_height = llmax(llfloor(mFont->getLineHeight()) + 15, llmin(getRect().getHeight(), height));
+
+	if (   mConsoleWidth == new_width
+		&& mConsoleHeight == new_height )
+	{
+		return;
+	}
+	
+	mConsoleWidth = new_width;
+	mConsoleHeight= new_height;
+	
+	LLView::reshape(new_width, new_height, called_from_parent);
+	
+	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
+	{
+		(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
+	}
+}
+
+void LLConsole::setFontSize(S32 size_index)
+{
+	if (-1 == size_index)
+	{
+		mFont = LLFontGL::getFontMonospace();
+	}
+	else if (0 == size_index)
+	{
+		mFont = LLFontGL::getFontSansSerif();
+	}
+	else if (1 == size_index)
+	{
+		mFont = LLFontGL::getFontSansSerifBig();
+	}
+	else
+	{
+		mFont = LLFontGL::getFontSansSerifHuge();
+	}
+	
+	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
+	{
+		(*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true);
+	}
+}
+
+void LLConsole::draw()
+{
+	LLGLSUIDefault gls_ui;
+
+	// skip lines added more than mLinePersistTime ago
+	F32 cur_time = mTimer.getElapsedTimeF32();
+	
+	F32 skip_time = cur_time - mLinePersistTime;
+	F32 fade_time = cur_time - mFadeTime;
+
+	if (mParagraphs.empty()) 	//No text to draw.
+	{
+		return;
+	}
+
+	U32 num_lines=0;
+
+	paragraph_t::reverse_iterator paragraph_it;
+	paragraph_it = mParagraphs.rbegin();
+	U32 paragraph_num=mParagraphs.size();
+	
+	while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend())
+	{
+		num_lines += (*paragraph_it).mLines.size();
+		if(num_lines > mMaxLines 
+			|| ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f)) 
+		{							//All lines above here are done.  Lose them.
+			for (U32 i=0;i<paragraph_num;i++)
+			{
+				if (!mParagraphs.empty())
+					mParagraphs.pop_front();
+			}
+			break;
+		}
+		paragraph_num--;
+		paragraph_it++;
+	}
+
+	if (mParagraphs.empty())
+	{
+		return;
+	}
+	
+	// draw remaining lines
+	F32 y_pos = 0.f;
+
+	LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga");
+
+//	F32 console_opacity = llclamp(gSavedSettings.getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
+	F32 console_opacity = llclamp(LLUI::sSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f);
+//	LLColor4 color = gSavedSkinSettings.getColor("ConsoleBackground");
+	LLColor4 color = LLUI::sSettingGroups["color"]->getColor("ConsoleBackground");
+	color.mV[VALPHA] *= console_opacity;
+
+	F32 line_height = mFont->getLineHeight();
+
+	for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++)
+	{
+		S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + 8);
+		S32 target_width =  llfloor( (*paragraph_it).mMaxWidth +15);
+
+		y_pos += ((*paragraph_it).mLines.size()) * line_height;
+		imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color);
+
+		F32 y_off=0;
+
+		F32 alpha;
+
+		if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time))
+		{
+			alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime);
+		}
+		else
+		{
+			alpha = 1.0f;
+		}
+
+		if( alpha > 0.f )
+		{
+			for (lines_t::iterator line_it=(*paragraph_it).mLines.begin(); 
+					line_it != (*paragraph_it).mLines.end();
+					line_it ++)
+			{
+				for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin();
+						seg_it != (*line_it).mLineColorSegments.end();
+						seg_it++)
+				{
+					mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos -  y_off,
+						LLColor4(
+							(*seg_it).mColor.mV[VRED], 
+							(*seg_it).mColor.mV[VGREEN], 
+							(*seg_it).mColor.mV[VBLUE], 
+							(*seg_it).mColor.mV[VALPHA]*alpha),
+						LLFontGL::LEFT, 
+						LLFontGL::BASELINE,
+						LLFontGL::NORMAL,
+						LLFontGL::DROP_SHADOW,
+						S32_MAX,
+						target_width
+						);
+				}
+				y_off += line_height;
+			}
+		}
+		y_pos  += 8;
+	}
+}
+
+void LLConsole::addLine(const std::string& utf8line)
+{
+	LLWString wline = utf8str_to_wstring(utf8line);
+	addLine(wline, 0.f, LLColor4(1.f, 1.f, 1.f, 1.f));
+}
+
+void LLConsole::addLine(const LLWString& wline)
+{
+	addLine(wline, 0.f, LLColor4(1.f, 1.f, 1.f, 1.f));
+}
+
+void LLConsole::addLine(const std::string& utf8line, F32 size, const LLColor4 &color)
+{
+	LLWString wline = utf8str_to_wstring(utf8line);
+	addLine(wline, size, color);
+}
+
+//Generate highlight color segments for this paragraph.  Pass in default color of paragraph.
+void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color) 
+{
+	LLSD paragraph_color_segments;
+	LLColor4 lcolor=color;
+	
+	paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText);
+	LLSD color_sd = color.getValue();
+	paragraph_color_segments[0]["color"]=color_sd;
+
+	for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray();
+		color_segment_it != paragraph_color_segments.endArray();
+		++color_segment_it)
+	{			
+		LLSD color_llsd = (*color_segment_it)["color"];
+		std::string color_str  = (*color_segment_it)["text"].asString();
+
+		ParagraphColorSegment color_segment;
+		
+		color_segment.mColor.setValue(color_llsd);
+		color_segment.mNumChars = color_str.length();
+		
+		mParagraphColorSegments.push_back(color_segment);
+	}
+}
+
+//Called when a paragraph is added to the console or window is resized.
+void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, bool force_resize)
+{
+	if ( !force_resize )
+	{
+		if ( mMaxWidth >= 0.0f 
+		 &&  mMaxWidth < screen_width )
+		{
+			return;					//No resize required.
+		}
+	}
+	
+	screen_width = screen_width - 30;	//Margin for small windows.
+	
+	if (	mParagraphText.empty() 
+		|| mParagraphColorSegments.empty()
+		|| font == NULL)
+	{
+		return;					//Not enough info to complete.
+	}
+	
+	mLines.clear();				//Chuck everything.
+	mMaxWidth = 0.0f;
+	
+	paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin();
+	U32 current_color_length = (*current_color).mNumChars;	
+	
+	S32 paragraph_offset = 0;			//Offset into the paragraph text.
+
+	// Wrap lines that are longer than the view is wide.
+	while( paragraph_offset < (S32)mParagraphText.length() )
+	{
+		S32 skip_chars; // skip '\n'
+		// Figure out if a word-wrapped line fits here.
+		LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset);
+		if (line_end != LLWString::npos)
+		{
+			skip_chars = 1; // skip '\n'
+		}
+		else
+		{
+			line_end = mParagraphText.size();
+			skip_chars = 0;
+		}
+
+		U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_end - paragraph_offset, TRUE);
+
+		if (drawable != 0)
+		{
+			F32 x_position = 0;						//Screen X position of text.
+			
+			mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) );
+			Line line;
+			
+			U32 left_to_draw = drawable;
+			U32 drawn = 0;
+			
+			while (left_to_draw >= current_color_length 
+				&& current_color != mParagraphColorSegments.end() )
+			{
+				LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length );
+				line.mLineColorSegments.push_back( LineColorSegment( color_text,			//Append segment to line.
+												(*current_color).mColor, 
+												x_position ) );
+												
+				x_position += font->getWidth( color_text.c_str() );	//Set up next screen position.
+				
+				drawn += current_color_length;
+				left_to_draw -= current_color_length;
+				
+				current_color++;							//Goto next paragraph color record.
+				
+				if (current_color != mParagraphColorSegments.end())
+				{
+					current_color_length = (*current_color).mNumChars;
+				}
+			}
+			
+			if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() )
+			{
+					LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw );
+					
+					line.mLineColorSegments.push_back( LineColorSegment( color_text,		//Append segment to line.
+													(*current_color).mColor, 
+													x_position ) );
+																		
+					current_color_length -= left_to_draw;
+			}
+			mLines.push_back(line);								//Append line to paragraph line list.
+		}
+		paragraph_offset += (drawable + skip_chars);
+	}
+}
+
+//Pass in the string and the default color for this block of text.
+LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width) 
+						: mParagraphText(str), mAddTime(add_time), mMaxWidth(-1)
+{
+	makeParagraphColorSegments(color);
+	updateLines( screen_width, font );
+}
+	
+void LLConsole::addLine(const LLWString& wline, F32 size, const LLColor4 &color)
+{	
+	Paragraph paragraph(wline, color, mTimer.getElapsedTimeF32(), mFont,  (F32)getRect().getWidth() );
+	
+	mParagraphs.push_back ( paragraph );
+	
+#if LL_WINDOWS && LL_LCD_COMPILE
+	// add to LCD screen
+	AddNewDebugConsoleToLCD(wline);
+#endif	
+}
diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h
new file mode 100644
index 0000000000..65149b217f
--- /dev/null
+++ b/indra/llui/llconsole.h
@@ -0,0 +1,162 @@
+/** 
+ * @file llconsole.h
+ * @brief a simple console-style output device
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLCONSOLE_H
+#define LL_LLCONSOLE_H
+
+#include "llfixedbuffer.h"
+#include "llview.h"
+#include "v4color.h"
+#include <deque>
+
+class LLFontGL;
+class LLSD;
+
+class LLConsole : public LLFixedBuffer, public LLView
+{
+public:
+	typedef enum e_font_size
+	{
+		MONOSPACE = -1,
+		SMALL = 0,
+		BIG = 1
+	} EFontSize;
+
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<U32>	max_lines;
+		Optional<F32>	persist_time;
+		Optional<S32>	font_size_index;
+		Params()
+		:	max_lines("max_lines", LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines")),
+			persist_time("persist_time", 0.f) // forever
+		{
+			mouse_opaque(false);
+		}
+	};
+protected:
+	LLConsole(const Params&);
+	friend class LLUICtrlFactory;
+
+public:
+	//A paragraph color segment defines the color of text in a line 
+	//of text that was received for console display.  It has no 
+	//notion of line wraps, screen position, or the text it contains.
+	//It is only the number of characters that are a color and the
+	//color.
+	struct ParagraphColorSegment
+	{
+		S32		mNumChars;
+		LLColor4 mColor;
+	};
+	
+	//A line color segment is a chunk of text, the color associated
+	//with it, and the X Position it was calculated to begin at 
+	//on the screen.  X Positions are re-calculated if the 
+	//screen changes size.
+	class LineColorSegment
+	{
+		public:
+			LineColorSegment(LLWString text, LLColor4 color, F32 xpos) : mText(text), mColor(color), mXPosition(xpos) {}
+		public:
+			LLWString mText;
+			LLColor4  mColor;
+			F32		  mXPosition;
+	};
+	 	
+	typedef std::list<LineColorSegment> line_color_segments_t;
+	
+	//A line is composed of one or more color segments.
+	class Line
+	{
+		public:
+			line_color_segments_t mLineColorSegments;
+	};
+	
+	typedef std::list<Line> lines_t;
+	typedef std::list<ParagraphColorSegment> paragraph_color_segments_t;
+	
+	//A paragraph is a processed element containing the entire text of the
+	//message (used for recalculating positions on screen resize)
+	//The time this message was added to the console output
+	//The visual screen width of the longest line in this block
+	//And a list of one or more lines which are used to display this message.
+	class Paragraph
+	{
+		public:
+			Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width);
+			void makeParagraphColorSegments ( const LLColor4 &color);
+			void updateLines ( F32 screen_width,  const LLFontGL* font, bool force_resize=false );
+		public:
+			LLWString mParagraphText;	//The entire text of the paragraph
+			paragraph_color_segments_t	mParagraphColorSegments;
+			F32 mAddTime;				//Time this paragraph was added to the display.
+			F32 mMaxWidth;				//Width of the widest line of text in this paragraph.
+			lines_t	mLines;
+			
+	};
+		
+	//The console contains a deque of paragraphs which represent the individual messages.
+	typedef std::deque<Paragraph> paragraph_t;
+	paragraph_t mParagraphs;
+
+	~LLConsole(){};
+
+	// each line lasts this long after being added
+	void			setLinePersistTime(F32 seconds);
+
+	void			reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+
+	// -1 = monospace, 0 means small, font size = 1 means big
+	void			setFontSize(S32 size_index);
+
+	void			addLine(const std::string& utf8line, F32 size, const LLColor4 &color);
+	void			addLine(const LLWString& wline, F32 size, const LLColor4 &color);
+	
+	// Overrides
+	/*virtual*/ void	draw();
+	/*virtual*/ void	addLine(const std::string& utf8line);
+	/*virtual*/ void	addLine(const LLWString& line);
+private:
+	F32			mLinePersistTime; // Age at which to stop drawing.
+	F32			mFadeTime; // Age at which to start fading
+	const LLFontGL*	mFont;
+	S32			mLastBoxHeight;
+	S32			mLastBoxWidth;
+	S32			mConsoleWidth;
+	S32			mConsoleHeight;
+
+};
+
+extern LLConsole* gConsole;
+
+#endif
diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp
new file mode 100644
index 0000000000..a63023e35c
--- /dev/null
+++ b/indra/llui/llcontainerview.cpp
@@ -0,0 +1,301 @@
+/** 
+ * @file llcontainerview.cpp
+ * @brief Container for all statistics info
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llcontainerview.h"
+
+#include "llerror.h"
+#include "llfontgl.h"
+#include "llgl.h"
+#include "llui.h"
+#include "llstring.h"
+#include "llscrollcontainer.h"
+#include "lluictrlfactory.h"
+
+static LLRegisterWidget<LLContainerView> r("container_view");
+
+LLContainerView::LLContainerView(const LLContainerView::Params& p)
+:	LLView(p),
+	mShowLabel(p.show_label),
+	mLabel(p.label),
+	mDisplayChildren(p.display_children)
+{
+	mCollapsible = TRUE;
+	mScrollContainer = NULL;
+}
+
+LLContainerView::~LLContainerView()
+{
+	// Children all cleaned up by default view destructor.
+}
+
+BOOL LLContainerView::postBuild()
+{
+	setDisplayChildren(mDisplayChildren);
+	reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
+	return TRUE;
+}
+
+bool LLContainerView::addChild(LLView* child, S32 tab_group)
+{
+	bool res = LLView::addChild(child, tab_group);
+	if (res)
+	{
+		sendChildToBack(child);
+	}
+	return res;
+}
+
+BOOL LLContainerView::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	BOOL handled = FALSE;
+	if (mDisplayChildren)
+	{
+		handled = (LLView::childrenHandleMouseDown(x, y, mask) != NULL);
+	}
+	if (!handled)
+	{
+		if( mCollapsible && mShowLabel && (y >= getRect().getHeight() - 10) )
+		{
+			setDisplayChildren(!mDisplayChildren);
+			reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
+			handled = TRUE;
+		}
+	}
+	return handled;
+}
+
+BOOL LLContainerView::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	BOOL handled = FALSE;
+	if (mDisplayChildren)
+	{
+		handled = (LLView::childrenHandleMouseUp(x, y, mask) != NULL);
+	}
+	return handled;
+}
+
+
+void LLContainerView::draw()
+{
+	{
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+		gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+	}
+		
+	// Draw the label
+	if (mShowLabel)
+	{
+		LLFontGL::getFontMonospace()->renderUTF8(
+			mLabel, 0, 2, getRect().getHeight() - 2, LLColor4(1,1,1,1), LLFontGL::LEFT, LLFontGL::TOP);
+	}
+
+	LLView::draw();
+}
+
+
+void LLContainerView::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	S32 desired_width = width;
+	S32 desired_height = height;
+
+	if (mScrollContainer)
+	{
+		BOOL dum_bool;
+		mScrollContainer->calcVisibleSize(&desired_width, &desired_height, &dum_bool, &dum_bool);
+	}
+	else
+	{
+		// if we're uncontained - make height as small as possible
+		desired_height = 0;
+	}
+
+	arrange(desired_width, desired_height, called_from_parent);
+
+	// sometimes, after layout, our container will change size (scrollbars popping in and out)
+	// if so, attempt another layout
+	if (mScrollContainer)
+	{
+		S32 new_container_width;
+		S32 new_container_height;
+		BOOL dum_bool;
+		mScrollContainer->calcVisibleSize(&new_container_width, &new_container_height, &dum_bool, &dum_bool);
+
+		if ((new_container_width != desired_width) ||
+			(new_container_height != desired_height))  // the container size has changed, attempt to arrange again
+		{
+			arrange(new_container_width, new_container_height, called_from_parent);
+		}
+	}
+}
+
+void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent)
+{
+	// Determine the sizes and locations of all contained views
+	S32 total_height = 0;
+	S32 top, left, right, bottom;
+	//LLView *childp;
+
+	// These will be used for the children
+	left = 4;
+	top = getRect().getHeight() - 4;
+	right = width - 2;
+	bottom = top;
+	
+	// Leave some space for the top label/grab handle
+	if (mShowLabel)
+	{
+		total_height += 20;
+	}
+
+	if (mDisplayChildren)
+	{
+		// Determine total height
+		U32 child_height = 0;
+		for (child_list_const_iter_t child_iter = getChildList()->begin();
+			 child_iter != getChildList()->end(); ++child_iter)
+		{
+			LLView *childp = *child_iter;
+			if (!childp->getVisible())
+			{
+				llwarns << "Incorrect visibility!" << llendl;
+			}
+			LLRect child_rect = childp->getRequiredRect();
+			child_height += child_rect.getHeight();
+			child_height += 2;
+		}
+		total_height += child_height;
+	}
+
+	if (total_height < height)
+		total_height = height;
+	
+	if (followsTop())
+	{
+		// HACK: casting away const. Should use setRect or some helper function instead.
+		const_cast<LLRect&>(getRect()).mBottom = getRect().mTop - total_height;
+	}
+	else
+	{
+		// HACK: casting away const. Should use setRect or some helper function instead.
+		const_cast<LLRect&>(getRect()).mTop = getRect().mBottom + total_height;
+	}
+	// HACK: casting away const. Should use setRect or some helper function instead.
+		const_cast<LLRect&>(getRect()).mRight = getRect().mLeft + width;
+
+	top = total_height;
+	if (mShowLabel)
+		{
+			top -= 20;
+		}
+	
+	bottom = top;
+
+	if (mDisplayChildren)
+	{
+		// Iterate through all children, and put in container from top down.
+		for (child_list_const_iter_t child_iter = getChildList()->begin();
+			 child_iter != getChildList()->end(); ++child_iter)
+		{
+			LLView *childp = *child_iter;
+			LLRect child_rect = childp->getRequiredRect();
+			bottom -= child_rect.getHeight();
+			LLRect r(left, bottom + child_rect.getHeight(), right, bottom);
+			childp->setRect(r);
+			childp->reshape(right - left, top - bottom);
+			top = bottom - 2;
+			bottom = top;
+		}
+	}
+	
+	if (!called_from_parent)
+	{
+		if (getParent())
+		{
+			getParent()->reshape(getParent()->getRect().getWidth(), getParent()->getRect().getHeight(), FALSE);
+		}
+	}
+
+}
+
+LLRect LLContainerView::getRequiredRect()
+{
+	LLRect req_rect;
+	//LLView *childp;
+	U32 total_height = 0;
+	
+	// Determine the sizes and locations of all contained views
+
+	// Leave some space for the top label/grab handle
+
+	if (mShowLabel)
+	{
+		total_height = 20;
+	}
+		
+
+	if (mDisplayChildren)
+	{
+		// Determine total height
+		U32 child_height = 0;
+		for (child_list_const_iter_t child_iter = getChildList()->begin();
+			 child_iter != getChildList()->end(); ++child_iter)
+		{
+			LLView *childp = *child_iter;
+			LLRect child_rect = childp->getRequiredRect();
+			child_height += child_rect.getHeight();
+			child_height += 2;
+		}
+
+		total_height += child_height;
+	}
+	req_rect.mTop = total_height;
+	return req_rect;
+}
+
+void LLContainerView::setLabel(const std::string& label)
+{
+	mLabel = label;
+}
+
+void LLContainerView::setDisplayChildren(const BOOL displayChildren)
+{
+	mDisplayChildren = displayChildren;
+	for (child_list_const_iter_t child_iter = getChildList()->begin();
+		 child_iter != getChildList()->end(); ++child_iter)
+	{
+		LLView *childp = *child_iter;
+		childp->setVisible(mDisplayChildren);
+	}
+}
diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h
new file mode 100644
index 0000000000..9f3d1ac7ad
--- /dev/null
+++ b/indra/llui/llcontainerview.h
@@ -0,0 +1,92 @@
+/** 
+ * @file llcontainerview.h
+ * @brief Container for all statistics info.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLCONTAINERVIEW_H
+#define LL_LLCONTAINERVIEW_H
+
+#include "stdtypes.h"
+#include "lltextbox.h"
+#include "llstatbar.h"
+
+class LLScrollContainer;
+
+class LLContainerView : public LLView
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<std::string> label;
+		Optional<bool> show_label;
+		Optional<bool> display_children;
+		Params()
+			: label("label"),
+			  show_label("show_label", FALSE),
+			  display_children("display_children", TRUE)
+		{
+			mouse_opaque(false);
+		}
+	};
+protected:
+	LLContainerView(const Params& p);
+	friend class LLUICtrlFactory;
+public:
+	~LLContainerView();
+
+	/*virtual*/ BOOL postBuild();
+	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
+	
+	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+
+	/*virtual*/ void draw();
+	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+	/*virtual*/ LLRect getRequiredRect();	// Return the height of this object, given the set options.
+
+	void setLabel(const std::string& label);
+	void showLabel(BOOL show) { mShowLabel = show; }
+	void setDisplayChildren(const BOOL displayChildren);
+	BOOL getDisplayChildren() { return mDisplayChildren; }
+	void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;}
+
+ private:
+	LLScrollContainer* mScrollContainer;
+	void arrange(S32 width, S32 height, BOOL called_from_parent = TRUE);
+	BOOL mShowLabel;
+
+protected:
+	BOOL mDisplayChildren;
+	std::string mLabel;
+public:
+	BOOL mCollapsible;
+
+};
+#endif // LL_CONTAINERVIEW_
diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp
index 6c92ea1ff7..8ecbdb98e1 100644
--- a/indra/llui/lldraghandle.cpp
+++ b/indra/llui/lldraghandle.cpp
@@ -43,10 +43,10 @@
 #include "llmenugl.h"
 #include "lltextbox.h"
 #include "llcontrol.h"
-#include "llresmgr.h"
 #include "llfontgl.h"
 #include "llwindow.h"
 #include "llfocusmgr.h"
+#include "lluictrlfactory.h"
 
 const S32 LEADING_PAD = 5;
 const S32 TITLE_PAD = 8;
@@ -56,21 +56,33 @@ const S32 RIGHT_PAD = BORDER_PAD + 32; // HACK: space for close btn and minimize
 
 S32 LLDragHandle::sSnapMargin = 5;
 
-LLDragHandle::LLDragHandle( const std::string& name, const LLRect& rect, const std::string& title )
-:	LLView( name, rect, TRUE ),
+LLDragHandle::LLDragHandle(const LLDragHandle::Params& p)
+:	LLView(p),
 	mDragLastScreenX( 0 ),
 	mDragLastScreenY( 0 ),
 	mLastMouseScreenX( 0 ),
 	mLastMouseScreenY( 0 ),
-	mDragHighlightColor(	LLUI::sColorsGroup->getColor( "DefaultHighlightLight" ) ),
-	mDragShadowColor(		LLUI::sColorsGroup->getColor( "DefaultShadowDark" ) ),
 	mTitleBox( NULL ),
 	mMaxTitleWidth( 0 ),
-	mForeground( TRUE )
+	mForeground( TRUE ),
+	mDragHighlightColor(p.drag_highlight_color()),
+	mDragShadowColor(p.drag_shadow_color())
+
 {
-	sSnapMargin = LLUI::sConfigGroup->getS32("SnapMargin");
+	static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
+	sSnapMargin = snap_margin;
+}
 
-	setSaveToXML(false);
+LLDragHandle::~LLDragHandle()
+{
+	removeChild(mTitleBox);
+	delete mTitleBox;
+}
+
+void LLDragHandle::initFromParams(const LLDragHandle::Params& p)
+{
+	LLView::initFromParams(p);
+	setTitle( p.label );
 }
 
 void LLDragHandle::setTitleVisible(BOOL visible) 
@@ -81,58 +93,47 @@ void LLDragHandle::setTitleVisible(BOOL visible)
 	}
 }
 
-void LLDragHandle::setTitleBox(LLTextBox* titlebox)
-{	
+void LLDragHandleTop::setTitle(const std::string& title)
+{
+	std::string trimmed_title = title;
+	LLStringUtil::trim(trimmed_title);
+
 	if( mTitleBox )
 	{
-		removeChild(mTitleBox);
-		delete mTitleBox;
+		mTitleBox->setText(trimmed_title);
 	}
-	mTitleBox = titlebox;
-	if(mTitleBox)
+	else
 	{
+		const LLFontGL* font = LLFontGL::getFontSansSerif();
+		LLTextBox::Params params;
+		params.name("Drag Handle Title");
+		params.rect(getRect());
+		params.text(trimmed_title);
+		params.font(font);
+		params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
+		params.font_shadow(LLFontGL::DROP_SHADOW_SOFT);
+		mTitleBox = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild( mTitleBox );
 	}
-}
-
-LLDragHandleTop::LLDragHandleTop(const std::string& name, const LLRect &rect, const std::string& title)
-:	LLDragHandle(name, rect, title)
-{
-	setFollowsAll();
-	setTitle( title );
-}
-
-LLDragHandleLeft::LLDragHandleLeft(const std::string& name, const LLRect &rect, const std::string& title)
-:	LLDragHandle(name, rect, title)
-{
-	setFollowsAll();
-	setTitle( title );
-}
-
-void LLDragHandleTop::setTitle(const std::string& title)
-{
-	std::string trimmed_title = title;
-	LLStringUtil::trim(trimmed_title);
-
-	const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF );
-	LLTextBox* titlebox = new LLTextBox( std::string("Drag Handle Title"), getRect(), trimmed_title, font );
-	titlebox->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
-	titlebox->setFontStyle(LLFontGL::DROP_SHADOW_SOFT);
 	
-	setTitleBox(titlebox);
 	reshapeTitleBox();
 }
 
 
 const std::string& LLDragHandleTop::getTitle() const
 {
-	return getTitleBox() == NULL ? LLStringUtil::null : getTitleBox()->getText();
+	return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText();
 }
 
 
 void LLDragHandleLeft::setTitle(const std::string& )
 {
-	setTitleBox(NULL);
+	if( mTitleBox )
+	{
+		removeChild(mTitleBox);
+		delete mTitleBox;
+		mTitleBox = NULL;
+	}
 	/* no title on left edge */
 }
 
@@ -184,9 +185,9 @@ void LLDragHandleTop::draw()
 	*/
 
 	// Colorize the text to match the frontmost state
-	if (getTitleBox())
+	if (mTitleBox)
 	{
-		getTitleBox()->setEnabled(getForeground());
+		mTitleBox->setEnabled(getForeground());
 	}
 
 	LLView::draw();
@@ -229,9 +230,9 @@ void LLDragHandleLeft::draw()
 	*/
 
 	// Colorize the text to match the frontmost state
-	if (getTitleBox())
+	if (mTitleBox)
 	{
-		getTitleBox()->setEnabled(getForeground());
+		mTitleBox->setEnabled(getForeground());
 	}
 
 	LLView::draw();
@@ -239,12 +240,12 @@ void LLDragHandleLeft::draw()
 
 void LLDragHandleTop::reshapeTitleBox()
 {
-	if( ! getTitleBox())
+	if( ! mTitleBox)
 	{
 		return;
 	}
-	const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF );
-	S32 title_width = font->getWidth( getTitleBox()->getText() ) + TITLE_PAD;
+	const LLFontGL* font = LLFontGL::getFontSansSerif();
+	S32 title_width = font->getWidth( mTitleBox->getText() ) + TITLE_PAD;
 	if (getMaxTitleWidth() > 0)
 		title_width = llmin(title_width, getMaxTitleWidth());
 	S32 title_height = llround(font->getLineHeight());
@@ -255,7 +256,7 @@ void LLDragHandleTop::reshapeTitleBox()
 		getRect().getWidth() - LEFT_PAD - RIGHT_PAD,
 		title_height);
 
-	getTitleBox()->setRect( title_rect );
+	mTitleBox->setRect( title_rect );
 }
 
 void LLDragHandleTop::reshape(S32 width, S32 height, BOOL called_from_parent)
@@ -337,14 +338,14 @@ BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask)
 
 		LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin);
 
-		getParent()->snappedTo(snap_view);
+		getParent()->setSnappedTo(snap_view);
 		delta_x = new_rect.mLeft - pre_snap_x;
 		delta_y = new_rect.mBottom - pre_snap_y;
 		translated_rect.translate(delta_x, delta_y);
 
 		// restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc
 		getParent()->setRect(original_rect);
-		getParent()->userSetShape(translated_rect);
+		getParent()->setShape(translated_rect, true);
 
 		mDragLastScreenX += delta_x;
 		mDragLastScreenY += delta_y;
diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h
index 9eb3e55a6c..8b53c46ae9 100644
--- a/indra/llui/lldraghandle.h
+++ b/indra/llui/lldraghandle.h
@@ -45,8 +45,24 @@ class LLTextBox;
 class LLDragHandle : public LLView
 {
 public:
-	LLDragHandle(const std::string& name, const LLRect& rect, const std::string& title );
-	virtual ~LLDragHandle() { setTitleBox(NULL); }
+	struct Params 
+	:	public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<std::string> label;
+		Optional<LLUIColor> drag_highlight_color;
+		Optional<LLUIColor> drag_shadow_color;
+		
+		Params() 
+		:	drag_highlight_color("", LLUI::getCachedColorFunctor("DefaultHighlightLight")),
+			drag_shadow_color("", LLUI::getCachedColorFunctor("DefaultShadowDark"))
+		{
+			mouse_opaque(true);
+			follows.flags(FOLLOWS_ALL);
+		}
+	};
+	void initFromParams(const Params&);
+	
+	virtual ~LLDragHandle();
 
 	virtual void setValue(const LLSD& value);
 
@@ -64,18 +80,20 @@ public:
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
 
 protected:
-	LLTextBox*		getTitleBox() const { return mTitleBox; }
-	void			setTitleBox(LLTextBox*);
-
+	LLDragHandle(const Params&);
+	friend class LLUICtrlFactory;
+	
+protected:
+	LLTextBox*		mTitleBox;
+	
 private:
 	S32				mDragLastScreenX;
 	S32				mDragLastScreenY;
 	S32				mLastMouseScreenX;
 	S32				mLastMouseScreenY;
 	LLCoordGL		mLastMouseDir;
-	LLColor4		mDragHighlightColor;
-	LLColor4		mDragShadowColor;
-	LLTextBox*		mTitleBox;
+	LLUIColor		mDragHighlightColor;
+	LLUIColor		mDragShadowColor;
 	S32				mMaxTitleWidth;
 	BOOL			mForeground;
 
@@ -88,9 +106,10 @@ private:
 class LLDragHandleTop
 : public LLDragHandle
 {
+protected:
+	LLDragHandleTop(const Params& p) : LLDragHandle(p) {}
+	friend class LLUICtrlFactory;
 public:
-	LLDragHandleTop(const std::string& name, const LLRect& rect, const std::string& title );
-
 	virtual void	setTitle( const std::string& title );
 	virtual const std::string& getTitle() const;
 	virtual void	draw();
@@ -105,9 +124,10 @@ private:
 class LLDragHandleLeft
 : public LLDragHandle
 {
+protected:
+	LLDragHandleLeft(const Params& p) : LLDragHandle(p) {}
+	friend class LLUICtrlFactory;
 public:
-	LLDragHandleLeft(const std::string& name, const LLRect& rect, const std::string& title );
-
 	virtual void	setTitle( const std::string& title );
 	virtual const std::string& getTitle() const;
 	virtual void	draw();
diff --git a/indra/llui/llf32uictrl.cpp b/indra/llui/llf32uictrl.cpp
new file mode 100644
index 0000000000..0978005b78
--- /dev/null
+++ b/indra/llui/llf32uictrl.cpp
@@ -0,0 +1,57 @@
+/**
+ * @file   llf32uictrl.cpp
+ * @author Nat Goodspeed
+ * @date   2008-09-08
+ * @brief  Implementation for llf32uictrl.
+ * 
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llf32uictrl.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+LLF32UICtrl::LLF32UICtrl(const Params& p)
+:	LLUICtrl(p),
+	mInitialValue(p.initial_value().asReal()),
+	mMinValue(p.min_value),
+	mMaxValue(p.max_value),
+    mIncrement(p.increment)
+{
+	mViewModel->setValue(p.initial_value);
+}
+
+F32 LLF32UICtrl::getValueF32() const
+{
+    return mViewModel->getValue().asReal();
+}
diff --git a/indra/llui/llf32uictrl.h b/indra/llui/llf32uictrl.h
new file mode 100644
index 0000000000..0a54fe761b
--- /dev/null
+++ b/indra/llui/llf32uictrl.h
@@ -0,0 +1,83 @@
+/**
+ * @file   llf32uictrl.h
+ * @author Nat Goodspeed
+ * @date   2008-09-08
+ * @brief  Base class for float-valued LLUICtrl widgets
+ * 
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLF32UICTRL_H)
+#define LL_LLF32UICTRL_H
+
+#include "lluictrl.h"
+
+class LLF32UICtrl: public LLUICtrl
+{
+public:
+    struct Params: public LLInitParam::Block<Params, LLUICtrl::Params>
+    {
+		Optional<F32>	min_value,
+						max_value,
+						increment;
+
+		Params()
+		:	min_value("min_val", 0.f),
+			max_value("max_val", 1.f),
+			increment("increment", 0.1f)
+        {}			
+    };
+
+protected:
+    LLF32UICtrl(const Params& p);
+
+public:
+	virtual F32		getValueF32() const;
+
+	virtual void	setValue(const LLSD& value ) { mViewModel->setValue(value); }
+	virtual LLSD	getValue() const		{ return LLSD(getValueF32()); }
+
+	virtual void	setMinValue(const LLSD& min_value)	{ setMinValue((F32)min_value.asReal()); }
+	virtual void	setMaxValue(const LLSD& max_value)	{ setMaxValue((F32)max_value.asReal()); }
+
+	virtual F32		getInitialValue() const { return mInitialValue; }
+	virtual F32		getMinValue() const		{ return mMinValue; }
+	virtual F32		getMaxValue() const		{ return mMaxValue; }
+	virtual F32		getIncrement() const	{ return mIncrement; }
+	virtual void	setMinValue(F32 min_value) { mMinValue = min_value; }
+	virtual void	setMaxValue(F32 max_value) { mMaxValue = max_value; }
+	virtual void	setIncrement(F32 increment) { mIncrement = increment;}
+
+protected:
+	F32				mInitialValue;
+	F32				mMinValue;
+	F32				mMaxValue;
+	F32				mIncrement;
+};
+
+#endif /* ! defined(LL_LLF32UICTRL_H) */
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 21f8f6e5f7..be7e050b58 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -43,11 +43,13 @@
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "lldraghandle.h"
+#include "llfloaterreg.h"
 #include "llfocusmgr.h"
 #include "llresizebar.h"
 #include "llresizehandle.h"
 #include "llkeyboard.h"
 #include "llmenugl.h"	// MENU_BAR_HEIGHT
+#include "llmodaldialog.h"
 #include "lltextbox.h"
 #include "llresmgr.h"
 #include "llui.h"
@@ -56,37 +58,37 @@
 #include "llcontrol.h"
 #include "lltabcontainer.h"
 #include "v2math.h"
+#include "lltrans.h"
+#include "llmultifloater.h"
 
-const S32 MINIMIZED_WIDTH = 160;
-const S32 CLOSE_BOX_FROM_TOP = 1;
 // use this to control "jumping" behavior when Ctrl-Tabbing
 const S32 TABBED_FLOATER_OFFSET = 0;
 
 std::string	LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = 
 {
-	"UIImgBtnCloseActiveUUID",		//BUTTON_CLOSE
-	"UIImgBtnRestoreActiveUUID",	//BUTTON_RESTORE
-	"UIImgBtnMinimizeActiveUUID",	//BUTTON_MINIMIZE
-	"UIImgBtnTearOffActiveUUID",	//BUTTON_TEAR_OFF
-	"UIImgBtnCloseActiveUUID",		//BUTTON_EDIT
+	"closebox.tga",		//BUTTON_CLOSE
+	"restore.tga",	//BUTTON_RESTORE
+	"minimize.tga",	//BUTTON_MINIMIZE
+	"tearoffbox.tga",	//BUTTON_TEAR_OFF
+	"closebox.tga",		//BUTTON_EDIT
 };
 
 std::string	LLFloater::sButtonInactiveImageNames[BUTTON_COUNT] = 
 {
-	"UIImgBtnCloseInactiveUUID",	//BUTTON_CLOSE
-	"UIImgBtnRestoreInactiveUUID",	//BUTTON_RESTORE
-	"UIImgBtnMinimizeInactiveUUID",	//BUTTON_MINIMIZE
-	"UIImgBtnTearOffInactiveUUID",	//BUTTON_TEAR_OFF
-	"UIImgBtnCloseInactiveUUID",	//BUTTON_EDIT
+	"close_inactive_blue.tga",	//BUTTON_CLOSE
+	"restore_inactive.tga",	//BUTTON_RESTORE
+	"minimize_inactive.tga",	//BUTTON_MINIMIZE
+	"tearoffbox.tga",	//BUTTON_TEAR_OFF
+	"close_inactive_blue.tga",	//BUTTON_EDIT
 };
 
 std::string	LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = 
 {
-	"UIImgBtnClosePressedUUID",		//BUTTON_CLOSE
-	"UIImgBtnRestorePressedUUID",	//BUTTON_RESTORE
-	"UIImgBtnMinimizePressedUUID",	//BUTTON_MINIMIZE
-	"UIImgBtnTearOffPressedUUID",	//BUTTON_TEAR_OFF
-	"UIImgBtnClosePressedUUID",		//BUTTON_EDIT
+	"close_in_blue.tga",		//BUTTON_CLOSE
+	"restore_pressed.tga",	//BUTTON_RESTORE
+	"minimize_pressed.tga",	//BUTTON_MINIMIZE
+	"tearoff_pressed.tga",	//BUTTON_TEAR_OFF
+	"close_in_blue.tga",		//BUTTON_EDIT
 };
 
 std::string	LLFloater::sButtonNames[BUTTON_COUNT] = 
@@ -98,17 +100,20 @@ std::string	LLFloater::sButtonNames[BUTTON_COUNT] =
 	"llfloater_edit_btn",		//BUTTON_EDIT
 };
 
-std::string	LLFloater::sButtonToolTips[BUTTON_COUNT] = 
+std::string LLFloater::sButtonToolTips[BUTTON_COUNT] = {};
+
+
+std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]=
 {
 #ifdef LL_DARWIN
-	"Close (Cmd-W)",	//BUTTON_CLOSE
+	"BUTTON_CLOSE_DARWIN",//LLTrans::getString("BUTTON_CLOSE_DARWIN"), //"Close (Cmd-W)",	//BUTTON_CLOSE
 #else
-	"Close (Ctrl-W)",	//BUTTON_CLOSE
+	"BUTTON_CLOSE_WIN", //LLTrans::getString("BUTTON_CLOSE_WIN"), //"Close (Ctrl-W)",	//BUTTON_CLOSE
 #endif
-	"Restore",	//BUTTON_RESTORE
-	"Minimize",	//BUTTON_MINIMIZE
-	"Tear Off",	//BUTTON_TEAR_OFF
-	"Edit",		//BUTTON_EDIT
+	"BUTTON_RESTORE",//LLTrans::getString("BUTTON_RESTORE"), //"Restore",	//BUTTON_RESTORE
+	"BUTTON_MINIMIZE",//LLTrans::getString("BUTTON_MINIMIZE"),	//"Minimize",	//BUTTON_MINIMIZE
+	"BUTTON_TEAR_OFF",//LLTrans::getString("BUTTON_TEAR_OFF"),	//"Tear Off",	//BUTTON_TEAR_OFF
+	"BUTTON_EDIT", //LLTrans::getString("BUTTON_EDIT"), //	"Edit",		//BUTTON_EDIT
 };
 
 LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
@@ -126,59 +131,118 @@ LLFloater::handle_map_t	LLFloater::sFloaterMap;
 
 LLFloaterView* gFloaterView = NULL;
 
-LLFloater::LLFloater() :
-	//FIXME: we should initialize *all* member variables here
-	LLPanel(), mAutoFocus(TRUE),
-	mResizable(FALSE),
-	mDragOnLeft(FALSE),
-	mMinWidth(0),
-	mMinHeight(0)
-{
-	// automatically take focus when opened
-	mAutoFocus = TRUE;
+//static
+bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
+{
+	if (a.type() != b.type())
+	{
+		//llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl;
+		return false;
+	}
+	else if (a.isUndefined())
+		return false;
+	else if (a.isInteger())
+		return a.asInteger() < b.asInteger();
+	else if (a.isReal())
+		return a.asReal() < b.asReal();
+	else if (a.isString())
+		return a.asString() < b.asString();
+	else if (a.isUUID())
+		return a.asUUID() < b.asUUID();
+	else if (a.isDate())
+		return a.asDate() < b.asDate();
+	else if (a.isURI())
+		return a.asString() < b.asString(); // compare URIs as strings
+	else if (a.isBoolean())
+		return a.asBoolean() < b.asBoolean();
+	else
+		return false; // no valid operation for Binary
+}
+
+bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
+{
+	if (a.type() != b.type())
+	{
+		//llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl;
+		return false;
+	}
+	else if (a.isUndefined())
+		return true;
+	else if (a.isInteger())
+		return a.asInteger() == b.asInteger();
+	else if (a.isReal())
+		return a.asReal() == b.asReal();
+	else if (a.isString())
+		return a.asString() == b.asString();
+	else if (a.isUUID())
+		return a.asUUID() == b.asUUID();
+	else if (a.isDate())
+		return a.asDate() == b.asDate();
+	else if (a.isURI())
+		return a.asString() == b.asString(); // compare URIs as strings
+	else if (a.isBoolean())
+		return a.asBoolean() == b.asBoolean();
+	else
+		return false; // no valid operation for Binary
+}
+
+//************************************
+
+LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
+	:	LLPanel(),
+		mDragHandle(NULL),
+		mTitle(p.title),
+		mShortTitle(p.short_title),
+		mSingleInstance(p.single_instance),
+		mKey(key),
+		mAutoTile(p.auto_tile),
+		mCanTearOff(p.can_tear_off),
+		mCanMinimize(p.can_minimize),
+		mCanClose(p.can_close),
+		mDragOnLeft(p.can_drag_on_left),
+		mResizable(p.can_resize),
+		mMinWidth(p.min_width),
+		mMinHeight(p.min_height),
+		mMinimized(FALSE),
+		mForeground(FALSE),
+		mFirstLook(TRUE),
+		mEditing(FALSE),
+		mButtonScale(1.0f),
+		mAutoFocus(TRUE), // automatically take focus when opened
+		mHasBeenDraggedWhileMinimized(FALSE),
+		mPreviousMinimizedBottom(0),
+		mPreviousMinimizedLeft(0),
+		mNotificationContext(NULL)
+{
+	static LLUICachedControl<LLColor4> default_background_color ("FloaterDefaultBackgroundColor", *(new LLColor4));
+	static LLUICachedControl<LLColor4> focus_background_color ("FloaterFocusBackgroundColor", *(new LLColor4));
+	
 	for (S32 i = 0; i < BUTTON_COUNT; i++)
 	{
-		mButtonsEnabled[i] = FALSE;
-		mButtons[i] = NULL;
-	}
-	for (S32 i = 0; i < 4; i++) 
-	{
-		mResizeBar[i] = NULL; 
-		mResizeHandle[i] = NULL;
+		sButtonToolTips[i] =LLTrans::getString( sButtonToolTipsIndex[i]);
 	}
-	mDragHandle = NULL;
+	
 	mHandle.bind(this);
 	mNotificationContext = new LLFloaterNotificationContext(getHandle());
-}
+	mBgColorAlpha        = default_background_color;
+	mBgColorOpaque       = focus_background_color;
 
-LLFloater::LLFloater(const std::string& name)
-:	LLPanel(name), mAutoFocus(TRUE) // automatically take focus when opened
-{
-	for (S32 i = 0; i < BUTTON_COUNT; i++)
-	{
-		mButtonsEnabled[i] = FALSE;
-		mButtons[i] = NULL;
-	}
 	for (S32 i = 0; i < 4; i++) 
 	{
-		mResizeBar[i] = NULL; 
+		mResizeBar[i] = NULL;
 		mResizeHandle[i] = NULL;
 	}
-	std::string title; // null string
-	initFloater(title, FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, TRUE, TRUE); // defaults
-}
 
+	// Clicks stop here.
+	setMouseOpaque(TRUE);
+	
+	// Floaters always draw their background, unlike every other panel.
+	setBackgroundVisible(TRUE);
 
-LLFloater::LLFloater(const std::string& name, const LLRect& rect, const std::string& title, 
-	BOOL resizable, 
-	S32 min_width, 
-	S32 min_height,
-	BOOL drag_on_left,
-	BOOL minimizable,
-	BOOL close_btn,
-	BOOL bordered)
-:	LLPanel(name, rect, bordered), mAutoFocus(TRUE) // automatically take focus when opened
-{
+	// Floaters start not minimized.  When minimized, they save their
+	// prior rectangle to be used on restore.
+	mExpandedRect.set(0,0,0,0);
+	
 	for (S32 i = 0; i < BUTTON_COUNT; i++)
 	{
 		mButtonsEnabled[i] = FALSE;
@@ -189,259 +253,176 @@ LLFloater::LLFloater(const std::string& name, const LLRect& rect, const std::str
 		mResizeBar[i] = NULL; 
 		mResizeHandle[i] = NULL;
 	}
-	initFloater( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn);
-}
+	
+	initFromParams(p);
+	
+	// chrome floaters don't take focus at all
+	setFocusRoot(!getIsChrome());
 
-LLFloater::LLFloater(const std::string& name, const std::string& rect_control, const std::string& title, 
-	BOOL resizable, 
-	S32 min_width, 
-	S32 min_height,
-	BOOL drag_on_left,
-	BOOL minimizable,
-	BOOL close_btn,
-	BOOL bordered)
-:	LLPanel(name, rect_control, bordered), mAutoFocus(TRUE) // automatically take focus when opened
-{
-	for (S32 i = 0; i < BUTTON_COUNT; i++)
-	{
-		mButtonsEnabled[i] = FALSE;
-		mButtons[i] = NULL;
-	}
-	for (S32 i = 0; i < 4; i++) 
-	{
-		mResizeBar[i] = NULL; 
-		mResizeHandle[i] = NULL;
-	}
-	initFloater( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn);
+	initFloater();
 }
 
-
 // Note: Floaters constructed from XML call init() twice!
-void LLFloater::initFloater(const std::string& title,
-					 BOOL resizable, S32 min_width, S32 min_height,
-					 BOOL drag_on_left, BOOL minimizable, BOOL close_btn)
+void LLFloater::initFloater()
 {
-	mHandle.bind(this);
-	mNotificationContext = new LLFloaterNotificationContext(getHandle());
-
-	// Init function can be called more than once, so clear out old data.
-	for (S32 i = 0; i < BUTTON_COUNT; i++)
-	{
-		mButtonsEnabled[i] = FALSE;
-		if (mButtons[i] != NULL)
-		{
-			removeChild(mButtons[i]);
-			delete mButtons[i];
-			mButtons[i] = NULL;
-		}
-	}
-	mButtonScale = 1.f;
+	addDragHandle();
+	
+	addResizeCtrls();
 
-	//sjb: Thia is a bit of a hack:
-	BOOL need_border = hasBorder();
-	// remove the border since deleteAllChildren() will also delete the border (but not clear mBorder)
-	removeBorder();
-	// this will delete mBorder too
-	deleteAllChildren();
-	// add the border back if we want it
-	if (need_border)
+	// Close button.
+	if (mCanClose)
 	{
-	    addBorder();
+		mButtonsEnabled[BUTTON_CLOSE] = TRUE;
 	}
 
-	// chrome floaters don't take focus at all
-	setFocusRoot(!getIsChrome());
-
-	// Reset cached pointers
-	mDragHandle = NULL;
-	for (S32 i = 0; i < 4; i++) 
+	// Minimize button only for top draggers
+	if ( !mDragOnLeft && mCanMinimize )
 	{
-		mResizeBar[i] = NULL;
-		mResizeHandle[i] = NULL;
+		mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
 	}
-	mCanTearOff = TRUE;
-	mEditing = FALSE;
 
-	// Clicks stop here.
-	setMouseOpaque(TRUE);
+	buildButtons();
 
-	mFirstLook = TRUE;
-	mForeground = FALSE;
-	mDragOnLeft = drag_on_left == TRUE;
+	// Floaters are created in the invisible state	
+	setVisible(FALSE);
 
-	// Floaters always draw their background, unlike every other panel.
-	setBackgroundVisible(TRUE);
+	// add self to handle->floater map
+	sFloaterMap[mHandle] = this;
 
-	// Floaters start not minimized.  When minimized, they save their
-	// prior rectangle to be used on restore.
-	mMinimized = FALSE;
-	mExpandedRect.set(0,0,0,0);
-	
-	S32 close_pad;			// space to the right of close box
-	S32 close_box_size;		// For layout purposes, how big is the close box?
-	if (close_btn)
-	{
-		close_box_size = LLFLOATER_CLOSE_BOX_SIZE;
-		close_pad = 0;
-	}
-	else
+	if (!getParent())
 	{
-		close_box_size = 0;
-		close_pad = 0;
+		gFloaterView->addChild(this);
 	}
+}
 
-	S32 minimize_box_size;
-	S32 minimize_pad;
-	if (minimizable && !drag_on_left)
-	{
-		minimize_box_size = LLFLOATER_CLOSE_BOX_SIZE;
-		minimize_pad = 0;
-	}
-	else
+void LLFloater::addDragHandle()
+{
+	static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+	S32 close_box_size = mCanClose ? floater_close_box_size : 0;
+	
+	if (!mDragHandle)
 	{
-		minimize_box_size = 0;
-		minimize_pad = 0;
+		if (mDragOnLeft)
+		{
+			LLDragHandleLeft::Params p;
+			p.name("drag");
+			p.follows.flags(FOLLOWS_ALL);
+			p.label(mTitle);
+			mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p);
+		}
+		else // drag on top
+		{
+			LLDragHandleTop::Params p;
+			p.name("Drag Handle");
+			p.follows.flags(FOLLOWS_ALL);
+			p.label(mTitle);
+			mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p);
+		}
+		addChild(mDragHandle);
 	}
-
-	// Drag Handle
-	// Add first so it's in the background.
-//	const S32 drag_pad = 2;
-	if (drag_on_left)
+	LLRect rect;
+	if (mDragOnLeft)
 	{
-		LLRect drag_handle_rect;
-		drag_handle_rect.setOriginAndSize(
-			0, 0,
-			DRAG_HANDLE_WIDTH,
-			getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
-		mDragHandle = new LLDragHandleLeft(std::string("drag"), drag_handle_rect, title );
+		rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
 	}
 	else // drag on top
 	{
-		LLRect drag_handle_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
-		mDragHandle = new LLDragHandleTop( std::string("Drag Handle"), drag_handle_rect, title );
-	}
-	addChild(mDragHandle);
-
-	// Resize Handle
-	mResizable = resizable;
-	mMinWidth = min_width;
-	mMinHeight = min_height;
-
-	if( mResizable )
-	{
-		// Resize bars (sides)
-		const S32 RESIZE_BAR_THICKNESS = 3;
-		mResizeBar[LLResizeBar::LEFT] = new LLResizeBar( 
-			std::string("resizebar_left"),
-			this,
-			LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0), 
-			min_width, S32_MAX, LLResizeBar::LEFT );
-		addChild( mResizeBar[0] );
-
-		mResizeBar[LLResizeBar::TOP] = new LLResizeBar( 
-			std::string("resizebar_top"),
-			this,
-			LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS), 
-			min_height, S32_MAX, LLResizeBar::TOP );
-		addChild( mResizeBar[1] );
-
-		mResizeBar[LLResizeBar::RIGHT] = new LLResizeBar( 
-			std::string("resizebar_right"),
-			this,
-			LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0), 
-			min_width, S32_MAX, LLResizeBar::RIGHT );
-		addChild( mResizeBar[2] );
-
-		mResizeBar[LLResizeBar::BOTTOM] = new LLResizeBar( 
-			std::string("resizebar_bottom"),
-			this,
-			LLRect( 0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0), 
-			min_height, S32_MAX, LLResizeBar::BOTTOM );
-		addChild( mResizeBar[3] );
-
-
-		// Resize handles (corners)
-		mResizeHandle[0] = new LLResizeHandle( 
-			std::string("Resize Handle"),
-			LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0),
-			min_width,
-			min_height,
-			LLResizeHandle::RIGHT_BOTTOM);
-		addChild(mResizeHandle[0]);
-
-		mResizeHandle[1] = new LLResizeHandle(
-			std::string("resize"), 
-			LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT),
-			min_width,
-			min_height,
-			LLResizeHandle::RIGHT_TOP );
-		addChild(mResizeHandle[1]);
-		
-		mResizeHandle[2] = new LLResizeHandle( std::string("resize"), 
-											   LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ),
-											   min_width,
-											   min_height,
-											   LLResizeHandle::LEFT_BOTTOM );
-		addChild(mResizeHandle[2]);
-
-		mResizeHandle[3] = new LLResizeHandle( std::string("resize"), 
-			LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ),
-			min_width,
-			min_height,
-			LLResizeHandle::LEFT_TOP );
-		addChild(mResizeHandle[3]);
+		rect = getLocalRect();
 	}
+	mDragHandle->setRect(rect);
+	updateButtons();
+	applyTitle();
+}
 
-	// Close button.
-	if (close_btn)
+void LLFloater::addResizeCtrls()
+{
+	for (S32 i = 0; i < 4; i++) 
 	{
-		mButtonsEnabled[BUTTON_CLOSE] = TRUE;
+		if (mResizeBar[i])
+		{
+			removeChild(mResizeBar[i]);
+			delete mResizeBar[i];
+			mResizeBar[i] = NULL;
+		}
+		if (mResizeHandle[i])
+		{
+			removeChild(mResizeHandle[i]);
+			delete mResizeHandle[i];
+			mResizeHandle[i] = NULL;
+		}
 	}
-
-	// Minimize button only for top draggers
-	if ( !drag_on_left && minimizable )
+	if( !mResizable )
 	{
-		mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
+		return;
 	}
+	
+	// Resize bars (sides)
+	const S32 RESIZE_BAR_THICKNESS = 3;
+	LLResizeBar::Params p;
+	p.name("resizebar_left");
+	p.resizing_view(this);
+	p.rect(LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0));
+	p.min_size(mMinWidth);
+	p.side(LLResizeBar::LEFT);
+	mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p);
+	addChild( mResizeBar[LLResizeBar::LEFT] );
+
+	p.name("resizebar_top");
+	p.rect(LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS));
+	p.min_size(mMinHeight);
+	p.side(LLResizeBar::TOP);
+
+	mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create<LLResizeBar>(p);
+	addChild( mResizeBar[LLResizeBar::TOP] );
+
+	p.name("resizebar_right");
+	p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0));
+	p.min_size(mMinWidth);
+	p.side(LLResizeBar::RIGHT);
+	
+	mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p);
+	addChild( mResizeBar[LLResizeBar::RIGHT] );
+
+	p.name("resizebar_bottom");
+	p.rect(LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0));
+	p.min_size(mMinHeight);
+	p.side(LLResizeBar::BOTTOM);
+	mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p);
+	addChild( mResizeBar[LLResizeBar::BOTTOM] );
+
+	// Resize handles (corners)
+	LLResizeHandle::Params handle_p;
+	handle_p.rect(LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0));
+	handle_p.min_width(mMinWidth);
+	handle_p.min_height(mMinHeight);
+	handle_p.corner(LLResizeHandle::RIGHT_BOTTOM);
+	mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+	addChild(mResizeHandle[0]);
+
+	handle_p.rect(LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT));
+	handle_p.corner(LLResizeHandle::RIGHT_TOP);
+	mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+	addChild(mResizeHandle[1]);
+	
+	handle_p.rect(LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ));
+	handle_p.corner(LLResizeHandle::LEFT_BOTTOM);
+	mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+	addChild(mResizeHandle[2]);
 
-	// Keep track of whether this window has ever been dragged while it
-	// was minimized.  If it has, we'll remember its position for the
-	// next time it's minimized.
-	mHasBeenDraggedWhileMinimized = FALSE;
-	mPreviousMinimizedLeft = 0;
-	mPreviousMinimizedBottom = 0;
-
-	buildButtons();
-
-	// JC - Don't do this here, because many floaters first construct themselves,
-	// then show themselves.  Put it in setVisibleAndFrontmost.
-	// make_ui_sound("UISndWindowOpen");
-
-	// RN: floaters are created in the invisible state	
-	setVisible(FALSE);
-
-	// add self to handle->floater map
-	sFloaterMap[mHandle] = this;
-
-	if (!getParent())
-	{
-		gFloaterView->addChild(this);
-	}
+	handle_p.rect(LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ));
+	handle_p.corner(LLResizeHandle::LEFT_TOP);
+	mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+	addChild(mResizeHandle[3]);
 }
 
 // virtual
 LLFloater::~LLFloater()
 {
+	LLFloaterReg::removeInstance(mInstanceName, mKey);
+	
 	delete mNotificationContext;
 	mNotificationContext = NULL;
 
-	control_map_t::iterator itor;
-	for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor)
-	{
-		delete itor->second;
-	}
-	mFloaterControls.clear();
-
 	//// am I not hosted by another floater?
 	//if (mHostHandle.isDead())
 	//{
@@ -469,8 +450,27 @@ LLFloater::~LLFloater()
 		delete mResizeBar[i];
 		delete mResizeHandle[i];
 	}
+
+	storeRectControl();
+	setVisible(false); // We're not visible if we're destroyed
+	storeVisibilityControl();
+}
+
+void LLFloater::storeRectControl()
+{
+	if( mRectControl.size() > 1 )
+	{
+		LLUI::sSettingGroups["floater"]->setRect( mRectControl, getRect() );
+	}
 }
 
+void LLFloater::storeVisibilityControl()
+{
+	if( mVisibilityControl.size() > 1 )
+	{
+		LLUI::sSettingGroups["floater"]->setBOOL( mVisibilityControl, getVisible() );
+	}
+}
 
 void LLFloater::setVisible( BOOL visible )
 {
@@ -504,10 +504,25 @@ void LLFloater::setVisible( BOOL visible )
 		}
 		++dependent_it;
 	}
+
+	storeVisibilityControl();
+}
+
+// virtual
+void LLFloater::onVisibilityChange ( BOOL new_visibility )
+{
+	if (new_visibility)
+	{
+		if (getHost())
+			getHost()->setFloaterFlashing(this, FALSE);
+	}
+	LLPanel::onVisibilityChange ( new_visibility );
 }
 
-void LLFloater::open()	/* Flawfinder: ignore */
+void LLFloater::openFloater(const LLSD& key)
 {
+	mKey = key; // in case we need to open ourselves again
+	
 	if (getSoundFlags() != SILENT 
 	// don't play open sound for hosted (tabbed) windows
 		&& !getHost() 
@@ -525,9 +540,11 @@ void LLFloater::open()	/* Flawfinder: ignore */
 		// only select tabs if window they are hosted in is visible
 		getFloaterHost()->addFloater(this, getFloaterHost()->getVisible());
 	}
-	else if (getHost() != NULL)
+
+	if (getHost() != NULL)
 	{
-		// already hosted
+		getHost()->setMinimized(FALSE);
+		getHost()->setVisibleAndFrontmost(mAutoFocus);
 		getHost()->showFloater(this);
 	}
 	else
@@ -536,10 +553,10 @@ void LLFloater::open()	/* Flawfinder: ignore */
 		setVisibleAndFrontmost(mAutoFocus);
 	}
 
-	onOpen();
+	onOpen(key);
 }
 
-void LLFloater::close(bool app_quitting)
+void LLFloater::closeFloater(bool app_quitting)
 {
 	// Always unminimize before trying to close.
 	// Most of the time the user will never see this state.
@@ -570,7 +587,7 @@ void LLFloater::close(bool app_quitting)
 			if (floaterp)
 			{
 				++dependent_it;
-				floaterp->close();
+				floaterp->closeFloater(app_quitting);
 			}
 			else
 			{
@@ -597,7 +614,7 @@ void LLFloater::close(bool app_quitting)
 				}
 			}
 		}
-
+		
 		// Let floater do cleanup.
 		onClose(app_quitting);
 	}
@@ -607,6 +624,7 @@ void LLFloater::close(bool app_quitting)
 void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
 	LLPanel::reshape(width, height, called_from_parent);
+	storeRectControl();
 }
 
 void LLFloater::releaseFocus()
@@ -664,15 +682,23 @@ void LLFloater::center()
 	centerWithin(gFloaterView->getRect());
 }
 
+LLMultiFloater* LLFloater::getHost()
+{ 
+	return (LLMultiFloater*)mHostHandle.get(); 
+}
+
 void LLFloater::applyRectControl()
 {
-	if (!getRectControl().empty())
+	if (mRectControl.size() > 1)
 	{
-		const LLRect& rect = LLUI::sConfigGroup->getRect(getRectControl());
-		translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom);
-		if (mResizable)
+		const LLRect& rect = LLUI::sSettingGroups["floater"]->getRect(mRectControl);
+		if (rect.getWidth() > 0 && rect.getHeight() > 0)
 		{
-			reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
+			translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom);
+			if (mResizable)
+			{
+				reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
+			}
 		}
 	}
 }
@@ -763,7 +789,7 @@ BOOL LLFloater::canSnapTo(const LLView* other_view)
 	return LLPanel::canSnapTo(other_view);
 }
 
-void LLFloater::snappedTo(const LLView* snap_view)
+void LLFloater::setSnappedTo(const LLView* snap_view)
 {
 	if (!snap_view || snap_view == getParent())
 	{
@@ -778,10 +804,10 @@ void LLFloater::snappedTo(const LLView* snap_view)
 	}
 }
 
-void LLFloater::userSetShape(const LLRect& new_rect)
+void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
 {
 	const LLRect old_rect = getRect();
-	LLView::userSetShape(new_rect);
+	LLView::handleReshape(new_rect, by_user);
 
 	// if not minimized, adjust all snapped dependents to new shape
 	if (!isMinimized())
@@ -816,7 +842,7 @@ void LLFloater::userSetShape(const LLRect& new_rect)
 				delta_y += new_rect.mBottom - old_rect.mBottom;
 
 				dependent_rect.translate(delta_x, delta_y);
-				floaterp->userSetShape(dependent_rect);
+				floaterp->setShape(dependent_rect, by_user);
 			}
 		}
 	}
@@ -834,6 +860,9 @@ void LLFloater::userSetShape(const LLRect& new_rect)
 
 void LLFloater::setMinimized(BOOL minimize)
 {
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
+
 	if (minimize == mMinimized) return;
 
 	if (minimize)
@@ -902,7 +931,7 @@ void LLFloater::setMinimized(BOOL minimize)
 		mMinimized = TRUE;
 
 		// Reshape *after* setting mMinimized
-		reshape( MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE, TRUE);
+		reshape( minimized_width, floater_header_size, TRUE);
 	}
 	else
 	{
@@ -995,6 +1024,13 @@ void LLFloater::setFocus( BOOL b )
 	}
 }
 
+// virtual
+void LLFloater::setRect(const LLRect &rect)
+{
+	LLPanel::setRect(rect);
+	addDragHandle(); // re-add drag handle, sized based on rect
+}
+
 // virtual
 void LLFloater::setIsChrome(BOOL is_chrome)
 {
@@ -1276,19 +1312,18 @@ void LLFloater::setEditModeEnabled(BOOL enable)
 
 
 // static
-void LLFloater::onClickMinimize(void *userdata)
+void LLFloater::onClickMinimize(LLFloater* self)
 {
-	LLFloater* self = (LLFloater*) userdata;
-	if (!self) return;
-
+	if (!self)
+		return;
 	self->setMinimized( !self->isMinimized() );
 }
 
-void LLFloater::onClickTearOff(void *userdata)
+void LLFloater::onClickTearOff(LLFloater* self)
 {
-	LLFloater* self = (LLFloater*) userdata;
-	if (!self) return;
-
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	if (!self)
+		return;
 	LLMultiFloater* host_floater = self->getHost();
 	if (host_floater) //Tear off
 	{
@@ -1297,12 +1332,12 @@ void LLFloater::onClickTearOff(void *userdata)
 		// reparent to floater view
 		gFloaterView->addChild(self);
 
-		self->open();	/* Flawfinder: ignore */
+		self->openFloater(self->getKey());
 		
 		// only force position for floaters that don't have that data saved
-		if (self->getRectControl().empty())
+		if (self->mRectControl.size() <= 1)
 		{
-			new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->getRect().getWidth(), self->getRect().getHeight());
+			new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight());
 			self->setRect(new_rect);
 		}
 		gFloaterView->adjustToFitScreen(self, FALSE);
@@ -1317,17 +1352,16 @@ void LLFloater::onClickTearOff(void *userdata)
 			self->setMinimized(FALSE); // to reenable minimize button if it was minimized
 			new_host->showFloater(self);
 			// make sure host is visible
-			new_host->open();
+			new_host->openFloater(new_host->getKey());
 		}
 	}
 }
 
 // static
-void LLFloater::onClickEdit(void *userdata)
+void LLFloater::onClickEdit(LLFloater* self)
 {
-	LLFloater* self = (LLFloater*) userdata;
-	if (!self) return;
-
+	if (!self)
+		return;
 	self->mEditing = self->mEditing ? FALSE : TRUE;
 }
 
@@ -1373,7 +1407,7 @@ void LLFloater::closeFocusedFloater()
 	LLFloater* floater_to_close = LLFloater::getClosableFloaterFromFocus();
 	if(floater_to_close)
 	{
-		floater_to_close->close();
+		floater_to_close->closeFloater();
 	}
 
 	// if nothing took focus after closing focused floater
@@ -1388,12 +1422,11 @@ void LLFloater::closeFocusedFloater()
 
 
 // static
-void LLFloater::onClickClose( void* userdata )
+void LLFloater::onClickClose( LLFloater* self )
 {
-	LLFloater* self = (LLFloater*) userdata;
-	if (!self) return;
-
-	self->close();
+	if (!self)
+		return;
+	self->closeFloater(false);
 }
 
 
@@ -1408,8 +1441,11 @@ void LLFloater::draw()
 		S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH;
 		S32 bottom = LLPANEL_BORDER_WIDTH;
 
-		LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow");
-		F32 shadow_offset = (F32)LLUI::sConfigGroup->getS32("DropShadowFloater");
+		static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0);
+		static LLUICachedControl<LLColor4> shadow_color_cached ("ColorDropShadow", *(new LLColor4));
+		LLColor4 shadow_color = shadow_color_cached;
+		F32 shadow_offset = (F32)shadow_offset_S32;
+
 		if (!isBackgroundOpaque())
 		{
 			shadow_offset *= 0.2f;
@@ -1422,20 +1458,21 @@ void LLFloater::draw()
 		// No transparent windows in simple UI
 		if (isBackgroundOpaque())
 		{
-			gl_rect_2d( left, top, right, bottom, getBackgroundColor() );
+			gl_rect_2d( left, top, right, bottom, mBgColorOpaque );
 		}
 		else
 		{
-			gl_rect_2d( left, top, right, bottom, getTransparentColor() );
+			gl_rect_2d( left, top, right, bottom, mBgColorAlpha );
 		}
 
 		if(gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() && !getCurrentTitle().empty())
 		{
+			static LLUICachedControl<LLColor4> titlebar_focus_color ("TitleBarFocusColor", *(new LLColor4));
 			// draw highlight on title bar to indicate focus.  RDW
-			const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF );
+			const LLFontGL* font = LLFontGL::getFontSansSerif();
 			LLRect r = getRect();
 			gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1, 
-				LLUI::sColorsGroup->getColor("TitleBarFocusColor"), 0, TRUE);
+				titlebar_focus_color, 0, TRUE);
 		}
 	}
 
@@ -1489,8 +1526,10 @@ void LLFloater::draw()
 	{
 		// add in a border to improve spacialized visual aclarity ;)
 		// use lines instead of gl_rect_2d so we can round the edges as per james' recommendation
+		static LLUICachedControl<LLColor4> focus_border_color ("FloaterFocusBorderColor", *(new LLColor4));
+		static LLUICachedControl<LLColor4> unfocus_border_color ("FloaterUnfocusBorderColor", *(new LLColor4));
 		LLUI::setLineWidth(1.5f);
-		LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? LLUI::sColorsGroup->getColor("FloaterFocusBorderColor") : LLUI::sColorsGroup->getColor("FloaterUnfocusBorderColor");
+		LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? focus_border_color() : unfocus_border_color;
 		gl_rect_2d_offset_local(0, getRect().getHeight() + 1, getRect().getWidth() + 1, 0, outlineColor, -LLPANEL_BORDER_WIDTH, FALSE);
 		LLUI::setLineWidth(1.f);
 	}
@@ -1511,6 +1550,7 @@ void	LLFloater::setCanMinimize(BOOL can_minimize)
 {
 	// if removing minimize/restore button programmatically,
 	// go ahead and unminimize floater
+	mCanMinimize = can_minimize;
 	if (!can_minimize)
 	{
 		setMinimized(FALSE);
@@ -1524,6 +1564,7 @@ void	LLFloater::setCanMinimize(BOOL can_minimize)
 
 void	LLFloater::setCanClose(BOOL can_close)
 {
+	mCanClose = can_close;
 	mButtonsEnabled[BUTTON_CLOSE] = can_close;
 
 	updateButtons();
@@ -1538,83 +1579,10 @@ void	LLFloater::setCanTearOff(BOOL can_tear_off)
 }
 
 
-void	LLFloater::setCanResize(BOOL can_resize)
+void LLFloater::setCanResize(BOOL can_resize)
 {
-	if (mResizable && !can_resize)
-	{
-		for (S32 i = 0; i < 4; i++) 
-		{
-			removeChild(mResizeBar[i], TRUE);
-			mResizeBar[i] = NULL; 
-
-			removeChild(mResizeHandle[i], TRUE);
-			mResizeHandle[i] = NULL;
-		}
-	}
-	else if (!mResizable && can_resize)
-	{
-		// Resize bars (sides)
-		const S32 RESIZE_BAR_THICKNESS = 3;
-		mResizeBar[0] = new LLResizeBar( 
-			std::string("resizebar_left"),
-			this,
-			LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0), 
-			mMinWidth, S32_MAX, LLResizeBar::LEFT );
-		addChild( mResizeBar[0] );
-
-		mResizeBar[1] = new LLResizeBar( 
-			std::string("resizebar_top"),
-			this,
-			LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS), 
-			mMinHeight, S32_MAX, LLResizeBar::TOP );
-		addChild( mResizeBar[1] );
-
-		mResizeBar[2] = new LLResizeBar( 
-			std::string("resizebar_right"),
-			this,
-			LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0), 
-			mMinWidth, S32_MAX, LLResizeBar::RIGHT );
-		addChild( mResizeBar[2] );
-
-		mResizeBar[3] = new LLResizeBar( 
-			std::string("resizebar_bottom"),
-			this,
-			LLRect( 0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0), 
-			mMinHeight, S32_MAX, LLResizeBar::BOTTOM );
-		addChild( mResizeBar[3] );
-
-
-		// Resize handles (corners)
-		mResizeHandle[0] = new LLResizeHandle( 
-			std::string("Resize Handle"),
-			LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0),
-			mMinWidth,
-			mMinHeight,
-			LLResizeHandle::RIGHT_BOTTOM);
-		addChild(mResizeHandle[0]);
-
-		mResizeHandle[1] = new LLResizeHandle( std::string("resize"), 
-			LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT),
-			mMinWidth,
-			mMinHeight,
-			LLResizeHandle::RIGHT_TOP );
-		addChild(mResizeHandle[1]);
-		
-		mResizeHandle[2] = new LLResizeHandle( std::string("resize"), 
-											   LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ),
-											   mMinWidth,
-											   mMinHeight,
-											   LLResizeHandle::LEFT_BOTTOM );
-		addChild(mResizeHandle[2]);
-
-		mResizeHandle[3] = new LLResizeHandle( std::string("resize"), 
-			LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ),
-			mMinWidth,
-			mMinHeight,
-			LLResizeHandle::LEFT_TOP );
-		addChild(mResizeHandle[3]);
-	}
 	mResizable = can_resize;
+	addResizeCtrls();
 }
 
 void LLFloater::setCanDrag(BOOL can_drag)
@@ -1633,6 +1601,8 @@ void LLFloater::setCanDrag(BOOL can_drag)
 
 void LLFloater::updateButtons()
 {
+	static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+	static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
 	S32 button_count = 0;
 	for (S32 i = 0; i < BUTTON_COUNT; i++)
 	{
@@ -1652,17 +1622,17 @@ void LLFloater::updateButtons()
 			{
 				btn_rect.setLeftTopAndSize(
 					LLPANEL_BORDER_WIDTH,
-					getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count,
-					llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
-					llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
+					getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count,
+					llround((F32)floater_close_box_size * mButtonScale),
+					llround((F32)floater_close_box_size * mButtonScale));
 			}
 			else
 			{
 				btn_rect.setLeftTopAndSize(
-					getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count,
-					getRect().getHeight() - CLOSE_BOX_FROM_TOP,
-					llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
-					llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
+					getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count,
+					getRect().getHeight() - close_box_from_top,
+					llround((F32)floater_close_box_size * mButtonScale),
+					llround((F32)floater_close_box_size * mButtonScale));
 			}
 
 			mButtons[i]->setRect(btn_rect);
@@ -1676,50 +1646,56 @@ void LLFloater::updateButtons()
 		}
 	}
 	if (mDragHandle)
-		mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (LLFLOATER_CLOSE_BOX_SIZE + 1)));
+		mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (floater_close_box_size + 1)));
 }
 
 void LLFloater::buildButtons()
 {
+	static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+	static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
 	for (S32 i = 0; i < BUTTON_COUNT; i++)
 	{
+		if (mButtons[i])
+		{
+			removeChild(mButtons[i]);
+			delete mButtons[i];
+			mButtons[i] = NULL;
+		}
+		
 		LLRect btn_rect;
 		if (mDragOnLeft)
 		{
 			btn_rect.setLeftTopAndSize(
 				LLPANEL_BORDER_WIDTH,
-				getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1),
-				llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
-				llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
+				getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * (i + 1),
+				llround(floater_close_box_size * mButtonScale),
+				llround(floater_close_box_size * mButtonScale));
 		}
 		else
 		{
 			btn_rect.setLeftTopAndSize(
-				getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1),
-				getRect().getHeight() - CLOSE_BOX_FROM_TOP,
-				llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
-				llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
-		}
-
-		LLButton* buttonp = new LLButton(
-			sButtonNames[i],
-			btn_rect,
-			sButtonActiveImageNames[i],
-			sButtonPressedImageNames[i],
-			LLStringUtil::null,
-			sButtonCallbacks[i],
-			this,
-			LLFontGL::getFontSansSerif());
-
-		buttonp->setTabStop(FALSE);
-		buttonp->setFollowsTop();
-		buttonp->setFollowsRight();
-		buttonp->setToolTip( sButtonToolTips[i] );
-		buttonp->setImageColor(LLUI::sColorsGroup->getColor("FloaterButtonImageColor"));
-		buttonp->setHoverImages(sButtonPressedImageNames[i],
-								sButtonPressedImageNames[i]);
-		buttonp->setScaleImage(TRUE);
-		buttonp->setSaveToXML(false);
+				getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * (i + 1),
+				getRect().getHeight() - close_box_from_top,
+				llround(floater_close_box_size * mButtonScale),
+				llround(floater_close_box_size * mButtonScale));
+		}
+
+		LLButton::Params p;
+		p.name(sButtonNames[i]);
+		p.rect(btn_rect);
+		p.label("");
+		p.image_unselected.name(sButtonActiveImageNames[i]);
+		p.image_selected.name(sButtonPressedImageNames[i]);
+		p.image_hover_selected.name(sButtonPressedImageNames[i]);
+		p.image_hover_unselected.name(sButtonPressedImageNames[i]);
+		p.click_callback.function(boost::bind(sButtonCallbacks[i], this));
+		p.tab_stop(false);
+		p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT);
+		p.tool_tip(sButtonToolTips[i]);
+		p.image_color(LLUI::getCachedColorFunctor("FloaterButtonImageColor"));
+		p.scale_image(true);
+
+		LLButton* buttonp = LLUICtrlFactory::create<LLButton>(p);
 		addChild(buttonp);
 		mButtons[i] = buttonp;
 	}
@@ -1730,13 +1706,11 @@ void LLFloater::buildButtons()
 /////////////////////////////////////////////////////
 // LLFloaterView
 
-LLFloaterView::LLFloaterView( const std::string& name, const LLRect& rect )
-:	LLUICtrl( name, rect, FALSE, NULL, NULL, FOLLOWS_ALL ),
+LLFloaterView::LLFloaterView (const Params& p)
+:	LLUICtrl (p),
 	mFocusCycleMode(FALSE),
 	mSnapOffsetBottom(0)
 {
-	setTabStop(FALSE);
-	resetStartingFloaterPosition();
 }
 
 // By default, adjust vertical.
@@ -1830,69 +1804,6 @@ void LLFloaterView::restoreAll()
 }
 
 
-void LLFloaterView::getNewFloaterPosition(S32* left,S32* top)
-{
-	// Workaround: mRect may change between when this object is created and the first time it is used.
-	static BOOL first = TRUE;
-	if( first )
-	{
-		resetStartingFloaterPosition();
-		first = FALSE;
-	}
-	
-	const S32 FLOATER_PAD = 16;
-	LLCoordWindow window_size;
-	getWindow()->getSize(&window_size);
-	LLRect full_window(0, window_size.mY, window_size.mX, 0);
-	LLRect floater_creation_rect(
-		160,
-		full_window.getHeight() - 2 * MENU_BAR_HEIGHT,
-		full_window.getWidth() * 2 / 3,
-		130 );
-	floater_creation_rect.stretch( -FLOATER_PAD );
-
-	*left = mNextLeft;
-	*top = mNextTop;
-
-	const S32 STEP = 25;
-	S32 bottom = floater_creation_rect.mBottom + 2 * STEP;
-	S32 right = floater_creation_rect.mRight - 4 * STEP;
-
-	mNextTop -= STEP;
-	mNextLeft += STEP;
-
-	if( (mNextTop < bottom ) || (mNextLeft > right) )
-	{
-		mColumn++;
-		mNextTop = floater_creation_rect.mTop;
-		mNextLeft = STEP * mColumn;
-
-		if( (mNextTop < bottom) || (mNextLeft > right) )
-		{
-			// Advancing the column didn't work, so start back at the beginning
-			resetStartingFloaterPosition();
-		}
-	}
-}
-
-void LLFloaterView::resetStartingFloaterPosition()
-{
-	const S32 FLOATER_PAD = 16;
-	LLCoordWindow window_size;
-	getWindow()->getSize(&window_size);
-	LLRect full_window(0, window_size.mY, window_size.mX, 0);
-	LLRect floater_creation_rect(
-		160,
-		full_window.getHeight() - 2 * MENU_BAR_HEIGHT,
-		full_window.getWidth() * 2 / 3,
-		130 );
-	floater_creation_rect.stretch( -FLOATER_PAD );
-
-	mNextLeft = floater_creation_rect.mLeft;
-	mNextTop = floater_creation_rect.mTop;
-	mColumn = 0;
-}
-
 LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor )
 {
 	LLRect base_rect = reference_floater->getRect();
@@ -2104,15 +2015,17 @@ void LLFloaterView::focusFrontFloater()
 
 void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
 {
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
 	S32 col = 0;
 	LLRect snap_rect_local = getLocalSnapRect();
 	for(S32 row = snap_rect_local.mBottom;
-		row < snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE;
-		row += LLFLOATER_HEADER_SIZE ) //loop rows
+		row < snap_rect_local.getHeight() - floater_header_size;
+		row += floater_header_size ) //loop rows
 	{
 		for(col = snap_rect_local.mLeft;
-			col < snap_rect_local.getWidth() - MINIMIZED_WIDTH;
-			col += MINIMIZED_WIDTH)
+			col < snap_rect_local.getWidth() - minimized_width;
+			col += minimized_width)
 		{
 			bool foundGap = TRUE;
 			for(child_list_const_iter_t child_it = getChildList()->begin();
@@ -2124,10 +2037,10 @@ void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
 				if(floater->isMinimized()) 
 				{
 					LLRect r = floater->getRect();
-					if((r.mBottom < (row + LLFLOATER_HEADER_SIZE))
-					   && (r.mBottom > (row - LLFLOATER_HEADER_SIZE))
-					   && (r.mLeft < (col + MINIMIZED_WIDTH))
-					   && (r.mLeft > (col - MINIMIZED_WIDTH)))
+					if((r.mBottom < (row + floater_header_size))
+					   && (r.mBottom > (row - floater_header_size))
+					   && (r.mLeft < (col + minimized_width))
+					   && (r.mLeft > (col - minimized_width)))
 					{
 						// needs the check for off grid. can't drag,
 						// but window resize makes them off
@@ -2179,7 +2092,7 @@ void LLFloaterView::closeAllChildren(bool app_quitting)
 		// dialogs to appear.
 		if (floaterp->canClose() && !floaterp->isDead())
 		{
-			floaterp->close(app_quitting);
+			floaterp->closeFloater(app_quitting);
 		}
 	}
 }
@@ -2202,14 +2115,13 @@ BOOL LLFloaterView::allChildrenClosed()
 	return true;
 }
 
-
 void LLFloaterView::refresh()
 {
 	// Constrain children to be entirely on the screen
 	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 	{
-		LLFloater* floaterp = (LLFloater*)*child_it;
-		if( floaterp->getVisible() )
+		LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);
+		if (floaterp && floaterp->getVisible() )
 		{
 			// minimized floaters are kept fully onscreen
 			adjustToFitScreen(floaterp, !floaterp->isMinimized());
@@ -2306,7 +2218,7 @@ LLRect LLFloaterView::getSnapRect() const
 	return snap_rect;
 }
 
-LLFloater *LLFloaterView::getFocusedFloater()
+LLFloater *LLFloaterView::getFocusedFloater() const
 {
 	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 	{
@@ -2319,7 +2231,7 @@ LLFloater *LLFloaterView::getFocusedFloater()
 	return NULL;
 }
 
-LLFloater *LLFloaterView::getFrontmost()
+LLFloater *LLFloaterView::getFrontmost() const
 {
 	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 	{
@@ -2332,7 +2244,7 @@ LLFloater *LLFloaterView::getFrontmost()
 	return NULL;
 }
 
-LLFloater *LLFloaterView::getBackmost()
+LLFloater *LLFloaterView::getBackmost() const
 {
 	LLFloater* back_most = NULL;
 	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
@@ -2348,18 +2260,51 @@ LLFloater *LLFloaterView::getBackmost()
 
 void LLFloaterView::syncFloaterTabOrder()
 {
-	// bring focused floater to front
-	for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it)
+	// look for a visible modal dialog, starting from first (should be only one)
+	LLModalDialog* modal_dialog = NULL;
+	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 	{
-		LLFloater* floaterp = (LLFloater*)*child_it;
-		if (gFocusMgr.childHasKeyboardFocus(floaterp))
+		LLModalDialog* dialog = dynamic_cast<LLModalDialog*>(*child_it);
+		if (dialog && dialog->isModal() && dialog->getVisible())
 		{
-			bringToFront(floaterp, FALSE);
+			modal_dialog = dialog;
 			break;
 		}
 	}
 
-	// then sync draw order to tab order
+	if (modal_dialog)
+	{
+		// If we have a visible modal dialog, make sure that it has focus
+		if( gFocusMgr.getTopCtrl() != modal_dialog )
+		{
+			gFocusMgr.setTopCtrl( modal_dialog );
+		}
+		
+		if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) )
+		{
+			modal_dialog->setFocus(TRUE);
+		}
+				
+		if( !gFocusMgr.childHasMouseCapture( modal_dialog ) )
+		{
+			gFocusMgr.setMouseCapture( modal_dialog );
+		}
+	}
+	else
+	{
+		// otherwise, make sure the focused floater is in the front of the child list
+		for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it)
+		{
+			LLFloater* floaterp = (LLFloater*)*child_it;
+			if (gFocusMgr.childHasKeyboardFocus(floaterp))
+			{
+				bringToFront(floaterp, FALSE);
+				break;
+			}
+		}
+	}
+
+	// sync draw order to tab order
 	for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it)
 	{
 		LLFloater* floaterp = (LLFloater*)*child_it;
@@ -2367,7 +2312,7 @@ void LLFloaterView::syncFloaterTabOrder()
 	}
 }
 
-LLFloater*	LLFloaterView::getParentFloater(LLView* viewp)
+LLFloater*	LLFloaterView::getParentFloater(LLView* viewp) const
 {
 	LLView* parentp = viewp->getParent();
 
@@ -2426,641 +2371,137 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
 	}
 }
 
-//
-// LLMultiFloater
-//
-
-LLMultiFloater::LLMultiFloater() :
-	mTabContainer(NULL),
-	mTabPos(LLTabContainer::TOP),
-	mAutoResize(TRUE),
-	mOrigMinWidth(0),
-	mOrigMinHeight(0)
-{
-
-}
-
-LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos) :
-	mTabContainer(NULL),
-	mTabPos(tab_pos),
-	mAutoResize(TRUE),
-	mOrigMinWidth(0),
-	mOrigMinHeight(0)
+void LLFloater::setInstanceName(const std::string& name)
 {
-
-}
-
-LLMultiFloater::LLMultiFloater(const std::string &name) :
-	LLFloater(name),
-	mTabContainer(NULL),
-	mTabPos(LLTabContainer::TOP),
-	mAutoResize(FALSE),
-	mOrigMinWidth(0),
-	mOrigMinHeight(0)
-{
-}
-
-LLMultiFloater::LLMultiFloater(
-	const std::string& name,
-	const LLRect& rect,
-	LLTabContainer::TabPosition tab_pos,
-	BOOL auto_resize) : 
-	LLFloater(name, rect, name),
-	mTabContainer(NULL),
-	mTabPos(LLTabContainer::TOP),
-	mAutoResize(auto_resize),
-	mOrigMinWidth(0),
-	mOrigMinHeight(0)
-{
-	mTabContainer = new LLTabContainer(std::string("Preview Tabs"), 
-		LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0), 
-		mTabPos, 
-		FALSE, 
-		FALSE);
-	mTabContainer->setFollowsAll();
-	if (isResizable())
-	{
-		mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
-	}
-
-	addChild(mTabContainer);
-}
-
-LLMultiFloater::LLMultiFloater(
-	const std::string& name,
-	const std::string& rect_control,
-	LLTabContainer::TabPosition tab_pos,
-	BOOL auto_resize) : 
-	LLFloater(name, rect_control, name),
-	mTabContainer(NULL),
-	mTabPos(tab_pos),
-	mAutoResize(auto_resize),
-	mOrigMinWidth(0),
-	mOrigMinHeight(0)
-{
-	mTabContainer = new LLTabContainer(std::string("Preview Tabs"), 
-		LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0), 
-		mTabPos, 
-		FALSE, 
-		FALSE);
-	mTabContainer->setFollowsAll();
-	if (isResizable() && mTabPos == LLTabContainer::BOTTOM)
-	{
-		mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
-	}
-
-	addChild(mTabContainer);
-	
-}
-
-
-void LLMultiFloater::open()	/* Flawfinder: ignore */
-{
-	if (mTabContainer->getTabCount() > 0)
-	{
-		LLFloater::open();	/* Flawfinder: ignore */
-	}
-	else
-	{
-		// for now, don't allow multifloaters
-		// without any child floaters
-		close();
-	}
-}
-
-void LLMultiFloater::onClose(bool app_quitting)
-{
-	if(closeAllFloaters() == TRUE)
-	{
-		LLFloater::onClose(app_quitting);
-	}//else not all tabs could be closed...
-}
-
-void LLMultiFloater::draw()
-{
-	if (mTabContainer->getTabCount() == 0)
-	{
-		//RN: could this potentially crash in draw hierarchy?
-		close();
-	}
-	else
+	if (name == mInstanceName)
+		return;
+	llassert_always(mInstanceName.empty());
+	mInstanceName = name;
+	if (!mInstanceName.empty())
 	{
-		for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
+		// save_rect and save_visibility only apply to registered floaters
+		if (!mRectControl.empty())
 		{
-			LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
-			if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i))
-			{
-				mTabContainer->setPanelTitle(i, floaterp->getShortTitle());
-			}
+			mRectControl = LLFloaterReg::declareRectControl(mInstanceName);
 		}
-		LLFloater::draw();
-	}
-}
-
-BOOL LLMultiFloater::closeAllFloaters()
-{
-	S32	tabToClose = 0;
-	S32	lastTabCount = mTabContainer->getTabCount();
-	while (tabToClose < mTabContainer->getTabCount())
-	{
-		LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
-		first_floater->close();
-		if(lastTabCount == mTabContainer->getTabCount())
+		if (!mVisibilityControl.empty())
 		{
-			//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
-			//so try and close the next one in the list...
-			tabToClose++;
-		}else
-		{
-			//Tab closed ok.
-			lastTabCount = mTabContainer->getTabCount();
+			mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName);
 		}
 	}
-	if( mTabContainer->getTabCount() != 0 )
-		return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE.
-	return TRUE; //else all tabs were successfully closed...
 }
 
-void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
+void LLFloater::setKey(const LLSD& newkey)
 {
-	S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
-	S32 new_height = llmax(getRect().getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
-
-    if (isMinimized())
-    {
-        LLRect newrect;
-        newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height);
-        setExpandedRect(newrect);
-    }
-	else
-	{
-		S32 old_height = getRect().getHeight();
-		reshape(new_width, new_height);
-		// keep top left corner in same position
-		translate(0, old_height - new_height);
-	}
+	// Note: We don't have to do anything special with registration when we change keys
+	mKey = newkey;
 }
 
-/**
-  void addFloater(LLFloater* floaterp, BOOL select_added_floater)
-
-  Adds the LLFloater pointed to by floaterp to this.
-  If floaterp is already hosted by this, then it is re-added to get
-  new titles, etc.
-  If select_added_floater is true, the LLFloater pointed to by floaterp will
-  become the selected tab in this
-
-  Affects: mTabContainer, floaterp
-**/
-void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
+void LLFloater::initFromParams(const LLFloater::Params& p)
 {
-	if (!floaterp)
-	{
-		return;
-	}
-
-	if (!mTabContainer)
-	{
-		llerrs << "Tab Container used without having been initialized." << llendl;
-		return;
-	}
-
-	if (floaterp->getHost() == this)
-	{
-		// already hosted by me, remove
-		// do this so we get updated title, etc.
-		mFloaterDataMap.erase(floaterp->getHandle());
-		mTabContainer->removeTabPanel(floaterp);
-	}
-	else if (floaterp->getHost())
-	{
-		// floaterp is hosted by somebody else and
-		// this is adding it, so remove it from it's old host
-		floaterp->getHost()->removeFloater(floaterp);
-	}
-	else if (floaterp->getParent() == gFloaterView)
-	{
-		// rehost preview floater as child panel
-		gFloaterView->removeChild(floaterp);
-	}
-
-	// store original configuration
-	LLFloaterData floater_data;
-	floater_data.mWidth = floaterp->getRect().getWidth();
-	floater_data.mHeight = floaterp->getRect().getHeight();
-	floater_data.mCanMinimize = floaterp->isMinimizeable();
-	floater_data.mCanResize = floaterp->isResizable();
-
-	// remove minimize and close buttons
-	floaterp->setCanMinimize(FALSE);
-	floaterp->setCanResize(FALSE);
-	floaterp->setCanDrag(FALSE);
-	floaterp->storeRectControl();
-	// avoid double rendering of floater background (makes it more opaque)
-	floaterp->setBackgroundVisible(FALSE);
-
-	if (mAutoResize)
-	{
-		growToFit(floater_data.mWidth, floater_data.mHeight);
-	}
+	 // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
+	LLPanel::initFromParams(p);
 
-	//add the panel, add it to proper maps
-	mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point);
-	mFloaterDataMap[floaterp->getHandle()] = floater_data;
+	mTitle = p.title;
+	mShortTitle = p.short_title;
+	applyTitle();
 
-	updateResizeLimits();
+	setCanTearOff(p.can_tear_off);
+	setCanMinimize(p.can_minimize);
+	setCanClose(p.can_close);
+	
+	mDragOnLeft = p.can_drag_on_left;
+	mResizable = p.can_resize;
+	mMinWidth = p.min_width;
+	mMinHeight = p.min_height;
+	mSingleInstance = p.single_instance;
+	mAutoTile = p.auto_tile;
 
-	if ( select_added_floater )
+	if (p.save_rect)
 	{
-		mTabContainer->selectTabPanel(floaterp);
+		mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set
 	}
-	else
+	if (p.save_visibility)
 	{
-		// reassert visible tab (hiding new floater if necessary)
-		mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
+		mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
 	}
-
-	floaterp->setHost(this);
-	if (isMinimized())
-	{
-		floaterp->setVisible(FALSE);
-	}
-}
-
-/**
-	BOOL selectFloater(LLFloater* floaterp)
-
-	If the LLFloater pointed to by floaterp is hosted by this,
-	then its tab is selected and returns true.  Otherwise returns false.
-
-	Affects: mTabContainer
-**/
-BOOL LLMultiFloater::selectFloater(LLFloater* floaterp)
-{
-	return mTabContainer->selectTabPanel(floaterp);
-}
-
-// virtual
-void LLMultiFloater::selectNextFloater()
-{
-	mTabContainer->selectNextTab();
 }
 
-// virtual
-void LLMultiFloater::selectPrevFloater()
+void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater, LLXMLNodePtr output_node)
 {
-	mTabContainer->selectPrevTab();
-}
+	Params params(LLUICtrlFactory::getDefaultParams<LLFloater::Params>());
+	LLXUIParser::instance().readXUI(node, params);
 
-void LLMultiFloater::showFloater(LLFloater* floaterp)
-{
-	// we won't select a panel that already is selected
-	// it is hard to do this internally to tab container
-	// as tab selection is handled via index and the tab at a given
-	// index might have changed
-	if (floaterp != mTabContainer->getCurrentPanel() &&
-		!mTabContainer->selectTabPanel(floaterp))
+	if (output_node)
 	{
-		addFloater(floaterp, TRUE);
+		Params output_params(params);
+		setupParamsForExport(output_params, parent);
+        Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater::Params>());
+		output_node->setName(node->getName()->mString);
+		LLXUIParser::instance().writeXUI(
+			output_node, output_params, &default_params);
 	}
-}
 
-void LLMultiFloater::removeFloater(LLFloater* floaterp)
-{
-	if ( floaterp->getHost() != this )
-		return;
-
-	floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
-	if (found_data_it != mFloaterDataMap.end())
+	setupParams(params, parent);
+ 	initFromParams(params);
+	
+	initFloater();
+	
+	LLMultiFloater* last_host = LLFloater::getFloaterHost();
+	if (node->hasName("multi_floater"))
 	{
-		LLFloaterData& floater_data = found_data_it->second;
-		floaterp->setCanMinimize(floater_data.mCanMinimize);
-		if (!floater_data.mCanResize)
-		{
-			// restore original size
-			floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
-		}
-		floaterp->setCanResize(floater_data.mCanResize);
-		mFloaterDataMap.erase(found_data_it);
+		LLFloater::setFloaterHost((LLMultiFloater*) this);
 	}
-	mTabContainer->removeTabPanel(floaterp);
-	floaterp->setBackgroundVisible(TRUE);
-	floaterp->setCanDrag(TRUE);
-	floaterp->setHost(NULL);
-	floaterp->applyRectControl();
-
-	updateResizeLimits();
-
-	tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
-}
 
-void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
-{
-	// default implementation does nothing
-}
+	addChildren(node, output_node);
 
-void LLMultiFloater::tabClose()
-{
-	if (mTabContainer->getTabCount() == 0)
+	if (node->hasName("multi_floater"))
 	{
-		// no more children, close myself
-		close();
+		LLFloater::setFloaterHost(last_host);
 	}
-}
-
-void LLMultiFloater::setVisible(BOOL visible)
-{
-	// *FIX: shouldn't have to do this, fix adding to minimized multifloater
-	LLFloater::setVisible(visible);
 	
-	if (mTabContainer)
-	{
-		LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
-
-		if (cur_floaterp)
-		{
-			cur_floaterp->setVisible(visible);
-		}
-
-		// if no tab selected, and we're being shown,
-		// select last tab to be added
-		if (visible && !cur_floaterp)
-		{
-			mTabContainer->selectLastTab();
-		}
-	}
-}
+	BOOL result = postBuild();
 
-BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
-{
-	if (key == 'W' && mask == MASK_CONTROL)
+	if (!result)
 	{
-		LLFloater* floater = getActiveFloater();
-		// is user closeable and is system closeable
-		if (floater && floater->canClose() && floater->isCloseable())
-		{
-			floater->close();
-		}
-		return TRUE;
+		llerrs << "Failed to construct floater " << getName() << llendl;
 	}
 
-	return LLFloater::handleKeyHere(key, mask);
-}
-
-LLFloater* LLMultiFloater::getActiveFloater()
-{
-	return (LLFloater*)mTabContainer->getCurrentPanel();
-}
-
-S32	LLMultiFloater::getFloaterCount()
-{
-	return mTabContainer->getTabCount();
-}
-
-/**
-	BOOL isFloaterFlashing(LLFloater* floaterp)
-
-	Returns true if the LLFloater pointed to by floaterp
-	is currently in a flashing state and is hosted by this.
-	False otherwise.
-
-	Requires: floaterp != NULL
-**/
-BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
-{
-	if ( floaterp && floaterp->getHost() == this )
-		return mTabContainer->getTabPanelFlashing(floaterp);
-
-	return FALSE;
-}
-
-/**
-	BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
-
-	Sets the current flashing state of the LLFloater pointed
-	to by floaterp to be the BOOL flashing if the LLFloater pointed
-	to by floaterp is hosted by this.
-
-	Requires: floaterp != NULL
-**/
-void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
-{
-	if ( floaterp && floaterp->getHost() == this )
-		mTabContainer->setTabPanelFlashing(floaterp, flashing);
-}
-
-//static
-void LLMultiFloater::onTabSelected(void* userdata, bool from_click)
-{
-	LLMultiFloater* floaterp = (LLMultiFloater*)userdata;
-
-	floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click);
-}
+	applyRectControl(); // If we have a saved rect control, apply it
+	gFloaterView->adjustToFitScreen(this, FALSE); // Floaters loaded from XML should all fit on screen	
 
-void LLMultiFloater::setCanResize(BOOL can_resize)
-{
-	LLFloater::setCanResize(can_resize);
-	if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
+	if (open_floater)
 	{
-		mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
-	}
-	else
-	{
-		mTabContainer->setRightTabBtnOffset(0);
+		this->openFloater(getKey());
 	}
+
+	moveResizeHandlesToFront();
 }
 
-BOOL LLMultiFloater::postBuild()
+// visibility methods
+bool VisibilityPolicy<LLFloater>::visible(LLFloater* instance, const LLSD& key)
 {
-	// remember any original xml minimum size
-	getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
-
-	if (mTabContainer)
-	{
-		return TRUE;
-	}
-
-	requires<LLTabContainer>("Preview Tabs");
-	if (checkRequirements())
+	if (instance) 
 	{
-		mTabContainer = getChild<LLTabContainer>("Preview Tabs");
-		return TRUE;
+		return !instance->isMinimized() && instance->isInVisibleChain();
 	}
-
 	return FALSE;
 }
 
-void LLMultiFloater::updateResizeLimits()
+void VisibilityPolicy<LLFloater>::show(LLFloater* instance, const LLSD& key)
 {
-	// initialize minimum size constraint to the original xml values.
-	S32 new_min_width = mOrigMinWidth;
-	S32 new_min_height = mOrigMinHeight;
-	// possibly increase minimum size constraint due to children's minimums.
-	for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+	if (instance) 
 	{
-		LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
-		if (floaterp)
+		instance->openFloater(key);
+		if (instance->getHost())
 		{
-			new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
-			new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
+			instance->getHost()->openFloater(key);
 		}
 	}
-	setResizeLimits(new_min_width, new_min_height);
-
-	S32 cur_height = getRect().getHeight();
-	S32 new_width = llmax(getRect().getWidth(), new_min_width);
-	S32 new_height = llmax(getRect().getHeight(), new_min_height);
-
-	if (isMinimized())
-	{
-		const LLRect& expanded = getExpandedRect();
-		LLRect newrect;
-		newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height));
-		setExpandedRect(newrect);
-	}
-	else
-	{
-		reshape(new_width, new_height);
-
-		// make sure upper left corner doesn't move
-		translate(0, cur_height - getRect().getHeight());
-
-		// make sure this window is visible on screen when it has been modified
-		// (tab added, etc)
-		gFloaterView->adjustToFitScreen(this, TRUE);
-	}
-}
-
-// virtual
-LLXMLNodePtr LLFloater::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLPanel::getXML();
-
-	node->createChild("title", TRUE)->setStringValue(getCurrentTitle());
-
-	node->createChild("can_resize", TRUE)->setBoolValue(isResizable());
-
-	node->createChild("can_minimize", TRUE)->setBoolValue(isMinimizeable());
-
-	node->createChild("can_close", TRUE)->setBoolValue(isCloseable());
-
-	node->createChild("can_drag_on_left", TRUE)->setBoolValue(isDragOnLeft());
-
-	node->createChild("min_width", TRUE)->setIntValue(getMinWidth());
-
-	node->createChild("min_height", TRUE)->setIntValue(getMinHeight());
-
-	node->createChild("can_tear_off", TRUE)->setBoolValue(mCanTearOff);
-	
-	return node;
 }
 
-// static
-LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+void VisibilityPolicy<LLFloater>::hide(LLFloater* instance, const LLSD& key)
 {
-	std::string name("floater");
-	node->getAttributeString("name", name);
-
-	LLFloater *floaterp = new LLFloater(name);
-
-	std::string filename;
-	node->getAttributeString("filename", filename);
-
-	if (filename.empty())
-	{
-		// Load from node
-		floaterp->initFloaterXML(node, parent, factory);
-	}
-	else
-	{
-		// Load from file
-		factory->buildFloater(floaterp, filename);
-	}
-
-	return floaterp;
+	if (instance) instance->closeFloater();
 }
 
-void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open)	/* Flawfinder: ignore */
-{
-	std::string name(getName());
-	std::string title(getCurrentTitle());
-	std::string short_title(getShortTitle());
-	std::string rect_control("");
-	BOOL resizable = isResizable();
-	S32 min_width = getMinWidth();
-	S32 min_height = getMinHeight();
-	BOOL drag_on_left = isDragOnLeft();
-	BOOL minimizable = isMinimizeable();
-	BOOL close_btn = isCloseable();
-	LLRect rect;
-
-	node->getAttributeString("name", name);
-	node->getAttributeString("title", title);
-	node->getAttributeString("short_title", short_title);
-	node->getAttributeString("rect_control", rect_control);
-	node->getAttributeBOOL("can_resize", resizable);
-	node->getAttributeBOOL("can_minimize", minimizable);
-	node->getAttributeBOOL("can_close", close_btn);
-	node->getAttributeBOOL("can_drag_on_left", drag_on_left);
-	node->getAttributeS32("min_width", min_width);
-	node->getAttributeS32("min_height", min_height);
-
-	if (! rect_control.empty())
-	{
-		setRectControl(rect_control);
-	}
-
-	createRect(node, rect, parent, LLRect());
-	
-	setRect(rect);
-	setName(name);
-	
-	initFloater(title,
-			resizable,
-			min_width,
-			min_height,
-			drag_on_left,
-			minimizable,
-			close_btn);
-
-	setTitle(title);
-	applyTitle ();
-
-	setShortTitle(short_title);
-
-	BOOL can_tear_off;
-	if (node->getAttributeBOOL("can_tear_off", can_tear_off))
-	{
-		setCanTearOff(can_tear_off);
-	}
-	
-	initFromXML(node, parent);
-
-	LLMultiFloater* last_host = LLFloater::getFloaterHost();
-	if (node->hasName("multi_floater"))
-	{
-		LLFloater::setFloaterHost((LLMultiFloater*) this);
-	}
-
-	initChildrenXML(node, factory);
-
-	if (node->hasName("multi_floater"))
-	{
-		LLFloater::setFloaterHost(last_host);
-	}
-
-	BOOL result = postBuild();
-
-	if (!result)
-	{
-		llerrs << "Failed to construct floater " << name << llendl;
-	}
-
-	applyRectControl();
-	if (open)	/* Flawfinder: ignore */
-	{
-		this->open();	/* Flawfinder: ignore */
-	}
-
-	moveResizeHandlesToFront();
-}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 0e3d148b09..f6c783b0bf 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -39,7 +39,6 @@
 
 #include "llpanel.h"
 #include "lluuid.h"
-#include "lltabcontainer.h"
 #include "llnotifications.h"
 #include <set>
 
@@ -50,17 +49,10 @@ class LLButton;
 class LLMultiFloater;
 class LLFloater;
 
-const S32 LLFLOATER_VPAD = 6;
-const S32 LLFLOATER_HPAD = 6;
-const S32 LLFLOATER_CLOSE_BOX_SIZE = 16;
-const S32 LLFLOATER_HEADER_SIZE = 18;
 
 const BOOL RESIZE_YES = TRUE;
 const BOOL RESIZE_NO = FALSE;
 
-const S32 DEFAULT_MIN_WIDTH = 100;
-const S32 DEFAULT_MIN_HEIGHT = 100;
-
 const BOOL DRAG_ON_TOP = FALSE;
 const BOOL DRAG_ON_LEFT = TRUE;
 
@@ -87,11 +79,22 @@ private:
 	LLHandle<LLFloater> mFloaterHandle;
 };
 
-
 class LLFloater : public LLPanel
 {
 friend class LLFloaterView;
+friend class LLFloaterReg;
+friend class LLMultiFloater;
 public:
+	struct KeyCompare
+	{
+		static bool compare(const LLSD& a, const LLSD& b);
+		static bool equate(const LLSD& a, const LLSD& b);
+		bool operator()(const LLSD& a, const LLSD& b) const
+		{
+			return compare(a, b);
+		}
+	};
+	
 	enum EFloaterButtons
 	{
 		BUTTON_CLOSE,
@@ -102,49 +105,63 @@ public:
 		BUTTON_COUNT
 	};
 	
-	LLFloater();
- 	LLFloater(const std::string& name); //simple constructor for data-driven initialization
-	LLFloater(	const std::string& name, const LLRect& rect, const std::string& title,
-		BOOL resizable = FALSE,
-		S32 min_width = DEFAULT_MIN_WIDTH,
-		S32 min_height = DEFAULT_MIN_HEIGHT,
-		BOOL drag_on_left = FALSE,
-		BOOL minimizable = TRUE,
-		BOOL close_btn = TRUE,
-		BOOL bordered = BORDER_NO);
-
-	LLFloater(	const std::string& name, const std::string& rect_control, const std::string& title,
-		BOOL resizable = FALSE,
-		S32 min_width = DEFAULT_MIN_WIDTH, 
-		S32 min_height = DEFAULT_MIN_HEIGHT,
-		BOOL drag_on_left = FALSE,
-		BOOL minimizable = TRUE,
-		BOOL close_btn = TRUE,
-		BOOL bordered = BORDER_NO);
+	struct Params 
+	:	public LLInitParam::Block<Params, LLPanel::Params>
+	{
+		Optional<std::string>	title,
+								short_title;
+		
+		Optional<bool>			single_instance,
+								auto_tile,
+								can_resize,
+								can_minimize,
+								can_close,
+								can_drag_on_left,
+								can_tear_off,
+								save_rect,
+								save_visibility;
+
+		Params() :
+			title("title"),
+			short_title("short_title"),
+			single_instance("single_instance", false),
+			auto_tile("auto_tile", false),
+			can_resize("can_resize", false),
+			can_minimize("can_minimize", true),
+			can_close("can_close", true),
+			can_drag_on_left("can_drag_on_left", false),
+			can_tear_off("can_tear_off", true),
+			save_rect("save_rect", false),
+			save_visibility("save_visibility", false)
+		{
+			name = "floater";
+			// defaults that differ from LLPanel:
+			background_visible = true;
+			visible = false;
+		}
+	};
+	
+	LLFloater(const LLSD& key = LLSD(), const LLFloater::Params& params = LLFloater::Params());
 
 	virtual ~LLFloater();
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-	void initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open = TRUE);
+	void initFromParams(const LLFloater::Params& p);
+	void initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL);
 
-	/*virtual*/ void userSetShape(const LLRect& new_rect);
+	/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
 	/*virtual*/ BOOL canSnapTo(const LLView* other_view);
-	/*virtual*/ void snappedTo(const LLView* snap_view);
+	/*virtual*/ void setSnappedTo(const LLView* snap_view);
 	/*virtual*/ void setFocus( BOOL b );
 	/*virtual*/ void setIsChrome(BOOL is_chrome);
+	/*virtual*/ void setRect(const LLRect &rect);
 
-	// Can be called multiple times to reset floater parameters.
-	// Deletes all children of the floater.
-	virtual void		initFloater(const std::string& title, BOOL resizable, 
-						S32 min_width, S32 min_height, BOOL drag_on_left,
-						BOOL minimizable, BOOL close_btn);
+	void 			initFloater();
 
-	virtual void	open();	/* Flawfinder: ignore */
+	void			openFloater(const LLSD& key = LLSD());
 
 	// If allowed, close the floater cleanly, releasing focus.
 	// app_quitting is passed to onClose() below.
-	virtual void	close(bool app_quitting = false);
+	void			closeFloater(bool app_quitting = false);
 
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	
@@ -153,11 +170,8 @@ public:
 
 	// moves to center of gFloaterView
 	void			center();
-	// applies rectangle stored in mRectControl, if any
-	void			applyRectControl();
 
-
-	LLMultiFloater* getHost() { return (LLMultiFloater*)mHostHandle.get(); }
+	LLMultiFloater* getHost();
 
 	void			applyTitle();
 	const std::string&	getCurrentTitle() const;
@@ -185,9 +199,8 @@ public:
 	void			setResizeLimits( S32 min_width, S32 min_height );
 	void			getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; }
 
-	bool			isMinimizeable() const{ return mButtonsEnabled[BUTTON_MINIMIZE]; }
-	// Does this window have a close button, NOT can we close it right now.
-	bool			isCloseable() const{ return (mButtonsEnabled[BUTTON_CLOSE]); }
+	bool			isMinimizeable() const{ return mCanMinimize; }
+	bool			isCloseable() const{ return mCanClose; }
 	bool			isDragOnLeft() const{ return mDragOnLeft; }
 	S32				getMinWidth() const{ return mMinWidth; }
 	S32				getMinHeight() const{ return mMinHeight; }
@@ -198,7 +211,7 @@ public:
 	virtual BOOL	handleMiddleMouseDown(S32 x, S32 y, MASK mask);
 	virtual void	draw();
 
-	virtual void	onOpen() {}
+	virtual void	onOpen(const LLSD& key) {}
 
 	// Call destroy() to free memory, or setVisible(FALSE) to keep it
 	// If app_quitting, you might not want to save your visibility.
@@ -210,8 +223,10 @@ public:
 	virtual BOOL	canClose() { return TRUE; }
 
 	virtual void	setVisible(BOOL visible);
+	virtual void	onVisibilityChange ( BOOL curVisibilityIn );
+	
 	void			setFrontmost(BOOL take_focus = TRUE);
-
+	
 	// Defaults to false.
 	virtual BOOL	canSaveAs() const { return FALSE; }
 
@@ -222,6 +237,8 @@ public:
 	LLHandle<LLFloater>	getSnapTarget() const { return mSnappedTo; }
 
 	LLHandle<LLFloater> getHandle() const { return mHandle; }
+	const LLSD& 	getKey() { return mKey; }
+	BOOL		 	matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); }
 
 	// Return a closeable floater, if any, given the current focus.
 	static LLFloater* getClosableFloaterFromFocus(); 
@@ -235,22 +252,30 @@ public:
 	    return LLNotification::Params(name).context(mNotificationContext); 
 	}
 
-	static void		onClickClose(void *userdata);
-	static void		onClickMinimize(void *userdata);
-	static void		onClickTearOff(void *userdata);
-	static void		onClickEdit(void *userdata);
+	static void		onClickClose(LLFloater* floater);
+	static void		onClickMinimize(LLFloater* floater);
+	static void		onClickTearOff(LLFloater* floater);
+	static void		onClickEdit(LLFloater* floater);
 
 	static void		setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; }
 	static void		setEditModeEnabled(BOOL enable);
 	static BOOL		getEditModeEnabled() { return sEditModeEnabled; }
-	static LLMultiFloater*		getFloaterHost() {return sHostp; }
-
+	static LLMultiFloater* getFloaterHost() {return sHostp; }
+		
 protected:
 
+	void			setRectControl(const std::string& rectname) { mRectControl = rectname; };
+	void			applyRectControl();
+	void			storeRectControl();
+	void			storeVisibilityControl();
+
+	void		 	setKey(const LLSD& key);
+	void		 	setInstanceName(const std::string& name);
+	
 	virtual void	bringToFront(S32 x, S32 y);
 	virtual void	setVisibleAndFrontmost(BOOL take_focus=TRUE);    
 	
-	void		setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized
+	void			setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized
 	const LLRect&	getExpandedRect() const { return mExpandedRect; }
 
 	void			setAutoFocus(BOOL focus) { mAutoFocus = focus; } // whether to automatically take focus when opened
@@ -266,31 +291,48 @@ private:
 	void			updateButtons();
 	void			buildButtons();
 	BOOL			offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons index);
-
+	void			addResizeCtrls();
+	void 			addDragHandle();
+	
+protected:
+	std::string		mRectControl;
+	std::string		mVisibilityControl;
+	
+	LLSD			mKey;				// Key used for retrieving instances; set (for now) by LLFLoaterReg
+	
+private:
 	LLRect			mExpandedRect;
 	LLDragHandle*	mDragHandle;
 	LLResizeBar*	mResizeBar[4];
 	LLResizeHandle*	mResizeHandle[4];
-	LLButton		*mMinimizeButton;
+	
+	LLUIString		mTitle;
+	LLUIString		mShortTitle;
+	
+	BOOL			mSingleInstance;	// TRUE if there is only ever one instance of the floater
+	std::string		mInstanceName;		// Store the instance name so we can remove ourselves from the list
+	BOOL			mAutoTile;			// TRUE if placement of new instances tiles
+	
 	BOOL			mCanTearOff;
+	BOOL			mCanMinimize;
+	BOOL			mCanClose;
+	BOOL			mDragOnLeft;
+	BOOL			mResizable;
+	
+	S32				mMinWidth;
+	S32				mMinHeight;
+	
 	BOOL			mMinimized;
 	BOOL			mForeground;
 	LLHandle<LLFloater>	mDependeeHandle;
-	std::string		mTitle;
-	std::string		mShortTitle;
+	
 
 	BOOL			mFirstLook;			// TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible.
-
-	BOOL			mResizable;
-	S32				mMinWidth;
-	S32				mMinHeight;
-
 	BOOL			mEditing;
 	
 	typedef std::set<LLHandle<LLFloater> > handle_set_t;
 	typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t;
 	handle_set_t	mDependents;
-	bool			mDragOnLeft;
 
 	BOOL			mButtonsEnabled[BUTTON_COUNT];
 	LLButton*		mButtons[BUTTON_COUNT];
@@ -308,7 +350,9 @@ private:
 	static std::string	sButtonPressedImageNames[BUTTON_COUNT];
 	static std::string	sButtonNames[BUTTON_COUNT];
 	static std::string	sButtonToolTips[BUTTON_COUNT];
-	typedef void (*click_callback)(void *);
+	static std::string  sButtonToolTipsIndex[BUTTON_COUNT];
+	
+	typedef void(*click_callback)(LLFloater*);
 	static click_callback sButtonCallbacks[BUTTON_COUNT];
 
 	typedef std::map<LLHandle<LLFloater>, LLFloater*> handle_map_t;
@@ -320,7 +364,10 @@ private:
 	BOOL			mHasBeenDraggedWhileMinimized;
 	S32				mPreviousMinimizedBottom;
 	S32				mPreviousMinimizedLeft;
-	
+
+	LLColor4		mBgColorAlpha;
+	LLColor4		mBgColorOpaque;
+
 	LLFloaterNotificationContext* mNotificationContext;
 	LLRootHandle<LLFloater>		mHandle;	
 };
@@ -331,18 +378,18 @@ private:
 
 class LLFloaterView : public LLUICtrl
 {
-public:
-	LLFloaterView( const std::string& name, const LLRect& rect );
+protected:
+	LLFloaterView (const Params& p);
+	friend class LLUICtrlFactory;
 
+public:
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	void reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical);
 
 	/*virtual*/ void draw();
 	/*virtual*/ LLRect getSnapRect() const;
-	void refresh();
+	/*virtual*/ void refresh();
 
-	void			getNewFloaterPosition( S32* left, S32* top );
-	void			resetStartingFloaterPosition();
 	LLRect			findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor );
 
 	// Given a child of gFloaterView, make sure this view can fit entirely onscreen.
@@ -365,10 +412,10 @@ public:
 	void			closeAllChildren(bool app_quitting);
 	BOOL			allChildrenClosed();
 
-	LLFloater* getFrontmost();
-	LLFloater* getBackmost();
-	LLFloater* getParentFloater(LLView* viewp);
-	LLFloater* getFocusedFloater();
+	LLFloater* getFrontmost() const;
+	LLFloater* getBackmost() const;
+	LLFloater* getParentFloater(LLView* viewp) const;
+	LLFloater* getFocusedFloater() const;
 	void		syncFloaterTabOrder();
 
 	// Returns z order of child provided. 0 is closest, larger numbers
@@ -386,99 +433,23 @@ private:
 	S32				mSnapOffsetBottom;
 };
 
-// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376
-class LLMultiFloater : public LLFloater
-{
-public:
-	LLMultiFloater();
-	LLMultiFloater(LLTabContainer::TabPosition tab_pos);
-	LLMultiFloater(const std::string& name);
-	LLMultiFloater(const std::string& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
-	LLMultiFloater(const std::string& name, const std::string& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
-	virtual ~LLMultiFloater() {};
-
-	virtual BOOL postBuild();
-	/*virtual*/ void open();	/* Flawfinder: ignore */
-	/*virtual*/ void onClose(bool app_quitting);
-	/*virtual*/ void draw();
-	/*virtual*/ void setVisible(BOOL visible);
-	/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
-
-	virtual void setCanResize(BOOL can_resize);
-	virtual void growToFit(S32 content_width, S32 content_height);
-	virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
-
-	virtual void showFloater(LLFloater* floaterp);
-	virtual void removeFloater(LLFloater* floaterp);
-
-	virtual void tabOpen(LLFloater* opened_floater, bool from_click);
-	virtual void tabClose();
-
-	virtual BOOL selectFloater(LLFloater* floaterp);
-	virtual void selectNextFloater();
-	virtual void selectPrevFloater();
-
-	virtual LLFloater*	getActiveFloater();
-	virtual BOOL		isFloaterFlashing(LLFloater* floaterp);
-	virtual S32			getFloaterCount();
-
-	virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing);
-	virtual BOOL closeAllFloaters();	//Returns FALSE if the floater could not be closed due to pending confirmation dialogs
-	void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; }
-	static void onTabSelected(void* userdata, bool);
-
-	virtual void updateResizeLimits();
-
-protected:
-	struct LLFloaterData
-	{
-		S32		mWidth;
-		S32		mHeight;
-		BOOL	mCanMinimize;
-		BOOL	mCanResize;
-	};
-
-	LLTabContainer*		mTabContainer;
-	
-	typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t;
-	floater_data_map_t	mFloaterDataMap;
-	
-	LLTabContainer::TabPosition mTabPos;
-	BOOL				mAutoResize;
-	S32					mOrigMinWidth, mOrigMinHeight;  // logically const but initialized late
-};
+// singleton implementation for floaters
+// https://wiki.lindenlab.com/mediawiki/index.php?title=LLFloaterSingleton&oldid=164990
 
+//*******************************************************
+//* TO BE DEPRECATED
+//*******************************************************
 // visibility policy specialized for floaters
 template<>
 class VisibilityPolicy<LLFloater>
 {
 public:
 	// visibility methods
-	static bool visible(LLFloater* instance, const LLSD& key)
-	{
-		if (instance) 
-		{
-			return !instance->isMinimized() && instance->isInVisibleChain();
-		}
-		return FALSE;
-	}
+	static bool visible(LLFloater* instance, const LLSD& key);
 
-	static void show(LLFloater* instance, const LLSD& key)
-	{
-		if (instance) 
-		{
-			instance->open();
-			if (instance->getHost())
-			{
-				instance->getHost()->open();
-			}
-		}
-	}
+	static void show(LLFloater* instance, const LLSD& key);
 
-	static void hide(LLFloater* instance, const LLSD& key)
-	{
-		if (instance) instance->close();
-	}
+	static void hide(LLFloater* instance, const LLSD& key);
 };
 
 
@@ -489,6 +460,10 @@ template <class T> class LLFloaterSingleton : public LLUISingleton<T, Visibility
 {
 };
 
+//
+// Globals
+//
+
 extern LLFloaterView* gFloaterView;
 
 #endif  // LL_FLOATER_H
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
new file mode 100644
index 0000000000..faa763cea9
--- /dev/null
+++ b/indra/llui/llfloaterreg.cpp
@@ -0,0 +1,423 @@
+/** 
+ * @file llfloaterreg.cpp
+ * @brief LLFloaterReg Floater Registration Class
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llfloaterreg.h"
+
+#include "llfloater.h"
+#include "llmultifloater.h"
+
+//*******************************************************
+
+//static
+LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;
+LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
+LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
+std::map<std::string,std::string> LLFloaterReg::sGroupMap;
+
+//*******************************************************
+
+//static
+void LLFloaterReg::add(const std::string& name, const std::string& filename, const LLFloaterBuildFunc& func, const std::string& groupname)
+{
+	sBuildMap[name].mFunc = func;
+	sBuildMap[name].mFile = filename;
+	sGroupMap[name] = groupname.empty() ? name : groupname;
+	sGroupMap[groupname] = groupname; // for referencing directly by group name
+}
+
+//static
+LLRect LLFloaterReg::getFloaterRect(const std::string& name)
+{
+	LLRect rect;
+	const std::string& groupname = sGroupMap[name];
+	if (!groupname.empty())
+	{
+		instance_list_t& list = sInstanceMap[groupname];
+		if (!list.empty())
+		{
+			static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16);
+			LLFloater* last_floater = list.back();
+			if (last_floater->getHost())
+			{
+				rect = last_floater->getHost()->getRect();
+			}
+			else
+			{
+				rect = last_floater->getRect();
+			}
+			rect.translate(floater_offset, -floater_offset);
+		}
+	}
+	return rect;
+}
+
+//static
+LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key)
+{
+	LLFloater* res = NULL;
+	const std::string& groupname = sGroupMap[name];
+	if (!groupname.empty())
+	{
+		instance_list_t& list = sInstanceMap[groupname];
+		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
+		{
+			LLFloater* inst = *iter;
+			if (inst->matchesKey(key))
+			{
+				res = inst;
+				break;
+			}
+		}
+	}
+	return res;
+}
+
+//static
+LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key) 
+{
+	LLFloater* res = findInstance(name, key);
+	if (!res)
+	{
+		const LLFloaterBuildFunc& build_func = sBuildMap[name].mFunc;
+		const std::string& xui_file = sBuildMap[name].mFile;
+		if (build_func)
+		{
+			const std::string& groupname = sGroupMap[name];
+			if (!groupname.empty())
+			{
+				instance_list_t& list = sInstanceMap[groupname];
+				int index = list.size();
+
+				res = build_func(key);
+				
+				const bool DONT_OPEN_FLOATER = false;
+				LLUICtrlFactory::getInstance()->buildFloater(res, xui_file, DONT_OPEN_FLOATER);
+				
+				// Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe
+				res->mKey = key;
+				res->setInstanceName(name);
+				res->applyRectControl(); // Can't apply rect control until setting instance name
+				if (res->mAutoTile && !res->getHost() && index > 0)
+				{
+					const LLRect& cur_rect = res->getRect();
+					LLRect next_rect = getFloaterRect(groupname);
+					next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, cur_rect.getWidth(), cur_rect.getHeight());
+					res->setRect(next_rect);
+					res->setRectControl(LLStringUtil::null); // don't save rect of tiled floaters
+					gFloaterView->adjustToFitScreen(res, true);
+				}
+				else
+				{
+					gFloaterView->adjustToFitScreen(res, false);
+				}
+				list.push_back(res);
+			}
+		}
+		if (!res)
+		{
+			llwarns << "Floater type: '" << name << "' not registered." << llendl;
+		}
+	}
+	return res;
+}
+
+//static
+LLFloater* LLFloaterReg::removeInstance(const std::string& name, const LLSD& key)
+{
+	LLFloater* res = NULL;
+	const std::string& groupname = sGroupMap[name];
+	if (!groupname.empty())
+	{
+		instance_list_t& list = sInstanceMap[groupname];
+		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
+		{
+			LLFloater* inst = *iter;
+			if (inst->matchesKey(key))
+			{
+				res = inst;
+				list.erase(iter);
+				break;
+			}
+		}
+	}
+	return res;
+}
+
+//static
+// returns true if the instance existed
+bool LLFloaterReg::destroyInstance(const std::string& name, const LLSD& key)
+{
+	LLFloater* inst = removeInstance(name, key);
+	if (inst)
+	{
+		delete inst;
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// Iterators
+//static
+LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::string& name)
+{
+	instance_map_t::iterator iter = sInstanceMap.find(name);
+	if (iter != sInstanceMap.end())
+	{
+		return iter->second;
+	}
+	else
+	{
+		return sNullInstanceList;
+	}
+}
+
+// Visibility Management
+
+//static
+LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) 
+{
+	LLFloater* instance = getInstance(name, key); 
+	if (instance) 
+	{
+		instance->openFloater(key);
+		if (focus)
+			instance->setFocus(TRUE);
+	}
+	return instance;
+}
+
+//static
+// returns true if the instance exists
+bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key) 
+{ 
+	LLFloater* instance = findInstance(name, key); 
+	if (instance)
+	{
+		// When toggling *visibility*, close the host instead of the floater when hosted
+		if (instance->getHost())
+			instance->getHost()->closeFloater();
+		else
+			instance->closeFloater();
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+//static
+// returns true if the instance is visible when completed
+bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
+{
+	LLFloater* instance = findInstance(name, key); 
+	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
+	{
+		// When toggling *visibility*, close the host instead of the floater when hosted
+		if (instance->getHost())
+			instance->getHost()->closeFloater();
+		else
+			instance->closeFloater();
+		return false;
+	}
+	else
+	{
+		return showInstance(name, key, TRUE) ? true : false;
+	}
+}
+
+//static
+// returns true if the instance exists and is visible
+bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
+{
+	LLFloater* instance = findInstance(name, key); 
+	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+//static
+void LLFloaterReg::showInitialVisibleInstances() 
+{
+	// Iterate through alll registered instance names and show any with a save visible state
+	for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
+	{
+		const std::string& name = iter->first;
+		std::string controlname = getVisibilityControlName(name);
+		if (LLUI::sSettingGroups["floater"]->controlExists(controlname))
+		{
+			BOOL isvis = LLUI::sSettingGroups["floater"]->getBOOL(controlname);
+			if (isvis)
+			{
+				showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true
+			}
+		}
+	}
+}
+
+//static
+void LLFloaterReg::hideVisibleInstances(const std::set<std::string>& exceptions)
+{
+	// Iterate through alll active instances and hide them
+	for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
+	{
+		const std::string& name = iter->first;
+		if (exceptions.find(name) != exceptions.end())
+			continue;
+		instance_list_t& list = iter->second;
+		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
+		{
+			LLFloater* floater = *iter;
+			floater->pushVisible(FALSE);
+		}
+	}
+}
+
+//static
+void LLFloaterReg::restoreVisibleInstances()
+{
+	// Iterate through all active instances and restore visibility
+	for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
+	{
+		instance_list_t& list = iter->second;
+		for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
+		{
+			LLFloater* floater = *iter;
+			floater->popVisible();
+		}
+	}
+}
+
+//static
+std::string LLFloaterReg::getRectControlName(const std::string& name)
+{
+	std::string res = std::string("floater_rect_") + name;
+	LLStringUtil::replaceChar( res, ' ', '_' );
+	return res;
+}
+
+//static
+std::string LLFloaterReg::declareRectControl(const std::string& name)
+{
+	std::string controlname = getRectControlName(name);
+	LLUI::sSettingGroups["floater"]->declareRect(controlname, LLRect(),
+												 llformat("Window Position and Size for %s", name.c_str()),
+												 TRUE);
+	return controlname;
+}
+
+//static
+std::string LLFloaterReg::getVisibilityControlName(const std::string& name)
+{
+	std::string res = std::string("floater_vis_") + name;
+	LLStringUtil::replaceChar( res, ' ', '_' );
+	return res;
+}
+
+//static
+std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
+{
+	std::string controlname = getVisibilityControlName(name);
+	LLUI::sSettingGroups["floater"]->declareBOOL(controlname, FALSE,
+												 llformat("Window Visibility for %s", name.c_str()),
+												 TRUE);
+	return controlname;
+}
+
+// Callbacks
+
+// static
+// Call once (i.e use for init callbacks)
+void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname)
+{
+	// Get the visibility control name for the floater
+	std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString());
+	// Set the control value to the floater visibility control (Sets the value as well)
+	ctrl->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name));
+}
+
+// callback args may use "floatername.key" format
+static void parse_name_key(std::string& name, LLSD& key)
+{
+	std::string instname = name;
+	std::size_t dotpos = instname.find(".");
+	if (dotpos != std::string::npos)
+	{
+		name = instname.substr(0, dotpos);
+		key = LLSD(instname.substr(dotpos+1, std::string::npos));
+	}
+}
+
+//static
+void LLFloaterReg::showFloaterInstance(const LLSD& sdname)
+{
+	LLSD key;
+	std::string name = sdname.asString();
+	parse_name_key(name, key);
+	showInstance(name, key, TRUE);
+}
+//static
+void LLFloaterReg::hideFloaterInstance(const LLSD& sdname)
+{
+	LLSD key;
+	std::string name = sdname.asString();
+	parse_name_key(name, key);
+	hideInstance(name, key);
+}
+//static
+void LLFloaterReg::toggleFloaterInstance(const LLSD& sdname)
+{
+	LLSD key;
+	std::string name = sdname.asString();
+	parse_name_key(name, key);
+	toggleInstance(name, key);
+}
+
+//static
+bool LLFloaterReg::floaterInstanceVisible(const LLSD& sdname)
+{
+	LLSD key;
+	std::string name = sdname.asString();
+	parse_name_key(name, key);
+	return instanceVisible(name, key);
+}
+
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
new file mode 100644
index 0000000000..af1bfc5ec1
--- /dev/null
+++ b/indra/llui/llfloaterreg.h
@@ -0,0 +1,149 @@
+/** 
+ * @file llfloaterreg.h
+ * @brief LLFloaterReg Floater Registration Class
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+/// llcommon
+#include "llboost.h"
+#include "llrect.h"
+#include "llstl.h"
+#include "llsd.h"
+
+/// llui
+#include "lluictrl.h"
+
+#include <boost/function.hpp>
+
+//*******************************************************
+//
+// Floater Class Registry
+//
+
+class LLFloater;
+
+typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc;
+
+class LLFloaterReg
+{
+public:
+	// We use a list of LLFloater's instead of a set for two reasons:
+	// 1) With a list we have a predictable ordering, useful for finding the last opened floater of a given type.
+	// 2) We can change the key of a floater without altering the list.
+	typedef std::list<LLFloater*> instance_list_t;
+	typedef const instance_list_t const_instance_list_t;
+	typedef std::map<std::string, instance_list_t> instance_map_t;
+
+	struct BuildData
+	{
+		LLFloaterBuildFunc mFunc;
+		std::string mFile;
+	};
+	typedef std::map<std::string, BuildData> build_map_t;
+	
+private:
+	static instance_list_t sNullInstanceList;
+	static instance_map_t sInstanceMap;
+	static build_map_t sBuildMap;
+	static std::map<std::string,std::string> sGroupMap;
+	
+public:
+	// Registration
+	
+	// usage: LLFloaterClassRegistry::add("foo", (LLFloaterBuildFunc)&LLFloaterClassRegistry::build<LLFloaterFoo>);
+	template <class T>
+	static LLFloater* build(const LLSD& key)
+	{
+		T* floater = new T(key);
+		return floater;
+	}
+	
+	static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func,
+					const std::string& groupname = LLStringUtil::null);
+
+	// Helpers
+	static LLRect getFloaterRect(const std::string& name);
+	
+	// Find / get (create) / remove / destroy
+	static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD());
+	static LLFloater* getInstance(const std::string& name, const LLSD& key = LLSD());
+	static LLFloater* removeInstance(const std::string& name, const LLSD& key = LLSD());
+	static bool destroyInstance(const std::string& name, const LLSD& key = LLSD());
+	
+	// Iterators
+	static const_instance_list_t& getFloaterList(const std::string& name);
+
+	// Visibility Management
+	// return NULL if instance not found or can't create instance (no builder)
+	static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE);
+	// Close a floater (may destroy or set invisible)
+	// return false if can't find instance
+	static bool hideInstance(const std::string& name, const LLSD& key = LLSD());
+	// return true if instance is visible:
+	static bool toggleInstance(const std::string& name, const LLSD& key = LLSD());
+	static bool instanceVisible(const std::string& name, const LLSD& key = LLSD());
+
+	static void showInitialVisibleInstances();
+	static void hideVisibleInstances(const std::set<std::string>& exceptions = std::set<std::string>());
+	static void restoreVisibleInstances();
+
+	// Control Variables
+	static std::string getRectControlName(const std::string& name);
+	static std::string declareRectControl(const std::string& name);
+	static std::string getVisibilityControlName(const std::string& name);
+	static std::string declareVisibilityControl(const std::string& name);
+
+	// Callback wrappers
+	static void initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname);
+	static void showFloaterInstance(const LLSD& sdname);
+	static void hideFloaterInstance(const LLSD& sdname);
+	static void toggleFloaterInstance(const LLSD& sdname);
+	static bool floaterInstanceVisible(const LLSD& sdname);
+	
+	// Typed find / get / show
+	template <class T>
+	static T* findTypedInstance(const std::string& name, const LLSD& key = LLSD())
+	{
+		return dynamic_cast<T*>(findInstance(name, key));
+	}
+
+	template <class T>
+	static T* getTypedInstance(const std::string& name, const LLSD& key = LLSD())
+	{
+		return dynamic_cast<T*>(getInstance(name, key));
+	}
+
+	template <class T>
+	static T* showTypedInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE)
+	{
+		return dynamic_cast<T*>(showInstance(name, key, focus));
+	}
+	
+};
+
diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp
new file mode 100644
index 0000000000..6b7c174726
--- /dev/null
+++ b/indra/llui/llflyoutbutton.cpp
@@ -0,0 +1,94 @@
+/** 
+ * @file llflyoutbutton.cpp
+ * @brief LLFlyoutButton base class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+// file includes
+#include "llflyoutbutton.h"
+
+static LLRegisterWidget<LLFlyoutButton> r2("flyout_button");
+
+const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
+
+LLFlyoutButton::LLFlyoutButton(const Params& p)
+:	LLComboBox(p),
+	mToggleState(FALSE),
+	mActionButton(NULL)
+{
+	// Always use text box 
+	// Text label button
+	LLButton::Params bp(p.action_button);
+	bp.name(p.label);
+	bp.rect.left(0).bottom(0).width(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH).height(getRect().getHeight());
+	bp.click_callback.function(boost::bind(&LLFlyoutButton::onActionButtonClick, this, _2));
+	bp.follows.flags(FOLLOWS_ALL);
+
+	mActionButton = LLUICtrlFactory::create<LLButton>(bp);
+	addChild(mActionButton);
+
+	mButton->setOrigin(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
+	mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
+	mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+	mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
+}
+
+void LLFlyoutButton::onActionButtonClick(const LLSD& data)
+{
+	// remember last list selection?
+	mList->deselect();
+	onCommit();
+}
+
+void LLFlyoutButton::draw()
+{
+	mActionButton->setToggleState(mToggleState);
+	mButton->setToggleState(mToggleState);
+
+	//FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
+	// the label reflects the last selected item, for now we have to manually remove the label
+	mButton->setLabel(LLStringUtil::null);
+	LLComboBox::draw();	
+}
+
+void LLFlyoutButton::setEnabled(BOOL enabled)
+{
+	mActionButton->setEnabled(enabled);
+	LLComboBox::setEnabled(enabled);
+}
+
+
+void LLFlyoutButton::setToggleState(BOOL state)
+{
+	mToggleState = state;
+}
+
+
diff --git a/indra/llui/llflyoutbutton.h b/indra/llui/llflyoutbutton.h
new file mode 100644
index 0000000000..f60fe1eb35
--- /dev/null
+++ b/indra/llui/llflyoutbutton.h
@@ -0,0 +1,71 @@
+/** 
+ * @file llflyoutbutton.h
+ * @brief LLFlyoutButton base class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// A control that displays the name of the chosen item, which when clicked
+// shows a scrolling box of choices.
+
+#ifndef LL_LLFLYOUTBUTTON_H
+#define LL_LLFLYOUTBUTTON_H
+
+#include "llcombobox.h"
+
+// Classes
+
+class LLFlyoutButton : public LLComboBox
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLComboBox::Params>
+	{
+		Optional<LLButton::Params> action_button;
+
+		Params()
+		:	action_button("action_button")
+		{}
+
+	};
+protected:
+	LLFlyoutButton(const Params&);
+	friend class LLUICtrlFactory;
+public:
+	virtual void	draw();
+	virtual void	setEnabled(BOOL enabled);
+
+	void setToggleState(BOOL state);
+
+	void onActionButtonClick(const LLSD& data);
+
+protected:
+	LLButton*				mActionButton;
+	BOOL					mToggleState;
+};
+
+#endif // LL_LLFLYOUTBUTTON_H
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 661ffdd467..9a4ec7627e 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -220,24 +220,19 @@ void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
 	{
 		LLMouseHandler* old_captor = mMouseCaptor;
 		mMouseCaptor = new_captor;
-		/*
-		if (new_captor)
+		
+		if (LLView::sDebugMouseHandling)
 		{
-			if ( new_captor->getName() == "Stickto")
+			if (new_captor)
 			{
 				llinfos << "New mouse captor: " << new_captor->getName() << llendl;
 			}
 			else
 			{
-				llinfos << "New mouse captor: " << new_captor->getName() << llendl;
+				llinfos << "New mouse captor: NULL" << llendl;
 			}
 		}
-		else
-		{
-			llinfos << "New mouse captor: NULL" << llendl;
-		}
-		*/
-
+			
 		if( old_captor )
 		{
 			old_captor->onMouseCaptureLost();
@@ -295,7 +290,7 @@ void LLFocusMgr::setTopCtrl( LLUICtrl* new_top  )
 
 		if (old_top)
 		{
-			old_top->onLostTop();
+			old_top->onTopLost();
 		}
 	}
 }
@@ -328,7 +323,8 @@ F32 LLFocusMgr::getFocusFlashAmt() const
 
 LLColor4 LLFocusMgr::getFocusColor() const
 {
-	LLColor4 focus_color = lerp(LLUI::sColorsGroup->getColor( "FocusColor" ), LLColor4::white, getFocusFlashAmt());
+	static LLUICachedControl<LLColor4> focus_color_cached ("FocusColor", *(new LLColor4));
+	LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt());
 	// de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem)
 	if (!mAppHasFocus)
 	{
diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h
index 8864f7af15..2c0bcc6012 100644
--- a/indra/llui/llfunctorregistry.h
+++ b/indra/llui/llfunctorregistry.h
@@ -40,7 +40,7 @@
 #include <boost/function.hpp>
 
 #include "llsd.h"
-#include "llmemory.h"
+#include "llsingleton.h"
 
 /**
  * @class LLFunctorRegistry
diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp
index cb3b2a3a62..d01679cd1c 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -40,65 +40,33 @@
 #include "llcontrol.h"
 #include "llui.h"
 #include "lluictrlfactory.h"
-
-const F32 RESOLUTION_BUMP = 1.f;
+#include "lluiimage.h"
 
 static LLRegisterWidget<LLIconCtrl> r("icon");
 
-LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id)
-:	LLUICtrl(name, 
-			 rect, 
-			 FALSE, // mouse opaque
-			 NULL, NULL, 
-			 FOLLOWS_LEFT | FOLLOWS_TOP),
-	mColor( LLColor4::white )
-{
-	setImage( image_id );
-	setTabStop(FALSE);
-}
-
-LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name)
-:	LLUICtrl(name, 
-			 rect, 
-			 FALSE, // mouse opaque
-			 NULL, NULL, 
-			 FOLLOWS_LEFT | FOLLOWS_TOP),
-	mColor( LLColor4::white ),
-	mImageName(image_name)
-{
-	setImage( image_name );
-	setTabStop(FALSE);
-}
-
-
-LLIconCtrl::~LLIconCtrl()
+LLIconCtrl::Params::Params()
+:	image("image_name"),
+	color("color"),
+	scale_image("scale_image")
 {
-	mImagep = NULL;
+	tab_stop = false;
+	mouse_opaque = false;
 }
 
-
-void LLIconCtrl::setImage(const std::string& image_name)
+LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p)
+:	LLUICtrl(p),
+	mColor(p.color()),
+	mImagep(p.image)
 {
-	//RN: support UUIDs masquerading as strings
-	if (LLUUID::validate(image_name))
-	{
-		mImageID = LLUUID(image_name);
-
-		setImage(mImageID);
-	}
-	else
+	if (mImagep.notNull())
 	{
-		mImageName = image_name;
-		mImagep = LLUI::sImageProvider->getUIImage(image_name);
-		mImageID.setNull();
+		LLUICtrl::setValue(mImagep->getName());
 	}
 }
 
-void LLIconCtrl::setImage(const LLUUID& image_id)
+LLIconCtrl::~LLIconCtrl()
 {
-	mImageName.clear();
-	mImagep = LLUI::sImageProvider->getUIImageByID(image_id);
-	mImageID = image_id;
+	mImagep = NULL;
 }
 
 
@@ -106,69 +74,37 @@ void LLIconCtrl::draw()
 {
 	if( mImagep.notNull() )
 	{
-		mImagep->draw(getLocalRect(), mColor );
+		mImagep->draw(getLocalRect(), mColor.get() );
 	}
 
 	LLUICtrl::draw();
 }
 
 // virtual
+// value might be a string or a UUID
 void LLIconCtrl::setValue(const LLSD& value )
 {
-	if (value.isUUID())
+	LLSD tvalue(value);
+	if (value.isString() && LLUUID::validate(value.asString()))
 	{
-		setImage(value.asUUID());
+		//RN: support UUIDs masquerading as strings
+		tvalue = LLSD(LLUUID(value.asString()));
 	}
-	else
+	LLUICtrl::setValue(tvalue);
+	if (tvalue.isUUID())
 	{
-		setImage(value.asString());
+		mImagep = LLUI::getUIImageByID(tvalue.asUUID());
 	}
-}
-
-// virtual
-LLSD LLIconCtrl::getValue() const
-{
-	LLSD ret = getImage();
-	return ret;
-}
-
-// virtual
-LLXMLNodePtr LLIconCtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	if (mImageName != "")
+	else
 	{
-		node->createChild("image_name", TRUE)->setStringValue(mImageName);
+		mImagep = LLUI::getUIImage(tvalue.asString());
 	}
-
-	node->createChild("color", TRUE)->setFloatValue(4, mColor.mV);
-
-	return node;
 }
 
-LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+std::string LLIconCtrl::getImageName() const
 {
-	std::string name("icon");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	std::string image_name;
-	if (node->hasAttribute("image_name"))
-	{
-		node->getAttributeString("image_name", image_name);
-	}
-
-	LLColor4 color(LLColor4::white);
-	LLUICtrlFactory::getAttributeColor(node,"color", color);
-
-	LLIconCtrl* icon = new LLIconCtrl(name, rect, image_name);
-
-	icon->setColor(color);
-
-	icon->initFromXML(node, parent);
-
-	return icon;
+	if (getValue().isString())
+		return getValue().asString();
+	else
+		return std::string();
 }
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index 50778cf226..ad0f6f563f 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -45,35 +45,37 @@ class LLUICtrlFactory;
 //
 // Classes
 //
+
+// 
 class LLIconCtrl
 : public LLUICtrl
 {
 public:
-	LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id);
-	LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name);
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<LLUIImage*>	image;
+		Optional<LLUIColor>		color;
+		Deprecated				scale_image;
+		Params();
+	};
+protected:
+	LLIconCtrl(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual ~LLIconCtrl();
 
 	// llview overrides
 	virtual void	draw();
 
-	void			setImage(const std::string& image_name);
-	void			setImage(const LLUUID& image_name);
-	const LLUUID	&getImage() const						{ return mImageID; }
-	std::string		getImageName() const						{ return mImageName; }
-
-	// Takes a UUID, wraps get/setImage
+	// lluictrl overrides
 	virtual void	setValue(const LLSD& value );
-	virtual LLSD	getValue() const;
 
-	void			setColor(const LLColor4& color) { mColor = color; }
+	std::string	getImageName() const;
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	void			setColor(const LLColor4& color) { mColor = color; }
 
 private:
-	LLColor4		mColor;
-	std::string		mImageName;
-	LLUUID			mImageID;
+	LLUIColor mColor;
 	LLPointer<LLUIImage>	mImagep;
 };
 
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp
index 51ef3dbacf..30796a5ab9 100644
--- a/indra/llui/llkeywords.cpp
+++ b/indra/llui/llkeywords.cpp
@@ -223,8 +223,8 @@ LLColor3 LLKeywords::readColor( const std::string& s )
 {
 	F32 r, g, b;
 	r = g = b = 0.0f;
-	S32 read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b );
-	if( read != 3 )	/* Flawfinder: ignore */
+	S32 values_read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b );
+	if( values_read != 3 )
 	{
 		llinfos << " poorly formed color in keyword file" << llendl;
 	}
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
new file mode 100644
index 0000000000..483c1358ae
--- /dev/null
+++ b/indra/llui/lllayoutstack.cpp
@@ -0,0 +1,718 @@
+/** 
+ * @file lllayoutstack.cpp
+ * @brief LLLayout class - dynamic stacking of UI elements
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Opaque view with a background and a border.  Can contain LLUICtrls.
+
+#include "linden_common.h"
+
+#include "lllayoutstack.h"
+#include "llresizebar.h"
+#include "llcriticaldamp.h"
+
+//
+// LLLayoutStack
+//
+struct LLLayoutStack::LLEmbeddedPanel
+{
+	LLEmbeddedPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize)	:	mPanel(panelp), 
+		mMinWidth(min_width), 
+		mMinHeight(min_height),
+		mAutoResize(auto_resize),
+		mUserResize(user_resize),
+		mOrientation(orientation),
+		mCollapsed(FALSE),
+		mCollapseAmt(0.f),
+		mVisibleAmt(1.f), // default to fully visible
+		mResizeBar(NULL) 
+	{
+		LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
+		LLRect resize_bar_rect = panelp->getRect();
+
+		S32 min_dim;
+		if (orientation == HORIZONTAL)
+		{
+			min_dim = mMinHeight;
+		}
+		else
+		{
+			min_dim = mMinWidth;
+		}
+		LLResizeBar::Params p;
+		p.name("resize");
+		p.resizing_view(mPanel);
+		p.min_size(min_dim);
+		p.side(side);
+		p.snapping_enabled(false);
+		mResizeBar = LLUICtrlFactory::create<LLResizeBar>(p);
+		// panels initialized as hidden should not start out partially visible
+		if (!mPanel->getVisible())
+		{
+			mVisibleAmt = 0.f;
+		}
+	}
+
+	~LLEmbeddedPanel()
+	{
+		// probably not necessary, but...
+		delete mResizeBar;
+		mResizeBar = NULL;
+	}
+
+	F32 getCollapseFactor()
+	{
+		if (mOrientation == HORIZONTAL)
+		{
+			F32 collapse_amt = 
+				clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
+			return mVisibleAmt * collapse_amt;
+		}
+		else
+		{
+			F32 collapse_amt = 
+				clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
+			return mVisibleAmt * collapse_amt;
+		}
+	}
+
+	LLPanel* mPanel;
+	S32 mMinWidth;
+	S32 mMinHeight;
+	BOOL mAutoResize;
+	BOOL mUserResize;
+	BOOL mCollapsed;
+	LLResizeBar* mResizeBar;
+	ELayoutOrientation mOrientation;
+	F32 mVisibleAmt;
+	F32 mCollapseAmt;
+};
+
+static LLRegisterWidget<LLLayoutStack> r2("layout_stack", &LLLayoutStack::fromXML);
+
+LLLayoutStack::Params::Params()
+:	orientation("orientation", std::string("vertical")),
+	border_size("border_size", LLCachedControl<S32>(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0))
+{
+	name="stack";
+}
+
+LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) 
+:	LLView(p),
+	mMinWidth(0),
+	mMinHeight(0),
+	mPanelSpacing(p.border_size),
+	mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL)
+{}
+
+LLLayoutStack::~LLLayoutStack()
+{
+	e_panel_list_t panels = mPanels; // copy list of panel pointers
+	mPanels.clear(); // clear so that removeChild() calls don't cause trouble
+	std::for_each(panels.begin(), panels.end(), DeletePointer());
+}
+
+void LLLayoutStack::draw()
+{
+	updateLayout();
+
+	e_panel_list_t::iterator panel_it;
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		// clip to layout rectangle, not bounding rectangle
+		LLRect clip_rect = (*panel_it)->mPanel->getRect();
+		// scale clipping rectangle by visible amount
+		if (mOrientation == HORIZONTAL)
+		{
+			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
+		}
+		else
+		{
+			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
+		}
+
+		LLPanel* panelp = (*panel_it)->mPanel;
+
+		LLLocalClipRect clip(clip_rect);
+		// only force drawing invisible children if visible amount is non-zero
+		drawChild(panelp, 0, 0, !clip_rect.isNull());
+	}
+}
+
+void LLLayoutStack::removeChild(LLView* view)
+{
+	LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast<LLPanel*>(view));
+
+	if (embedded_panelp)
+	{
+		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
+		delete embedded_panelp;
+	}
+
+	// need to update resizebars
+
+	calcMinExtents();
+
+	LLView::removeChild(view);
+}
+
+BOOL LLLayoutStack::postBuild()
+{
+	updateLayout();
+	return TRUE;
+}
+
+static void get_attribute_s32_and_write(LLXMLNodePtr node,
+										const char* name,
+										S32 *value,
+										S32 default_value,
+										LLXMLNodePtr output_child)
+{
+	BOOL has_attr = node->getAttributeS32(name, *value);
+	if (has_attr && *value != default_value && output_child)
+	{
+		// create an attribute child node
+		LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
+		child_attr->setIntValue(*value);
+	}
+}
+
+static void get_attribute_bool_and_write(LLXMLNodePtr node,
+										const char* name,
+										BOOL *value,
+										BOOL default_value,
+										LLXMLNodePtr output_child)
+{
+	BOOL has_attr = node->getAttributeBOOL(name, *value);
+	if (has_attr && *value != default_value && output_child)
+	{
+		LLXMLNodePtr child_attr = output_child->createChild(name, TRUE);
+		child_attr->setBoolValue(*value);
+	}
+}
+//static 
+LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
+{
+	LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams<LLLayoutStack::Params>());
+	LLXUIParser::instance().readXUI(node, p);
+	setupParams(p, parent);
+	LLLayoutStack* layout_stackp = LLUICtrlFactory::create<LLLayoutStack>(p);
+
+	if (parent && layout_stackp)
+	{
+		S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup();
+
+		parent->addChild(layout_stackp, tab_group);
+	}
+
+	if (output_node)
+	{
+		Params output_params(p);
+		setupParamsForExport(output_params, parent);
+		LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams<LLLayoutStack::Params>());
+		output_node->setName(node->getName()->mString);
+		LLXUIParser::instance().writeXUI(
+			output_node, output_params, &default_params);
+	}
+
+	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
+	{
+		const S32 DEFAULT_MIN_WIDTH = 0;
+		const S32 DEFAULT_MIN_HEIGHT = 0;
+		const BOOL DEFAULT_AUTO_RESIZE = TRUE;
+
+		S32 min_width = DEFAULT_MIN_WIDTH;
+		S32 min_height = DEFAULT_MIN_HEIGHT;
+		BOOL auto_resize = DEFAULT_AUTO_RESIZE;
+
+		LLXMLNodePtr output_child;
+		if (output_node) 
+		{
+			output_child = output_node->createChild("", FALSE);
+		}
+
+		// Layout stack allows child nodes to acquire additional attributes,
+		// such as "min_width" in:  <button label="Foo" min_width="100"/>
+		// If these attributes exist and have non-default values, write them
+		// to the output node.
+		get_attribute_s32_and_write(child_node, "min_width", &min_width,
+			DEFAULT_MIN_WIDTH, output_child);
+		get_attribute_s32_and_write(child_node, "min_height", &min_height,
+			DEFAULT_MIN_HEIGHT, output_child);
+		get_attribute_bool_and_write(child_node, "auto_resize", &auto_resize,
+			DEFAULT_AUTO_RESIZE, output_child);
+
+		if (child_node->hasName("layout_panel"))
+		{
+			BOOL user_resize = TRUE;
+			get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
+				TRUE, output_child);
+			LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child_node, layout_stackp, output_child);
+			if (panelp)
+			{
+				panelp->setFollowsNone();
+				layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
+			}
+		}
+		else
+		{
+			BOOL user_resize = FALSE;
+			get_attribute_bool_and_write(child_node, "user_resize", &user_resize,
+				FALSE, output_child);
+
+			LLPanel* panelp = new LLPanel();
+			LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, output_child);
+			if (new_child)
+			{
+				// put child in new embedded panel
+				layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
+				// resize panel to contain widget and move widget to be contained in panel
+				panelp->setRect(new_child->getRect());
+				new_child->setOrigin(0, 0);
+			}
+			else
+			{
+				panelp->die();
+			}
+		}
+		
+		if (output_child && !output_child->mChildren && output_child->mAttributes.empty() && output_child->getValue().empty())
+		{
+			output_node->deleteChild(output_child);
+		}
+	}
+
+	if (!layout_stackp->postBuild())
+	{
+		delete layout_stackp;
+		return NULL;
+	}
+
+	return layout_stackp;
+}
+
+S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
+{
+	// if we are spanning our children (crude upward propagation of size)
+	// then don't enforce our size on our children
+	if (mOrientation == HORIZONTAL)
+	{
+		cur_height = llmax(mMinHeight, getRect().getHeight());
+	}
+
+	return cur_height;
+}
+
+S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
+{
+	// if we are spanning our children (crude upward propagation of size)
+	// then don't enforce our size on our children
+	if (mOrientation == VERTICAL)
+	{
+		cur_width = llmax(mMinWidth, getRect().getWidth());
+	}
+
+	return cur_width;
+}
+
+void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
+{
+	// panel starts off invisible (collapsed)
+	if (animate == ANIMATE)
+	{
+		panel->setVisible(FALSE);
+	}
+	LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
+	
+	mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
+	
+	if (panel->getParent() != this) 
+	{
+		addChild(panel);
+	}
+	addChild(embedded_panel->mResizeBar);
+
+	// bring all resize bars to the front so that they are clickable even over the panels
+	// with a bit of overlap
+	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
+		sendChildToFront(resize_barp);
+	}
+
+	// start expanding panel animation
+	if (animate == ANIMATE)
+	{
+		panel->setVisible(TRUE);
+	}
+}
+
+void LLLayoutStack::removePanel(LLPanel* panel)
+{
+	removeChild(panel);
+}
+
+void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
+{
+	LLEmbeddedPanel* panel_container = findEmbeddedPanel(panel);
+	if (!panel_container) return;
+
+	panel_container->mCollapsed = collapsed;
+}
+
+void LLLayoutStack::updateLayout(BOOL force_resize)
+{
+	static LLUICachedControl<S32> resize_bar_overlap ("UIResizeBarOverlap", 0);
+	calcMinExtents();
+
+	// calculate current extents
+	S32 total_width = 0;
+	S32 total_height = 0;
+
+	const F32 ANIM_OPEN_TIME = 0.02f;
+	const F32 ANIM_CLOSE_TIME = 0.03f;
+
+	e_panel_list_t::iterator panel_it;
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)
+	{
+		LLPanel* panelp = (*panel_it)->mPanel;
+		if (panelp->getVisible()) 
+		{
+			(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
+			if ((*panel_it)->mVisibleAmt > 0.99f)
+			{
+				(*panel_it)->mVisibleAmt = 1.f;
+			}
+		}
+		else // not visible
+		{
+			(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+			if ((*panel_it)->mVisibleAmt < 0.001f)
+			{
+				(*panel_it)->mVisibleAmt = 0.f;
+			}
+		}
+
+		if ((*panel_it)->mCollapsed)
+		{
+			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+		}
+		else
+		{
+			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
+		}
+
+		if (mOrientation == HORIZONTAL)
+		{
+			// enforce minimize size constraint by default
+			if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
+			{
+				panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
+			}
+        	total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
+        	// want n-1 panel gaps for n panels
+			if (panel_it != mPanels.begin())
+			{
+				total_width += mPanelSpacing;
+			}
+		}
+		else //VERTICAL
+		{
+			// enforce minimize size constraint by default
+			if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
+			{
+				panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
+			}
+			total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
+			if (panel_it != mPanels.begin())
+			{
+				total_height += mPanelSpacing;
+			}
+		}
+	}
+
+	S32 num_resizable_panels = 0;
+	S32 shrink_headroom_available = 0;
+	S32 shrink_headroom_total = 0;
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		// panels that are not fully visible do not count towards shrink headroom
+		if ((*panel_it)->getCollapseFactor() < 1.f) 
+		{
+			continue;
+		}
+
+		// if currently resizing a panel or the panel is flagged as not automatically resizing
+		// only track total available headroom, but don't use it for automatic resize logic
+		if ((*panel_it)->mResizeBar->hasMouseCapture() 
+			|| (!(*panel_it)->mAutoResize 
+				&& !force_resize))
+		{
+			if (mOrientation == HORIZONTAL)
+			{
+				shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
+			}
+			else //VERTICAL
+			{
+				shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
+			}
+		}
+		else
+		{
+			num_resizable_panels++;
+			if (mOrientation == HORIZONTAL)
+			{
+				shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
+				shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
+			}
+			else //VERTICAL
+			{
+				shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
+				shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
+			}
+		}
+	}
+
+	// calculate how many pixels need to be distributed among layout panels
+	// positive means panels need to grow, negative means shrink
+	S32 pixels_to_distribute;
+	if (mOrientation == HORIZONTAL)
+	{
+		pixels_to_distribute = getRect().getWidth() - total_width;
+	}
+	else //VERTICAL
+	{
+		pixels_to_distribute = getRect().getHeight() - total_height;
+	}
+
+	// now we distribute the pixels...
+	S32 cur_x = 0;
+	S32 cur_y = getRect().getHeight();
+
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		LLPanel* panelp = (*panel_it)->mPanel;
+
+		S32 cur_width = panelp->getRect().getWidth();
+		S32 cur_height = panelp->getRect().getHeight();
+		S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
+		S32 new_height = llmax((*panel_it)->mMinHeight, cur_height); 
+
+		S32 delta_size = 0;
+
+		// if panel can automatically resize (not animating, and resize flag set)...
+		if ((*panel_it)->getCollapseFactor() == 1.f 
+			&& (force_resize || (*panel_it)->mAutoResize) 
+			&& !(*panel_it)->mResizeBar->hasMouseCapture()) 
+		{
+			if (mOrientation == HORIZONTAL)
+			{
+				// if we're shrinking
+				if (pixels_to_distribute < 0)
+				{
+					// shrink proportionally to amount over minimum
+					// so we can do this in one pass
+					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
+					shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
+				}
+				else
+				{
+					// grow all elements equally
+					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
+					num_resizable_panels--;
+				}
+				pixels_to_distribute -= delta_size;
+				new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
+			}
+			else
+			{
+				new_width = getDefaultWidth(new_width);
+			}
+
+			if (mOrientation == VERTICAL)
+			{
+				if (pixels_to_distribute < 0)
+				{
+					// shrink proportionally to amount over minimum
+					// so we can do this in one pass
+					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
+					shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
+				}
+				else
+				{
+					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
+					num_resizable_panels--;
+				}
+				pixels_to_distribute -= delta_size;
+				new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
+			}
+			else
+			{
+				new_height = getDefaultHeight(new_height);
+			}
+		}
+		else
+		{
+			if (mOrientation == HORIZONTAL)
+			{
+				new_height = getDefaultHeight(new_height);
+			}
+			else // VERTICAL
+			{
+				new_width = getDefaultWidth(new_width);
+			}
+		}
+
+		// adjust running headroom count based on new sizes
+		shrink_headroom_total += delta_size;
+
+		panelp->reshape(new_width, new_height);
+		panelp->setOrigin(cur_x, cur_y - new_height);
+
+		LLRect panel_rect = panelp->getRect();
+		LLRect resize_bar_rect = panel_rect;
+		if (mOrientation == HORIZONTAL)
+		{
+			resize_bar_rect.mLeft = panel_rect.mRight - resize_bar_overlap;
+			resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + resize_bar_overlap;
+		}
+		else
+		{
+			resize_bar_rect.mTop = panel_rect.mBottom + resize_bar_overlap;
+			resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - resize_bar_overlap;
+		}
+		(*panel_it)->mResizeBar->setRect(resize_bar_rect);
+
+		if (mOrientation == HORIZONTAL)
+		{
+			cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
+		}
+		else //VERTICAL
+		{
+			cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
+		}
+	}
+
+	// update resize bars with new limits
+	LLResizeBar* last_resize_bar = NULL;
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		LLPanel* panelp = (*panel_it)->mPanel;
+
+		if (mOrientation == HORIZONTAL)
+		{
+			(*panel_it)->mResizeBar->setResizeLimits(
+				(*panel_it)->mMinWidth, 
+				(*panel_it)->mMinWidth + shrink_headroom_total);
+		}
+		else //VERTICAL
+		{
+			(*panel_it)->mResizeBar->setResizeLimits(
+				(*panel_it)->mMinHeight, 
+				(*panel_it)->mMinHeight + shrink_headroom_total);
+		}
+
+		// toggle resize bars based on panel visibility, resizability, etc
+		BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
+		(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
+
+		if (resize_bar_enabled)
+		{
+			last_resize_bar = (*panel_it)->mResizeBar;
+		}
+	}
+
+	// hide last resize bar as there is nothing past it
+	// resize bars need to be in between two resizable panels
+	if (last_resize_bar)
+	{
+		last_resize_bar->setVisible(FALSE);
+	}
+
+	// not enough room to fit existing contents
+	if (force_resize == FALSE
+		// layout did not complete by reaching target position
+		&& ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
+			|| (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
+	{
+		// do another layout pass with all stacked elements contributing
+		// even those that don't usually resize
+		llassert_always(force_resize == FALSE);
+		updateLayout(TRUE);
+	}
+} // end LLLayoutStack::updateLayout
+
+
+LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
+{
+	if (!panelp) return NULL;
+
+	e_panel_list_t::const_iterator panel_it;
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		if ((*panel_it)->mPanel == panelp)
+		{
+			return *panel_it;
+		}
+	}
+	return NULL;
+}
+
+// Compute sum of min_width or min_height of children
+void LLLayoutStack::calcMinExtents()
+{
+	mMinWidth = 0;
+	mMinHeight = 0;
+
+	e_panel_list_t::iterator panel_it;
+	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
+	{
+		if (mOrientation == HORIZONTAL)
+		{
+			mMinHeight = llmax(	mMinHeight, 
+								(*panel_it)->mMinHeight);
+            mMinWidth += (*panel_it)->mMinWidth;
+			if (panel_it != mPanels.begin())
+			{
+				mMinWidth += mPanelSpacing;
+			}
+		}
+		else //VERTICAL
+		{
+	        mMinWidth = llmax(	mMinWidth, 
+								(*panel_it)->mMinWidth);
+			mMinHeight += (*panel_it)->mMinHeight;
+			if (panel_it != mPanels.begin())
+			{
+				mMinHeight += mPanelSpacing;
+			}
+		}
+	}
+}
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
new file mode 100644
index 0000000000..600690f67d
--- /dev/null
+++ b/indra/llui/lllayoutstack.h
@@ -0,0 +1,102 @@
+/** 
+ * @file lllayoutstack.h
+ * @author Richard Nelson
+ * @brief LLLayout class - dynamic stacking of UI elements
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLAYOUTSTACK_H
+#define LL_LLLAYOUTSTACK_H
+
+#include "llpanel.h"
+
+class LLLayoutStack : public LLView
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<std::string>	orientation;
+		Optional<S32>			border_size;
+		// mMinWidth and mMinHeight are calculated, not set in XML
+
+		Params();
+	};
+
+	typedef enum e_layout_orientation
+	{
+		HORIZONTAL,
+		VERTICAL
+	} ELayoutOrientation;
+
+	virtual ~LLLayoutStack();
+
+	/*virtual*/ void draw();
+	/*virtual*/ void removeChild(LLView*);
+	/*virtual*/ BOOL postBuild();
+
+	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
+
+	S32 getMinWidth() const { return mMinWidth; }
+	S32 getMinHeight() const { return mMinHeight; }
+	
+	typedef enum e_animate
+	{
+		NO_ANIMATE,
+		ANIMATE
+	} EAnimate;
+
+	void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
+	void removePanel(LLPanel* panel);
+	void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
+	S32 getNumPanels() { return mPanels.size(); }
+
+protected:
+	LLLayoutStack(const Params&);
+	friend class LLUICtrlFactory;
+
+private:
+	struct LLEmbeddedPanel;
+
+	void updateLayout(BOOL force_resize = FALSE);
+	void calcMinExtents();
+	S32 getDefaultHeight(S32 cur_height);
+	S32 getDefaultWidth(S32 cur_width);
+
+	const ELayoutOrientation mOrientation;
+
+	typedef std::vector<LLEmbeddedPanel*> e_panel_list_t;
+	e_panel_list_t mPanels;
+	LLEmbeddedPanel* findEmbeddedPanel(LLPanel* panelp) const;
+
+	S32 mMinWidth;  // calculated by calcMinExtents
+	S32 mMinHeight;  // calculated by calcMinExtents
+	S32 mPanelSpacing;
+}; // end class LLLayoutStack
+
+#endif
diff --git a/indra/llui/lllazyvalue.h b/indra/llui/lllazyvalue.h
new file mode 100644
index 0000000000..da0af6f522
--- /dev/null
+++ b/indra/llui/lllazyvalue.h
@@ -0,0 +1,83 @@
+/** 
+ * @file lllazyvalue.h
+ * @brief generic functor/value abstraction for lazy evaluation of a value
+ * parsing construction parameters from xml and LLSD
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LAZY_VALUE_H
+#define LL_LAZY_VALUE_H
+
+#include <boost/function.hpp>
+
+// Holds on to a value of type T *or* calls a functor to generate a value of type T
+template<typename T>
+class LLLazyValue
+{
+public:
+	typedef typename boost::add_reference<typename boost::add_const<T>::type>::type	T_const_ref;
+	typedef typename boost::function<T_const_ref (void)>							function_type;
+
+public:
+	LLLazyValue(const function_type& value) 
+	:	mValueGetter(value)
+	{} 
+	LLLazyValue(T_const_ref value)
+	:	mValue(value)
+	{}
+	LLLazyValue()
+	:	mValue()
+	{}
+
+	void set(const LLLazyValue& val)
+	{
+		mValueGetter = val.mValueGetter;
+	}
+
+	void set(T_const_ref val)
+	{
+		mValue = val;
+		mValueGetter = NULL;
+	}
+
+	T_const_ref get() const
+	{
+		if (!mValueGetter.empty())
+		{
+			return mValueGetter();
+		}
+		return mValue;
+	}
+
+private:
+	function_type	mValueGetter;
+	T				mValue;
+};
+
+#endif // LL_LAZY_VALUE_H
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 964254d93f..c03ef7968f 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -34,6 +34,8 @@
 
 #include "linden_common.h"
  
+#define INSTANTIATE_GETCHILD_LINEEDITOR
+
 #include "lllineeditor.h"
 
 #include "lltexteditor.h"
@@ -64,79 +66,102 @@
 // Constants
 //
 
-const S32	UI_LINEEDITOR_CURSOR_THICKNESS = 2;
-const S32	UI_LINEEDITOR_H_PAD = 2;
-const S32	UI_LINEEDITOR_V_PAD = 1;
 const F32	CURSOR_FLASH_DELAY = 1.0f;  // in seconds
 const S32	SCROLL_INCREMENT_ADD = 0;	// make space for typing
 const S32   SCROLL_INCREMENT_DEL = 4;	// make space for baskspacing
 const F32   AUTO_SCROLL_TIME = 0.05f;
 
-const F32	PREEDIT_MARKER_BRIGHTNESS = 0.4f;
-const S32	PREEDIT_MARKER_GAP = 1;
-const S32	PREEDIT_MARKER_POSITION = 2;
-const S32	PREEDIT_MARKER_THICKNESS = 1;
-const F32	PREEDIT_STANDOUT_BRIGHTNESS = 0.6f;
-const S32	PREEDIT_STANDOUT_GAP = 1;
-const S32	PREEDIT_STANDOUT_POSITION = 2;
-const S32	PREEDIT_STANDOUT_THICKNESS = 2;
-
 static LLRegisterWidget<LLLineEditor> r1("line_editor");
 
-/* static */ LLPointer<LLUIImage> LLLineEditor::sImage;
+template LLLineEditor* LLView::getChild<LLLineEditor>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
 
 //
 // Member functions
 //
- 
-LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
-						   const std::string& default_text, const LLFontGL* font,
-						   S32 max_length_bytes,
-						   void (*commit_callback)(LLUICtrl* caller, void* user_data ),
-						   void (*keystroke_callback)(LLLineEditor* caller, void* user_data ),
-						   void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data ),
-						   void* userdata,
-						   LLLinePrevalidateFunc prevalidate_func,
-						   LLViewBorder::EBevel border_bevel,
-						   LLViewBorder::EStyle border_style,
-						   S32 border_thickness)
-	:
-		LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ),
-		mMaxLengthBytes(max_length_bytes),
-		mCursorPos( 0 ),
-		mScrollHPos( 0 ),
-		mTextPadLeft(0),
-		mTextPadRight(0),
-		mCommitOnFocusLost( TRUE ),
-		mRevertOnEsc( TRUE ),
-		mKeystrokeCallback( keystroke_callback ),
-		mIsSelecting( FALSE ),
-		mSelectionStart( 0 ),
-		mSelectionEnd( 0 ),
-		mLastSelectionX(-1),
-		mLastSelectionY(-1),
-		mLastSelectionStart(-1),
-		mLastSelectionEnd(-1),
-		mPrevalidateFunc( prevalidate_func ),
-		mCursorColor(		LLUI::sColorsGroup->getColor( "TextCursorColor" ) ),
-		mFgColor(			LLUI::sColorsGroup->getColor( "TextFgColor" ) ),
-		mReadOnlyFgColor(	LLUI::sColorsGroup->getColor( "TextFgReadOnlyColor" ) ),
-		mTentativeFgColor(	LLUI::sColorsGroup->getColor( "TextFgTentativeColor" ) ),
-		mWriteableBgColor(	LLUI::sColorsGroup->getColor( "TextBgWriteableColor" ) ),
-		mReadOnlyBgColor(	LLUI::sColorsGroup->getColor( "TextBgReadOnlyColor" ) ),
-		mFocusBgColor(		LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ),
-		mBorderThickness( border_thickness ),
-		mIgnoreArrowKeys( FALSE ),
-		mIgnoreTab( TRUE ),
-		mDrawAsterixes( FALSE ),
-		mHandleEditKeysDirectly( FALSE ),
-		mSelectAllonFocusReceived( FALSE ),
-		mPassDelete(FALSE),
-		mReadOnly(FALSE),
-		mImage( sImage ),
-		mReplaceNewlinesWithSpaces( TRUE )
-{
-	llassert( max_length_bytes > 0 );
+
+void LLLineEditor::PrevalidateNamedFuncs::declareValues()
+{
+	declare("ascii", LLLineEditor::prevalidateASCII);
+	declare("float", LLLineEditor::prevalidateFloat);
+	declare("int", LLLineEditor::prevalidateInt);
+	declare("positive_s32", LLLineEditor::prevalidatePositiveS32);
+	declare("non_negative_s32", LLLineEditor::prevalidateNonNegativeS32);
+	declare("alpha_num", LLLineEditor::prevalidateAlphaNum);
+	declare("alpha_num_space", LLLineEditor::prevalidateAlphaNumSpace);
+	declare("printable_not_pipe", LLLineEditor::prevalidatePrintableNotPipe);
+	declare("printable_no_space", LLLineEditor::prevalidatePrintableNoSpace);
+}
+
+LLLineEditor::Params::Params()
+:	max_length_bytes("max_length", 254),
+	background_image("background_image"),
+	select_on_focus("select_on_focus", false),
+	handle_edit_keys_directly("handle_edit_keys_directly", false),
+	commit_on_focus_lost("commit_on_focus_lost", true),
+	ignore_tab("ignore_tab", true),
+	cursor_color("cursor_color"),
+	text_color("text_color"),
+	text_readonly_color("text_readonly_color"),
+	text_tentative_color("text_tentative_color"),
+	bg_readonly_color("bg_readonly_color"),
+	bg_writeable_color("bg_writeable_color"),
+	bg_focus_color("bg_focus_color"),
+	border(""),
+	is_unicode("is_unicode"),
+	drop_shadow_visible("drop_shadow_visible"),
+	border_drop_shadow_visible("border_drop_shadow_visible"),
+	bg_visible("bg_visible"),
+	text_pad_left("text_pad_left"),
+	text_pad_right("text_pad_right"),
+	default_text("default_text")
+{
+	mouse_opaque = true;
+	addSynonym(select_on_focus, "select_all_on_focus_received");
+	addSynonym(border, "border");
+}
+
+LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
+:	LLUICtrl(p),
+	mMaxLengthBytes(p.max_length_bytes),
+	mCursorPos( 0 ),
+	mScrollHPos( 0 ),
+	mTextPadLeft(p.text_pad_left),
+	mTextPadRight(p.text_pad_right),
+	mCommitOnFocusLost( p.commit_on_focus_lost ),
+	mRevertOnEsc( TRUE ),
+	mKeystrokeCallback( p.keystroke_callback() ),
+	mIsSelecting( FALSE ),
+	mSelectionStart( 0 ),
+	mSelectionEnd( 0 ),
+	mLastSelectionX(-1),
+	mLastSelectionY(-1),
+	mLastSelectionStart(-1),
+	mLastSelectionEnd(-1),
+	mBorderThickness( 0 ),
+	mIgnoreArrowKeys( FALSE ),
+	mIgnoreTab( p.ignore_tab ),
+	mDrawAsterixes( FALSE ),
+	mHandleEditKeysDirectly(p.handle_edit_keys_directly),
+	mSelectAllonFocusReceived( p.select_on_focus ),
+	mPassDelete(FALSE),
+	mReadOnly(FALSE),
+	mImage( NULL ),
+	mReplaceNewlinesWithSpaces( TRUE ),
+	mLabel(p.label),
+	mCursorColor(p.cursor_color()),
+	mFgColor(p.text_color()),
+	mReadOnlyFgColor(p.text_readonly_color()),
+	mTentativeFgColor(p.text_tentative_color()),
+	mWriteableBgColor(p.bg_writeable_color()),
+	mReadOnlyBgColor(p.bg_readonly_color()),
+	mFocusBgColor(p.bg_focus_color()),
+	mGLFont(p.font),
+	mGLFontStyle(LLFontGL::getStyleFromString(p.font.style))
+{
+	llassert( mMaxLengthBytes > 0 );
+
+	mScrollTimer.reset();
+	setText(p.default_text());
 
 	// line history support:
 	// - initialize line history list
@@ -146,40 +171,24 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
 	// - reset current history line pointer
 	mCurrentHistoryLine = 0;
 
-	if (font)
-	{
-		mGLFont = font;
-	}
-	else
-	{
-		mGLFont = LLFontGL::getFontSansSerifSmall();
-	}
-
-	setFocusLostCallback(focus_lost_callback);
-
-	setTextPadding(0, 0);
-
-	mScrollTimer.reset();
+	LLRect border_rect(getLocalRect());
+	// adjust for gl line drawing glitch
+	border_rect.mTop -= 1;
+	border_rect.mRight -=1;
+	LLViewBorder::Params border_p(p.border);
+	border_p.rect = border_rect;
+	border_p.follows.flags = FOLLOWS_ALL;
+	border_p.bevel_type = LLViewBorder::BEVEL_IN;
+	mBorder = LLUICtrlFactory::create<LLViewBorder>(border_p);
+	addChild( mBorder );
 
-	setText(default_text);
-	
+	// clamp text padding to current editor size
+	updateTextPadding();
 	setCursor(mText.length());
 
-	// Scalable UI somehow made these rectangles off-by-one.
-	// I don't know why. JC
-	LLRect border_rect(0, getRect().getHeight()-1, getRect().getWidth()-1, 0);
-	mBorder = new LLViewBorder( std::string("line ed border"), border_rect, border_bevel, border_style, mBorderThickness );
-	addChild( mBorder );
-	mBorder->setFollows(FOLLOWS_LEFT|FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
-
-	if( ! sImage)
-	{
-		sImage = LLUI::getUIImage("sm_rounded_corners_simple.tga");
-	}
-	mImage = sImage;
+	setPrevalidate(p.prevalidate_callback());
 }
-
-
+ 
 LLLineEditor::~LLLineEditor()
 {
 	mCommitOnFocusLost = FALSE;
@@ -227,6 +236,7 @@ void LLLineEditor::onCommit()
 	// put current line into the line history
 	updateHistory();
 
+	setControlValue(getValue());
 	LLUICtrl::onCommit();
 	selectAll();
 }
@@ -255,7 +265,7 @@ void LLLineEditor::updateHistory()
 void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
 	LLUICtrl::reshape(width, height, called_from_parent);
-	setTextPadding(mTextPadLeft, mTextPadRight); // For clamping side-effect.
+	updateTextPadding(); // For clamping side-effect.
 	setCursor(mCursorPos); // For clamping side-effect.
 }
 
@@ -273,11 +283,12 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length)
 	mMaxLengthBytes = max_len;
 } 
 
-void LLLineEditor::setTextPadding(S32 left, S32 right)
+void LLLineEditor::updateTextPadding()
 {
-	mTextPadLeft = llclamp(left, 0, getRect().getWidth());
-	mTextPadRight = llclamp(right, 0, getRect().getWidth());
-	mMinHPixels = UI_LINEEDITOR_H_PAD + mTextPadLeft;
+	static LLUICachedControl<S32> line_editor_hpad ("UILineEditorHPad", 0);
+	mTextPadLeft = llclamp(mTextPadLeft, 0, getRect().getWidth());
+	mTextPadRight = llclamp(mTextPadRight, 0, getRect().getWidth());
+	mMinHPixels = line_editor_hpad + mTextPadLeft;
 	mMaxHPixels = getRect().getWidth() - mMinHPixels - mTextPadRight;
 }
 
@@ -362,7 +373,7 @@ void LLLineEditor::setCursor( S32 pos )
 	{
 		S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos);
 		S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left))); 
-		S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), mText.length(), getCursor());
+		S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels), mText.length(), getCursor());
 		if (old_cursor_pos == last_visible_char)
 		{
 			mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD));
@@ -936,7 +947,7 @@ void LLLineEditor::cut()
 		else
 		if( mKeystrokeCallback )
 		{
-			mKeystrokeCallback( this, mCallbackUserData );
+			mKeystrokeCallback( this );
 		}
 	}
 }
@@ -1057,7 +1068,7 @@ void LLLineEditor::pasteHelper(bool is_primary)
 			else
 			if( mKeystrokeCallback )
 			{
-				mKeystrokeCallback( this, mCallbackUserData );
+				mKeystrokeCallback( this );
 			}
 		}
 	}
@@ -1370,7 +1381,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
 			{
 				if (mKeystrokeCallback)
 				{
-					mKeystrokeCallback(this, mCallbackUserData);
+					mKeystrokeCallback(this);
 				}
 			}
 		}
@@ -1420,7 +1431,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
 			{
 				// HACK! The only usage of this callback doesn't do anything with the character.
 				// We'll have to do something about this if something ever changes! - Doug
-				mKeystrokeCallback( this, mCallbackUserData );
+				mKeystrokeCallback( this );
 			}
 		}
 	}
@@ -1461,7 +1472,7 @@ void LLLineEditor::doDelete()
 		{
 			if( mKeystrokeCallback )
 			{
-				mKeystrokeCallback( this, mCallbackUserData );
+				mKeystrokeCallback( this );
 			}
 		}
 	}
@@ -1471,6 +1482,16 @@ void LLLineEditor::doDelete()
 void LLLineEditor::draw()
 {
 	S32 text_len = mText.length();
+	static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0);
+	static LLUICachedControl<S32> lineeditor_v_pad ("UILineEditorVPad", 0);
+	static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0);
+	static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0);
+	static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0);
+	static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0);
+	static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0);
+	static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0);
+	static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0);
+	static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0);
 
 	std::string saved_text;
 	if (mDrawAsterixes)
@@ -1488,7 +1509,7 @@ void LLLineEditor::draw()
 	LLRect background( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	background.stretch( -mBorderThickness );
 
-	LLColor4 bg_color = mReadOnlyBgColor;
+	LLColor4 bg_color = mReadOnlyBgColor.get();
 
 #if 0 // for when we're ready for image art.
 	if( hasFocus())
@@ -1505,11 +1526,11 @@ void LLLineEditor::draw()
 		{
 			if( gFocusMgr.getKeyboardFocus() == this )
 			{
-				bg_color = mFocusBgColor;
+				bg_color = mFocusBgColor.get();
 			}
 			else
 			{
-				bg_color = mWriteableBgColor;
+				bg_color = mWriteableBgColor.get();
 			}
 		}
 		gl_rect_2d(background, bg_color);
@@ -1526,18 +1547,18 @@ void LLLineEditor::draw()
 	{
 		if (!getTentative())
 		{
-			text_color = mFgColor;
+			text_color = mFgColor.get();
 		}
 		else
 		{
-			text_color = mTentativeFgColor;
+			text_color = mTentativeFgColor.get();
 		}
 	}
 	else
 	{
-		text_color = mReadOnlyFgColor;
+		text_color = mReadOnlyFgColor.get();
 	}
-	LLColor4 label_color = mTentativeFgColor;
+	LLColor4 label_color = mTentativeFgColor.get();
 
 	if (hasPreeditString())
 	{
@@ -1556,19 +1577,19 @@ void LLLineEditor::draw()
 				}
 				if (mPreeditStandouts[i])
 				{
-					gl_rect_2d(preedit_pixels_left + PREEDIT_STANDOUT_GAP,
-						background.mBottom + PREEDIT_STANDOUT_POSITION,
-						preedit_pixels_right - PREEDIT_STANDOUT_GAP - 1,
-						background.mBottom + PREEDIT_STANDOUT_POSITION - PREEDIT_STANDOUT_THICKNESS,
-						(text_color * PREEDIT_STANDOUT_BRIGHTNESS + bg_color * (1 - PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f));
+					gl_rect_2d(preedit_pixels_left + preedit_standout_gap,
+						background.mBottom + preedit_standout_position,
+						preedit_pixels_right - preedit_standout_gap - 1,
+						background.mBottom + preedit_standout_position - preedit_standout_thickness,
+						(text_color * preedit_standout_brightness + bg_color * (1 - preedit_standout_brightness)).setAlpha(1.0f));
 				}
 				else
 				{
-					gl_rect_2d(preedit_pixels_left + PREEDIT_MARKER_GAP,
-						background.mBottom + PREEDIT_MARKER_POSITION,
-						preedit_pixels_right - PREEDIT_MARKER_GAP - 1,
-						background.mBottom + PREEDIT_MARKER_POSITION - PREEDIT_MARKER_THICKNESS,
-						(text_color * PREEDIT_MARKER_BRIGHTNESS + bg_color * (1 - PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f));
+					gl_rect_2d(preedit_pixels_left + preedit_marker_gap,
+						background.mBottom + preedit_marker_position,
+						preedit_pixels_right - preedit_marker_gap - 1,
+						background.mBottom + preedit_marker_position - preedit_marker_thickness,
+						(text_color * preedit_marker_brightness + bg_color * (1 - preedit_marker_brightness)).setAlpha(1.0f));
 				}
 			}
 		}
@@ -1576,7 +1597,7 @@ void LLLineEditor::draw()
 
 	S32 rendered_text = 0;
 	F32 rendered_pixels_right = (F32)mMinHPixels;
-	F32 text_bottom = (F32)background.mBottom + (F32)UI_LINEEDITOR_V_PAD;
+	F32 text_bottom = (F32)background.mBottom + (F32)lineeditor_v_pad;
 
 	if( (gFocusMgr.getKeyboardFocus() == this) && hasSelection() )
 	{
@@ -1601,7 +1622,8 @@ void LLLineEditor::draw()
 				rendered_pixels_right, text_bottom,
 				text_color,
 				LLFontGL::LEFT, LLFontGL::BOTTOM,
-				LLFontGL::NORMAL,
+				mGLFontStyle,
+				LLFontGL::NO_SHADOW,
 				select_left - mScrollHPos,
 				mMaxHPixels - llround(rendered_pixels_right),
 				&rendered_pixels_right);
@@ -1620,7 +1642,8 @@ void LLLineEditor::draw()
 				rendered_pixels_right, text_bottom,
 				LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
 				LLFontGL::LEFT, LLFontGL::BOTTOM,
-				LLFontGL::NORMAL,
+				mGLFontStyle,
+				LLFontGL::NO_SHADOW,
 				select_right - mScrollHPos - rendered_text,
 				mMaxHPixels - llround(rendered_pixels_right),
 				&rendered_pixels_right);
@@ -1634,7 +1657,8 @@ void LLLineEditor::draw()
 				rendered_pixels_right, text_bottom,
 				text_color,
 				LLFontGL::LEFT, LLFontGL::BOTTOM,
-				LLFontGL::NORMAL,
+				mGLFontStyle,
+				LLFontGL::NO_SHADOW,
 				S32_MAX,
 				mMaxHPixels - llround(rendered_pixels_right),
 				&rendered_pixels_right);
@@ -1647,7 +1671,8 @@ void LLLineEditor::draw()
 			rendered_pixels_right, text_bottom,
 			text_color,
 			LLFontGL::LEFT, LLFontGL::BOTTOM,
-			LLFontGL::NORMAL,
+			mGLFontStyle,
+			LLFontGL::NO_SHADOW,
 			S32_MAX,
 			mMaxHPixels - llround(rendered_pixels_right),
 			&rendered_pixels_right);
@@ -1667,8 +1692,8 @@ void LLLineEditor::draw()
 			if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) )
 			{
 				S32 cursor_left = findPixelNearestPos();
-				cursor_left -= UI_LINEEDITOR_CURSOR_THICKNESS / 2;
-				S32 cursor_right = cursor_left + UI_LINEEDITOR_CURSOR_THICKNESS;
+				cursor_left -= lineeditor_cursor_thickness / 2;
+				S32 cursor_right = cursor_left + lineeditor_cursor_thickness;
 				if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
 				{
 					const LLWString space(utf8str_to_wstring(std::string(" ")));
@@ -1681,17 +1706,18 @@ void LLLineEditor::draw()
 					cursor_right, cursor_bottom, text_color);
 				if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
 				{
-					mGLFont->render(mText, getCursor(), (F32)(cursor_left + UI_LINEEDITOR_CURSOR_THICKNESS / 2), text_bottom, 
+					mGLFont->render(mText, getCursor(), (F32)(cursor_left + lineeditor_cursor_thickness / 2), text_bottom, 
 						LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ),
 						LLFontGL::LEFT, LLFontGL::BOTTOM,
-						LLFontGL::NORMAL,
+						mGLFontStyle,
+						LLFontGL::NO_SHADOW,
 						1);
 				}
 
 				// Make sure the IME is in the right place
 				S32 pixels_after_scroll = findPixelNearestPos();	// RCalculcate for IME position
-				LLRect screen_pos = getScreenRect();
-				LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - UI_LINEEDITOR_V_PAD );
+				LLRect screen_pos = calcScreenRect();
+				LLCoordGL ime_pos( screen_pos.mLeft + pixels_after_scroll, screen_pos.mTop - lineeditor_v_pad );
 
 				ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]);
 				ime_pos.mY = (S32) (ime_pos.mY * LLUI::sGLScaleFactor.mV[VY]);
@@ -1709,7 +1735,8 @@ void LLLineEditor::draw()
 							label_color,
 							LLFontGL::LEFT,
 							LLFontGL::BOTTOM,
-							LLFontGL::NORMAL,
+							mGLFontStyle,
+							LLFontGL::NO_SHADOW,
 							S32_MAX,
 							mMaxHPixels - llround(rendered_pixels_right),
 							&rendered_pixels_right, FALSE);
@@ -1733,7 +1760,8 @@ void LLLineEditor::draw()
 							label_color,
 							LLFontGL::LEFT,
 							LLFontGL::BOTTOM,
-							LLFontGL::NORMAL,
+							mGLFontStyle,
+							LLFontGL::NO_SHADOW,
 							S32_MAX,
 							mMaxHPixels - llround(rendered_pixels_right),
 							&rendered_pixels_right, FALSE);
@@ -1849,7 +1877,7 @@ void LLLineEditor::setRect(const LLRect& rect)
 	}
 }
 
-void LLLineEditor::setPrevalidate(BOOL (*func)(const LLWString &))
+void LLLineEditor::setPrevalidate(LLLinePrevalidateFunc func)
 {
 	mPrevalidateFunc = func;
 	updateAllowingLanguageInput();
@@ -2169,244 +2197,11 @@ void LLLineEditor::setSelectAllonFocusReceived(BOOL b)
 }
 
 
-void LLLineEditor::setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data))
-{
-	mKeystrokeCallback = keystroke_callback;
-}
-
-// virtual
-LLXMLNodePtr LLLineEditor::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("max_length", TRUE)->setIntValue(mMaxLengthBytes);
-
-	node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont));
-
-	if (mBorder)
-	{
-		std::string bevel;
-		switch(mBorder->getBevel())
-		{
-		default:
-		case LLViewBorder::BEVEL_NONE:	bevel = "none"; break;
-		case LLViewBorder::BEVEL_IN:	bevel = "in"; break;
-		case LLViewBorder::BEVEL_OUT:	bevel = "out"; break;
-		case LLViewBorder::BEVEL_BRIGHT:bevel = "bright"; break;
-		}
-		node->createChild("bevel_style", TRUE)->setStringValue(bevel);
-
-		std::string style;
-		switch(mBorder->getStyle())
-		{
-		default:
-		case LLViewBorder::STYLE_LINE:		style = "line"; break;
-		case LLViewBorder::STYLE_TEXTURE:	style = "texture"; break;
-		}
-		node->createChild("border_style", TRUE)->setStringValue(style);
-
-		node->createChild("border_thickness", TRUE)->setIntValue(mBorder->getBorderWidth());
-	}
-
-	if (!mLabel.empty())
-	{
-		node->createChild("label", TRUE)->setStringValue(mLabel.getString());
-	}
-
-	node->createChild("select_all_on_focus_received", TRUE)->setBoolValue(mSelectAllonFocusReceived);
-
-	node->createChild("handle_edit_keys_directly", TRUE)->setBoolValue(mHandleEditKeysDirectly );
-
-	addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor");
-	addColorXML(node, mFgColor, "text_color", "TextFgColor");
-	addColorXML(node, mReadOnlyFgColor, "text_readonly_color", "TextFgReadOnlyColor");
-	addColorXML(node, mTentativeFgColor, "text_tentative_color", "TextFgTentativeColor");
-	addColorXML(node, mReadOnlyBgColor, "bg_readonly_color", "TextBgReadOnlyColor");
-	addColorXML(node, mWriteableBgColor, "bg_writeable_color", "TextBgWriteableColor");
-	addColorXML(node, mFocusBgColor, "bg_focus_color", "TextBgFocusColor");
-
-	node->createChild("select_on_focus", TRUE)->setBoolValue(mSelectAllonFocusReceived );
-
-	return node;
-}
-
-// static
-LLView* LLLineEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("line_editor");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	S32 max_text_length = 128;
-	node->getAttributeS32("max_length", max_text_length);
-
-	LLFontGL* font = LLView::selectFont(node);
-
-	std::string text = node->getTextContents().substr(0, max_text_length - 1);
-
-	LLViewBorder::EBevel bevel_style = LLViewBorder::BEVEL_IN;
-	LLViewBorder::getBevelFromAttribute(node, bevel_style);
-	
-	LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE;
-	std::string border_string;
-	node->getAttributeString("border_style", border_string);
-	LLStringUtil::toLower(border_string);
-
-	if (border_string == "texture")
-	{
-		border_style = LLViewBorder::STYLE_TEXTURE;
-	}
-
-	S32 border_thickness = 1;
-	node->getAttributeS32("border_thickness", border_thickness);
-
-	LLUICtrlCallback commit_callback = NULL;
-
-	LLLineEditor* line_editor = new LLLineEditor(name,
-								rect, 
-								text, 
-								font,
-								max_text_length,
-								commit_callback,
-								NULL,
-								NULL,
-								NULL,
-								NULL,
-								bevel_style,
-								border_style,
-								border_thickness);
-
-	std::string label;
-	if(node->getAttributeString("label", label))
-	{
-		line_editor->setLabel(label);
-	}
-	BOOL select_all_on_focus_received = FALSE;
-	if (node->getAttributeBOOL("select_all_on_focus_received", select_all_on_focus_received))
-	{
-		line_editor->setSelectAllonFocusReceived(select_all_on_focus_received);
-	}
-	BOOL handle_edit_keys_directly = FALSE;
-	if (node->getAttributeBOOL("handle_edit_keys_directly", handle_edit_keys_directly))
-	{
-		line_editor->setHandleEditKeysDirectly(handle_edit_keys_directly);
-	}
-	BOOL commit_on_focus_lost = TRUE;
-	if (node->getAttributeBOOL("commit_on_focus_lost", commit_on_focus_lost))
-	{
-		line_editor->setCommitOnFocusLost(commit_on_focus_lost);
-	}
-	
-	line_editor->setColorParameters(node);
-	
-	if(node->hasAttribute("select_on_focus"))
-	{
-		BOOL selectall = FALSE;
-		node->getAttributeBOOL("select_on_focus", selectall);
-		line_editor->setSelectAllonFocusReceived(selectall);
-	}
-
-	std::string prevalidate;
-	if(node->getAttributeString("prevalidate", prevalidate))
-	{
-		LLStringUtil::toLower(prevalidate);
-
-		if ("ascii" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidateASCII );
-		}
-		else if ("float" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidateFloat );
-		}
-		else if ("int" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidateInt );
-		}
-		else if ("positive_s32" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidatePositiveS32 );
-		}
-		else if ("non_negative_s32" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidateNonNegativeS32 );
-		}
-		else if ("alpha_num" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidateAlphaNum );
-		}
-		else if ("alpha_num_space" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidateAlphaNumSpace );
-		}
-		else if ("printable_not_pipe" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidatePrintableNotPipe );
-		}
-		else if ("printable_no_space" == prevalidate)
-		{
-			line_editor->setPrevalidate( LLLineEditor::prevalidatePrintableNoSpace );
-		}
-	}
-	
-	line_editor->initFromXML(node, parent);
-	
-	return line_editor;
-}
-
-//static
-void LLLineEditor::cleanupLineEditor()
-{
-	sImage = NULL;
-}
-
-/* static */ 
-LLPointer<LLUIImage> LLLineEditor::parseImage(std::string name, LLXMLNodePtr from, LLPointer<LLUIImage> def)
+void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data)
 {
-	std::string xml_name;
-	if (from->hasAttribute(name.c_str())) from->getAttributeString(name.c_str(), xml_name);
-	if (xml_name == LLStringUtil::null) return def;
-	LLPointer<LLUIImage> image = LLUI::getUIImage(xml_name);
-	return image.isNull() ? def : image;
+	mKeystrokeCallback = boost::bind(callback, _1, user_data);
 }
 
-void LLLineEditor::setColorParameters(LLXMLNodePtr node)
-{
-	// overrides default image if supplied.
-	mImage = parseImage(std::string("image"), node, mImage);
-
-	LLColor4 color;
-	if (LLUICtrlFactory::getAttributeColor(node,"cursor_color", color)) 
-	{
-		setCursorColor(color);
-	}
-	if(node->hasAttribute("text_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"text_color", color);
-		setFgColor(color);
-	}
-	if(node->hasAttribute("text_readonly_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"text_readonly_color", color);
-		setReadOnlyFgColor(color);
-	}
-	if (LLUICtrlFactory::getAttributeColor(node,"text_tentative_color", color))
-	{
-		setTentativeFgColor(color);
-	}
-	if(node->hasAttribute("bg_readonly_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"bg_readonly_color", color);
-		setReadOnlyBgColor(color);
-	}
-	if(node->hasAttribute("bg_writeable_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"bg_writeable_color", color);
-		setWriteableBgColor(color);
-	}
-}
 
 BOOL LLLineEditor::setTextArg( const std::string& key, const LLStringExplicit& text )
 {
@@ -2429,13 +2224,19 @@ void LLLineEditor::updateAllowingLanguageInput()
 	// fine on 1.15.0.2, since all prevalidate func reject any
 	// non-ASCII characters.  I'm not sure on future versions,
 	// however...
+	LLWindow* window = getWindow();
+	if (!window)
+	{
+		// test app, no window available
+		return;	
+	}
 	if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL)
 	{
-		getWindow()->allowLanguageTextInput(this, TRUE);
+		window->allowLanguageTextInput(this, TRUE);
 	}
 	else
 	{
-		getWindow()->allowLanguageTextInput(this, FALSE);
+		window->allowLanguageTextInput(this, FALSE);
 	}
 }
 
@@ -2513,7 +2314,7 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string,
 	mKeystrokeTimer.reset();
 	if( mKeystrokeCallback )
 	{
-		mKeystrokeCallback( this, mCallbackUserData );
+		mKeystrokeCallback( this );
 	}
 }
 
@@ -2656,146 +2457,19 @@ LLWString LLLineEditor::getConvertedText() const
 	return text;
 }
 
-static LLRegisterWidget<LLSearchEditor> r2("search_editor");
-
-
-LLSearchEditor::LLSearchEditor(const std::string& name, 
-		const LLRect& rect,
-		S32 max_length_bytes,
-		void (*search_callback)(const std::string& search_string, void* user_data),
-		void* userdata)
-	: 
-		LLUICtrl(name, rect, TRUE, NULL, userdata),
-		mSearchCallback(search_callback)
-{
-	LLRect search_edit_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
-	mSearchEdit = new LLLineEditor(std::string("search edit"),
-								   search_edit_rect,
-								   LLStringUtil::null,
-								   NULL,
-								   max_length_bytes,
-								   NULL,
-								   onSearchEdit,
-								   NULL,
-								   this);
-
-	mSearchEdit->setFollowsAll();
-	mSearchEdit->setSelectAllonFocusReceived(TRUE);
-
-	addChild(mSearchEdit);
-
-	S32 btn_width = rect.getHeight(); // button is square, and as tall as search editor
-	LLRect clear_btn_rect(rect.getWidth() - btn_width, rect.getHeight(), rect.getWidth(), 0);
-	mClearSearchButton = new LLButton(std::string("clear search"), 
-								clear_btn_rect, 
-								std::string("icn_clear_lineeditor.tga"),
-								std::string("UIImgBtnCloseInactiveUUID"),
-								LLStringUtil::null,
-								onClearSearch,
-								this,
-								NULL,
-								LLStringUtil::null);
-	mClearSearchButton->setFollowsRight();
-	mClearSearchButton->setFollowsTop();
-	mClearSearchButton->setImageColor(LLUI::sColorsGroup->getColor("TextFgTentativeColor"));
-	mClearSearchButton->setTabStop(FALSE);
-	mSearchEdit->addChild(mClearSearchButton);
-
-	mSearchEdit->setTextPadding(0, btn_width);
-}
-
-
-//virtual
-void LLSearchEditor::setValue(const LLSD& value )
-{
-	mSearchEdit->setValue(value);
-}
-
-//virtual
-LLSD LLSearchEditor::getValue() const
+namespace LLInitParam
 {
-	return mSearchEdit->getValue();
-}
-
-//virtual
-BOOL LLSearchEditor::setTextArg( const std::string& key, const LLStringExplicit& text )
-{
-	return mSearchEdit->setTextArg(key, text);
-}
-
-//virtual
-BOOL LLSearchEditor::setLabelArg( const std::string& key, const LLStringExplicit& text )
-{
-	return mSearchEdit->setLabelArg(key, text);
-}
-
-//virtual
-void LLSearchEditor::clear()
-{
-	if (mSearchEdit)
+	template<>
+	bool ParamCompare<LLLinePrevalidateFunc>::equals(const LLLinePrevalidateFunc &a, const LLLinePrevalidateFunc &b)
 	{
-		mSearchEdit->clear();
+		return false;
 	}
-}
-
-void LLSearchEditor::draw()
-{
-	mClearSearchButton->setVisible(!mSearchEdit->getWText().empty());
-
-	LLUICtrl::draw();
-}
 
-
-//static
-void LLSearchEditor::onSearchEdit(LLLineEditor* caller, void* user_data )
-{
-	LLSearchEditor* search_editor = (LLSearchEditor*)user_data;
-	if (search_editor->mSearchCallback)
-	{
-		search_editor->mSearchCallback(caller->getText(), search_editor->mCallbackUserData);
-	}
-}
-
-//static
-void LLSearchEditor::onClearSearch(void* user_data)
-{
-	LLSearchEditor* search_editor = (LLSearchEditor*)user_data;
-
-	search_editor->setText(LLStringUtil::null);
-	if (search_editor->mSearchCallback)
-	{
-		search_editor->mSearchCallback(LLStringUtil::null, search_editor->mCallbackUserData);
-	}
-}
-
-// static
-LLView* LLSearchEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("search_editor");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	S32 max_text_length = 128;
-	node->getAttributeS32("max_length", max_text_length);
-
-	std::string text = node->getValue().substr(0, max_text_length - 1);
-
-	LLSearchEditor* search_editor = new LLSearchEditor(name,
-								rect, 
-								max_text_length,
-								NULL, NULL);
-
-	std::string label;
-	if(node->getAttributeString("label", label))
+	template<>
+	bool ParamCompare<boost::function<void (LLLineEditor *)> >::equals(
+		const boost::function<void (LLLineEditor *)> &a,
+		const boost::function<void (LLLineEditor *)> &b)
 	{
-		search_editor->mSearchEdit->setLabel(label);
+		return false;
 	}
-	
-	search_editor->setText(text);
-
-	search_editor->initFromXML(node, parent);
-	
-	return search_editor;
 }
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index fc5fcc5b90..4c2a9b77b2 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -51,39 +51,71 @@
 #include "llviewborder.h"
 
 #include "llpreeditor.h"
+#include <boost/function.hpp>
 
 class LLFontGL;
 class LLLineEditorRollback;
 class LLButton;
 
-typedef BOOL (*LLLinePrevalidateFunc)(const LLWString &wstr);
-
+typedef boost::function<BOOL (const LLWString &wstr)> LLLinePrevalidateFunc;
 
 class LLLineEditor
 : public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor
 {
-
 public:
-	LLLineEditor(const std::string& name, 
-				 const LLRect& rect,
-				 const std::string& default_text = LLStringUtil::null,
-				 const LLFontGL* glfont = NULL,
-				 S32 max_length_bytes = 254,
-				 void (*commit_callback)(LLUICtrl* caller, void* user_data) = NULL,
-				 void (*keystroke_callback)(LLLineEditor* caller, void* user_data) = NULL,
-				 void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data) = NULL,
-				 void* userdata = NULL,
-				 LLLinePrevalidateFunc prevalidate_func = NULL,
-				 LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_IN,
-				 LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE,
-				 S32 border_thickness = 1);
 
-	virtual ~LLLineEditor();
+	struct PrevalidateNamedFuncs
+	:	public LLInitParam::TypeValuesHelper<LLLinePrevalidateFunc, PrevalidateNamedFuncs>
+
+	{
+		static void declareValues();
+	};
+	
+	typedef boost::function<void (LLLineEditor* caller)> keystroke_callback_t;
+	
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<std::string>			default_text;
+		Optional<S32>					max_length_bytes;
+
+		Optional<keystroke_callback_t>	keystroke_callback;
+
+		Optional<LLLinePrevalidateFunc, PrevalidateNamedFuncs>	prevalidate_callback;
+		
+		Optional<LLViewBorder::Params>	border;
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	void setColorParameters(LLXMLNodePtr node);
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-	static void cleanupLineEditor();
+		Optional<LLUIImage*>			background_image;
+
+		Optional<bool>					select_on_focus,
+										handle_edit_keys_directly,
+										commit_on_focus_lost,
+										ignore_tab;
+
+		// colors
+		Optional<LLUIColor>				cursor_color,
+										text_color,
+										text_readonly_color,
+										text_tentative_color,
+										bg_readonly_color,
+										bg_writeable_color,
+										bg_focus_color;
+
+		Optional<S32>					text_pad_left,
+										text_pad_right;
+
+		Deprecated						is_unicode,
+										drop_shadow_visible,	
+										border_drop_shadow_visible,
+										bg_visible;
+
+		Params();
+	};
+protected:
+	LLLineEditor(const Params&);
+	friend class LLUICtrlFactory;
+	friend class LLFloaterEditUI;
+public:
+	virtual ~LLLineEditor();
 
 	// mousehandler overrides
 	/*virtual*/ BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
@@ -144,7 +176,7 @@ public:
 	void			setText(const LLStringExplicit &new_text);
 
 	const std::string& getText() const		{ return mText.getString(); }
-	const LLWString& getWText() const	{ return mText.getWString(); }
+	LLWString       getWText() const	{ return mText.getWString(); }
 	LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines
 
 	S32				getLength() const	{ return mText.length(); }
@@ -160,7 +192,7 @@ public:
 	void			setRevertOnEsc( BOOL b )		{ mRevertOnEsc = b; }
 
 	void setCursorColor(const LLColor4& c)			{ mCursorColor = c; }
-	const LLColor4& getCursorColor() const			{ return mCursorColor; }
+	const LLColor4& getCursorColor() const			{ return mCursorColor.get(); }
 
 	void setFgColor( const LLColor4& c )			{ mFgColor = c; }
 	void setReadOnlyFgColor( const LLColor4& c )	{ mReadOnlyFgColor = c; }
@@ -169,12 +201,12 @@ public:
 	void setReadOnlyBgColor( const LLColor4& c )	{ mReadOnlyBgColor = c; }
 	void setFocusBgColor(const LLColor4& c)			{ mFocusBgColor = c; }
 
-	const LLColor4& getFgColor() const			{ return mFgColor; }
-	const LLColor4& getReadOnlyFgColor() const	{ return mReadOnlyFgColor; }
-	const LLColor4& getTentativeFgColor() const { return mTentativeFgColor; }
-	const LLColor4& getWriteableBgColor() const	{ return mWriteableBgColor; }
-	const LLColor4& getReadOnlyBgColor() const	{ return mReadOnlyBgColor; }
-	const LLColor4& getFocusBgColor() const		{ return mFocusBgColor; }
+	const LLColor4& getFgColor() const			{ return mFgColor.get(); }
+	const LLColor4& getReadOnlyFgColor() const	{ return mReadOnlyFgColor.get(); }
+	const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); }
+	const LLColor4& getWriteableBgColor() const	{ return mWriteableBgColor.get(); }
+	const LLColor4& getReadOnlyBgColor() const	{ return mReadOnlyBgColor.get(); }
+	const LLColor4& getFocusBgColor() const		{ return mFocusBgColor.get(); }
 
 	void			setIgnoreArrowKeys(BOOL b)		{ mIgnoreArrowKeys = b; }
 	void			setIgnoreTab(BOOL b)			{ mIgnoreTab = b; }
@@ -193,14 +225,14 @@ public:
 
 	void			setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; }
 	void			setSelectAllonFocusReceived(BOOL b);
-
-	void			setKeystrokeCallback(void (*keystroke_callback)(LLLineEditor* caller, void* user_data));
+	
+	typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t;
+	void			setKeystrokeCallback(callback_t callback, void* user_data);
 
 	void			setMaxTextLength(S32 max_text_length);
-	void			setTextPadding(S32 left, S32 right); // Used to specify room for children before or after text.
 
 	// Prevalidation controls which keystrokes can affect the editor
-	void			setPrevalidate( BOOL (*func)(const LLWString &) );
+	void			setPrevalidate( LLLinePrevalidateFunc func );
 	static BOOL		prevalidateFloat(const LLWString &str );
 	static BOOL		prevalidateInt(const LLWString &str );
 	static BOOL		prevalidatePositiveS32(const LLWString &str);
@@ -233,6 +265,7 @@ private:
 	BOOL			handleSelectionKey(KEY key, MASK mask);
 	BOOL			handleControlKey(KEY key, MASK mask);
 	S32				handleCommitKey(KEY key, MASK mask);
+	void			updateTextPadding();
 
 	//
 	// private data members
@@ -261,6 +294,7 @@ protected:
 
 	LLViewBorder* mBorder;
 	const LLFontGL*	mGLFont;
+	U8          mGLFontStyle;
 	S32			mMaxLengthBytes;			// Max length of the UTF8 string in bytes
 	S32			mCursorPos;					// I-beam is just after the mCursorPos-th character.
 	S32			mScrollHPos;				// Horizontal offset from the start of mText.  Used for scrolling.
@@ -273,7 +307,7 @@ protected:
 	BOOL		mCommitOnFocusLost;
 	BOOL		mRevertOnEsc;
 
-	void		(*mKeystrokeCallback)( LLLineEditor* caller, void* userdata );
+	keystroke_callback_t mKeystrokeCallback;
 
 	BOOL		mIsSelecting;				// Selection for clipboard operations
 	S32			mSelectionStart;
@@ -283,18 +317,17 @@ protected:
 	S32			mLastSelectionStart;
 	S32			mLastSelectionEnd;
 
-	S32			(*mPrevalidateFunc)(const LLWString &str);
+	LLLinePrevalidateFunc mPrevalidateFunc;
 
 	LLFrameTimer mKeystrokeTimer;
 
-	LLColor4	mCursorColor;
-
-	LLColor4	mFgColor;
-	LLColor4	mReadOnlyFgColor;
-	LLColor4	mTentativeFgColor;
-	LLColor4	mWriteableBgColor;
-	LLColor4	mReadOnlyBgColor;
-	LLColor4	mFocusBgColor;
+	LLUIColor	mCursorColor;
+	LLUIColor	mFgColor;
+	LLUIColor	mReadOnlyFgColor;
+	LLUIColor	mTentativeFgColor;
+	LLUIColor	mWriteableBgColor;
+	LLUIColor	mReadOnlyBgColor;
+	LLUIColor	mFocusBgColor;
 
 	S32			mBorderThickness;
 
@@ -314,11 +347,6 @@ protected:
 	LLPreeditor::standouts_t mPreeditStandouts;
 
 private:
-	// Utility on top of LLUI::getUIImage, looks up a named image in a given XML node and returns it if possible
-	// or returns a given default image if anything in the process fails.
-	static LLPointer<LLUIImage> parseImage(std::string name, LLXMLNodePtr from, LLPointer<LLUIImage> def);
-	// Global instance used as default for member instance below.
-	static LLPointer<LLUIImage> sImage;
 	// Instances that by default point to the statics but can be overidden in XML.
 	LLPointer<LLUIImage> mImage;
 
@@ -363,45 +391,22 @@ private:
 
 }; // end class LLLineEditor
 
+#ifdef LL_WINDOWS
+#ifndef INSTANTIATE_GETCHILD_LINEEDITOR
+#pragma warning (disable : 4231)
+extern template LLLineEditor* LLView::getChild<LLLineEditor>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+#endif
+#endif
 
-
-/*
- * @brief A line editor with a button to clear it and a callback to call on every edit event.
- */
-class LLSearchEditor : public LLUICtrl
+namespace LLInitParam
 {
-public:
-	LLSearchEditor(const std::string& name, 
-		const LLRect& rect,
-		S32 max_length_bytes,
-		void (*search_callback)(const std::string& search_string, void* user_data),
-		void* userdata);
-
-	virtual ~LLSearchEditor() {}
-
-	/*virtual*/ void	draw();
-
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-
-	void setText(const LLStringExplicit &new_text) { mSearchEdit->setText(new_text); }
-
-	void setSearchCallback(void (*search_callback)(const std::string& search_string, void* user_data), void* data) { mSearchCallback = search_callback; mCallbackUserData = data; }
-
-	// LLUICtrl interface
-	virtual void	setValue(const LLSD& value );
-	virtual LLSD	getValue() const;
-	virtual BOOL	setTextArg( const std::string& key, const LLStringExplicit& text );
-	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
-	virtual void	clear();
-
-private:
-	static void onSearchEdit(LLLineEditor* caller, void* user_data );
-	static void onClearSearch(void* user_data);
-
-	LLLineEditor* mSearchEdit;
-	class LLButton* mClearSearchButton;
-	void (*mSearchCallback)(const std::string& search_string, void* user_data);
-
-};
+    template<>
+	bool ParamCompare<LLLinePrevalidateFunc>::equals(
+		const LLLinePrevalidateFunc &a, const LLLinePrevalidateFunc &b); 
+
+    template<>
+	bool ParamCompare<boost::function<void (LLLineEditor *)> >::equals(
+		const boost::function<void (LLLineEditor *)> &a, const boost::function<void (LLLineEditor *)> &b); 
+}
 
 #endif  // LL_LINEEDITOR_
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 5fb0e57c06..a3588d9dae 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -59,8 +59,6 @@
 #include "llresmgr.h"
 #include "llui.h"
 
-#include "lluitrans.h"
-
 #include "llstl.h"
 
 #include "v2math.h"
@@ -78,7 +76,6 @@ S32 MENU_BAR_WIDTH = 0;
 ///============================================================================
 
 const std::string SEPARATOR_NAME("separator");
-const std::string TEAROFF_SEPARATOR_LABEL( "~~~~~~~~~~~" );
 const std::string SEPARATOR_LABEL( "-----------" );
 const std::string VERTICAL_SEPARATOR_LABEL( "|" );
 
@@ -110,12 +107,6 @@ const F32 MAX_MOUSE_SLOPE_SUB_MENU = 0.9f;
 
 const S32 PIE_GESTURE_ACTIVATE_DISTANCE = 10;
 
-LLColor4 LLMenuItemGL::sEnabledColor( 0.0f, 0.0f, 0.0f, 1.0f );
-LLColor4 LLMenuItemGL::sDisabledColor( 0.5f, 0.5f, 0.5f, 1.0f );
-LLColor4 LLMenuItemGL::sHighlightBackground( 0.0f, 0.0f, 0.7f, 1.0f );
-LLColor4 LLMenuItemGL::sHighlightForeground( 1.0f, 1.0f, 1.0f, 1.0f );
-
-LLColor4 LLMenuGL::sDefaultBackgroundColor( 0.25f, 0.25f, 0.25f, 0.75f );
 BOOL LLMenuGL::sKeyboardMode = FALSE;
 
 LLHandle<LLView> LLMenuHolderGL::sItemLastSelectedHandle;
@@ -131,69 +122,59 @@ const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f;
 ///============================================================================
 /// Class LLMenuItemGL
 ///============================================================================
-
 // Default constructor
-LLMenuItemGL::LLMenuItemGL( const std::string& name, const std::string& label, KEY key, MASK mask ) :
-	LLView( name, TRUE ),
-	mJumpKey(KEY_NONE),
-	mAcceleratorKey( key ),
-	mAcceleratorMask( mask ),
+LLMenuItemGL::LLMenuItemGL(const LLMenuItemGL::Params& p)
+:	LLUICtrl(p),
+	mJumpKey(p.jump_key),
 	mAllowKeyRepeat(FALSE),
 	mHighlight( FALSE ),
 	mGotHover( FALSE ),
 	mBriefItem( FALSE ),
-	mFont( LLFontGL::getFontSansSerif() ),
-	mStyle(LLFontGL::NORMAL),
-	mDrawTextDisabled( FALSE )
-{
-	setLabel( label );
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const
+	mDrawTextDisabled( FALSE ),
+	mFont(p.font),
+	mAcceleratorKey(KEY_NONE),
+	mAcceleratorMask(MASK_NONE),
+	mLabel(p.label.isProvided() ? p.label() : p.name()),
+	mEnabledColor(p.enabled_color()),
+	mDisabledColor(p.disabled_color()),
+	mHighlightBackground(p.highlight_bg_color()),
+	mHighlightForeground(p.highlight_fg_color())
 {
-	LLXMLNodePtr node = LLView::getXML();
-
-	node->createChild("type", TRUE)->setStringValue(getType());
-
-	node->createChild("label", TRUE)->setStringValue(mLabel);
-
-	if (mAcceleratorKey != KEY_NONE)
+#ifdef LL_DARWIN
+	// See if this Mac accelerator should really use the ctrl key and not get mapped to cmd
+	BOOL useMacCtrl = p.use_mac_ctrl;
+#endif // LL_DARWIN
+	
+	std::string shortcut = p.shortcut;
+	if (shortcut.find("control") != shortcut.npos)
 	{
-		std::stringstream out;
-		if (mAcceleratorMask & MASK_CONTROL)
-		{
-			out << "control|";
-		}
-		if (mAcceleratorMask & MASK_ALT)
-		{
-			out << "alt|";
-		}
-		if (mAcceleratorMask & MASK_SHIFT)
-		{
-			out << "shift|";
-		}
-		out << LLKeyboard::stringFromKey(mAcceleratorKey);
-
-		node->createChild("shortcut", TRUE)->setStringValue(out.str());
-		
 #ifdef LL_DARWIN
-		// Write in special tag if this key is really a ctrl combination on the Mac
-		if (mAcceleratorMask & MASK_MAC_CONTROL)
+		if ( useMacCtrl )
 		{
-			node->createChild("useMacCtrl", TRUE)->setBoolValue( TRUE );
+			mAcceleratorMask |= MASK_MAC_CONTROL;
 		}
 #endif // LL_DARWIN
+		mAcceleratorMask |= MASK_CONTROL;
+	}
+	if (shortcut.find("alt") != shortcut.npos)
+	{
+		mAcceleratorMask |= MASK_ALT;
 	}
+	if (shortcut.find("shift") != shortcut.npos)
+	{
+		mAcceleratorMask |= MASK_SHIFT;
+	}
+	S32 pipe_pos = shortcut.rfind("|");
+	std::string key_str = shortcut.substr(pipe_pos+1);
 
-	return node;
+	LLKeyboard::keyFromString(key_str, &mAcceleratorKey);
 }
 
 BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask)
 {
 	if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
 	{
-		doIt();
+		onCommit();
 		return TRUE;
 	}
 	return FALSE;
@@ -269,24 +250,24 @@ void LLMenuItemGL::appendAcceleratorString( std::string& st ) const
 	{
 		if ( mAcceleratorMask & MASK_MAC_CONTROL )
 		{
-			st.append( LLUITrans::getString("accel-mac-control") );
+			st.append( "Ctrl-" );
 		}
 		else
 		{
-			st.append( LLUITrans::getString("accel-mac-command") );		// Symbol would be "\xE2\x8C\x98"
+			st.append( "Cmd-" );		// Symbol would be "\xE2\x8C\x98"
 		}
 	}
 	if( mAcceleratorMask & MASK_ALT )
-		st.append( LLUITrans::getString("accel-mac-option") );		// Symbol would be "\xE2\x8C\xA5"
+		st.append( "Opt-" );		// Symbol would be "\xE2\x8C\xA5"
 	if( mAcceleratorMask & MASK_SHIFT )
-		st.append( LLUITrans::getString("accel-mac-shift") );		// Symbol would be "\xE2\x8C\xA7"
+		st.append( "Shift-" );		// Symbol would be "\xE2\x8C\xA7"
 #else
 	if( mAcceleratorMask & MASK_CONTROL )
-		st.append( LLUITrans::getString("accel-win-control") );
+		st.append( "Ctrl-" );
 	if( mAcceleratorMask & MASK_ALT )
-		st.append( LLUITrans::getString("accel-win-alt") );
+		st.append( "Alt-" );
 	if( mAcceleratorMask & MASK_SHIFT )
-		st.append( LLUITrans::getString("accel-win-shift") );
+		st.append( "Shift-" );
 #endif
 
 	std::string keystr = LLKeyboard::stringFromKey( mAcceleratorKey );
@@ -354,7 +335,7 @@ void LLMenuItemGL::buildDrawLabel( void )
 	mDrawAccelLabel = st;
 }
 
-void LLMenuItemGL::doIt( void )
+void LLMenuItemGL::onCommit( void )
 {
 	// close all open menus by default
 	// if parent menu is actually visible (and we are not triggering menu item via accelerator)
@@ -363,6 +344,8 @@ void LLMenuItemGL::doIt( void )
 	{
 		LLMenuGL::sMenuContainer->hideMenus();
 	}
+	
+	LLUICtrl::onCommit();
 }
 
 // set the hover status (called by it's menu)
@@ -402,7 +385,7 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask )
 			// switch to keyboard navigation mode
 			LLMenuGL::setKeyboardMode(TRUE);
 
-			doIt();
+			onCommit();
 			return TRUE;
 		}
 	}
@@ -415,7 +398,7 @@ BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK )
 	// switch to mouse navigation mode
 	LLMenuGL::setKeyboardMode(FALSE);
 
-	doIt();
+	onCommit();
 	make_ui_sound("UISndClickRelease");
 	return TRUE;
 }
@@ -439,55 +422,58 @@ void LLMenuItemGL::draw( void )
 	// let disabled items be highlighted, just don't draw them as such
 	if( getEnabled() && getHighlight() && !mBriefItem)
 	{
-		gGL.color4fv( sHighlightBackground.mV );
+		int debug_count = 0;
+		if (dynamic_cast<LLMenuItemCallGL*>(this))
+			debug_count++;
+		gGL.color4fv( mHighlightBackground.get().mV );
 		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	}
 
 	LLColor4 color;
 
-	U8 font_style = mStyle;
+	LLFontGL::ShadowType shadow_style = LLFontGL::NO_SHADOW;
 	if (getEnabled() && !mDrawTextDisabled )
 	{
-		font_style |= LLFontGL::DROP_SHADOW_SOFT;
+		shadow_style = LLFontGL::DROP_SHADOW_SOFT;
 	}
 
 	if ( getEnabled() && getHighlight() )
 	{
-		color = sHighlightForeground;
+		color = mHighlightForeground.get();
 	}
 	else if( getEnabled() && !mDrawTextDisabled )
 	{
-		color = sEnabledColor;
+		color = mEnabledColor.get();
 	}
 	else
 	{
-		color = sDisabledColor;
+		color = mDisabledColor.get();
 	}
 
 	// Draw the text on top.
 	if (mBriefItem)
 	{
 		mFont->render( mLabel, 0, BRIEF_PAD_PIXELS / 2, 0, color,
-					   LLFontGL::LEFT, LLFontGL::BOTTOM, font_style );
+					   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style );
 	}
 	else
 	{
 		if( !mDrawBoolLabel.empty() )
 		{
 			mFont->render( mDrawBoolLabel.getWString(), 0, (F32)LEFT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
-						   LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+						   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
 		}
 		mFont->render( mLabel.getWString(), 0, (F32)LEFT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
-					   LLFontGL::LEFT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+					   LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
 		if( !mDrawAccelLabel.empty() )
 		{
 			mFont->render( mDrawAccelLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PLAIN_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
-						   LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+						   LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
 		}
 		if( !mDrawBranchLabel.empty() )
 		{
 			mFont->render( mDrawBranchLabel.getWString(), 0, (F32)getRect().mRight - (F32)RIGHT_PAD_PIXELS, ((F32)MENU_ITEM_PADDING / 2.f) + 1.f, color,
-						   LLFontGL::RIGHT, LLFontGL::BOTTOM, font_style, S32_MAX, S32_MAX, NULL, FALSE );
+						   LLFontGL::RIGHT, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style, S32_MAX, S32_MAX, NULL, FALSE );
 		}
 	}
 
@@ -515,38 +501,41 @@ BOOL LLMenuItemGL::setLabelArg( const std::string& key, const LLStringExplicit&
 	return TRUE;
 }
 
+void LLMenuItemGL::onVisibilityChange(BOOL new_visibility)
+{
+	if (getMenu())
+	{
+		getMenu()->needsArrange();
+	}
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemSeparatorGL
 //
 // This class represents a separator.
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static LLRegisterWidget<LLMenuItemSeparatorGL> register_separator("menu_item_separator");
 
-class LLMenuItemSeparatorGL : public LLMenuItemGL
+LLMenuItemSeparatorGL::Params::Params()
 {
-public:
-	LLMenuItemSeparatorGL( const std::string &name = SEPARATOR_NAME );
-
-	virtual std::string getType() const	{ return "separator"; }
-
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void ) {}
-
-	virtual void draw( void );
-	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
-	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
-	virtual BOOL handleHover(S32 x, S32 y, MASK mask);
+	name = "separator";
+	label = SEPARATOR_LABEL;
+}
 
-	virtual U32 getNominalHeight( void ) const { return SEPARATOR_HEIGHT_PIXELS; }
-};
+LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) :
+	LLMenuItemGL( p )
+{
+}
 
-LLMenuItemSeparatorGL::LLMenuItemSeparatorGL( const std::string &name ) :
-	LLMenuItemGL( name, SEPARATOR_LABEL )
+//virtual
+U32 LLMenuItemSeparatorGL::getNominalHeight( void ) const
 {
+	return SEPARATOR_HEIGHT_PIXELS;
 }
 
 void LLMenuItemSeparatorGL::draw( void )
 {
-	gGL.color4fv( getDisabledColor().mV );
+	gGL.color4fv( mDisabledColor.get().mV );
 	const S32 y = getRect().getHeight() / 2;
 	const S32 PAD = 6;
 	gl_line_2d( PAD, y, getRect().getWidth() - PAD, y );
@@ -557,11 +546,13 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
 	LLMenuGL* parent_menu = getMenu();
 	if (y > getRect().getHeight() / 2)
 	{
-		return parent_menu->handleMouseDown(x + getRect().mLeft, getRect().mTop + 1, mask);
+		LLView* prev_menu_item = parent_menu->findPrevSibling(this);
+		return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
 	}
 	else
 	{
-		return parent_menu->handleMouseDown(x + getRect().mLeft, getRect().mBottom - 1, mask);
+		LLView* next_menu_item = parent_menu->findNextSibling(this);
+		return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
 	}
 }
 
@@ -570,11 +561,13 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask)
 	LLMenuGL* parent_menu = getMenu();
 	if (y > getRect().getHeight() / 2)
 	{
-		return parent_menu->handleMouseUp(x + getRect().mLeft, getRect().mTop + 1, mask);
+		LLView* prev_menu_item = parent_menu->findPrevSibling(this);
+		return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
 	}
 	else
 	{
-		return parent_menu->handleMouseUp(x + getRect().mLeft, getRect().mBottom - 1, mask);
+		LLView* next_menu_item = parent_menu->findNextSibling(this);
+		return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
 	}
 }
 
@@ -593,7 +586,6 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask)
 	}
 }
 
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemVerticalSeparatorGL
 //
@@ -617,19 +609,19 @@ LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void )
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemTearOffGL
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LLMenuItemTearOffGL::LLMenuItemTearOffGL(LLHandle<LLFloater> parent_floater_handle) : 
-	LLMenuItemGL(std::string("tear off"), TEAROFF_SEPARATOR_LABEL), 
-	mParentHandle(parent_floater_handle)
+LLMenuItemTearOffGL::LLMenuItemTearOffGL(const LLMenuItemTearOffGL::Params& p) 
+:	LLMenuItemGL(p), 
+	mParentHandle(p.parent_floater_handle)
 {
 }
 
 
-void LLMenuItemTearOffGL::doIt()
+void LLMenuItemTearOffGL::onCommit()
 {
 	if (getMenu()->getTornOff())
 	{
 		LLTearOffMenu* torn_off_menu = (LLTearOffMenu*)(getMenu()->getParent());
-		torn_off_menu->close();
+		torn_off_menu->closeFloater();
 	}
 	else
 	{
@@ -639,7 +631,7 @@ void LLMenuItemTearOffGL::doIt()
 			getMenu()->highlightNextItem(this);
 		}
 
-		getMenu()->arrange();
+		getMenu()->needsArrange();
 
 		LLFloater* parent_floater = mParentHandle.get();
 		LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu());
@@ -656,7 +648,7 @@ void LLMenuItemTearOffGL::doIt()
 			tear_off_menu->setFocus(TRUE);
 		}
 	}
-	LLMenuItemGL::doIt();
+	LLMenuItemGL::onCommit();
 }
 
 void LLMenuItemTearOffGL::draw()
@@ -664,17 +656,17 @@ void LLMenuItemTearOffGL::draw()
 	// disabled items can be highlighted, but shouldn't render as such
 	if( getEnabled() && getHighlight() && !isBriefItem())
 	{
-		gGL.color4fv( getHighlightBGColor().mV );
+		gGL.color4fv( mHighlightBackground.get().mV );
 		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	}
 
 	if (getEnabled())
 	{
-		gGL.color4fv( getEnabledColor().mV );
+		gGL.color4fv( mEnabledColor.get().mV );
 	}
 	else
 	{
-		gGL.color4fv( getDisabledColor().mV );
+		gGL.color4fv( mDisabledColor.get().mV );
 	}
 	const S32 y = getRect().getHeight() / 3;
 	const S32 PAD = 6;
@@ -697,11 +689,16 @@ U32 LLMenuItemTearOffGL::getNominalHeight( void ) const
 class LLMenuItemBlankGL : public LLMenuItemGL
 {
 public:
-	LLMenuItemBlankGL( void ) :	LLMenuItemGL( LLStringUtil::null, LLStringUtil::null )
+	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
 	{
-		setEnabled(FALSE);
-	}
-	virtual void doIt( void ) {}
+		Params()
+		{
+			name="";
+			enabled = false;
+		}
+	};
+	LLMenuItemBlankGL( const Params& p ) :	LLMenuItemGL( p )
+	{}
 	virtual void draw( void ) {}
 };
 
@@ -709,239 +706,117 @@ public:
 ///============================================================================
 /// Class LLMenuItemCallGL
 ///============================================================================
+static LLRegisterWidget<LLMenuItemCallGL> register_menu_item_call_gl("menu_item_call");
 
-LLMenuItemCallGL::LLMenuItemCallGL( const std::string& name, 
-									const std::string& label, 
-									menu_callback clicked_cb, 
-								    enabled_callback enabled_cb,
-									void* user_data,
-									KEY key, MASK mask,
-									BOOL enabled,
-									on_disabled_callback on_disabled_cb) :
-	LLMenuItemGL( name, label, key, mask ),
-	mCallback( clicked_cb ),
-	mEnabledCallback( enabled_cb ),
-	mLabelCallback(NULL),
-	mUserData( user_data ),
-	mOnDisabledCallback(on_disabled_cb)
-{
-	if(!enabled) setEnabled(FALSE);
-}
-
-LLMenuItemCallGL::LLMenuItemCallGL( const std::string& name, 
-									menu_callback clicked_cb, 
-								    enabled_callback enabled_cb,
-									void* user_data,
-									KEY key, MASK mask,
-									BOOL enabled,
-									on_disabled_callback on_disabled_cb) :
-	LLMenuItemGL( name, name, key, mask ),
-	mCallback( clicked_cb ),
-	mEnabledCallback( enabled_cb ),
-	mLabelCallback(NULL),
-	mUserData( user_data ),
-	mOnDisabledCallback(on_disabled_cb)
-{
-	if(!enabled) setEnabled(FALSE);
-}
-
-LLMenuItemCallGL::LLMenuItemCallGL(const std::string& name,
-								   const std::string& label,
-								   menu_callback clicked_cb,
-								   enabled_callback enabled_cb,
-								   label_callback label_cb,
-								   void* user_data,
-								   KEY key, MASK mask,
-								   BOOL enabled,
-								   on_disabled_callback on_disabled_cb) :
-	LLMenuItemGL(name, label, key, mask),
-	mCallback(clicked_cb),
-	mEnabledCallback(enabled_cb),
-	mLabelCallback(label_cb),
-	mUserData(user_data),
-	mOnDisabledCallback(on_disabled_cb)
-{
-	if(!enabled) setEnabled(FALSE);
-}
-
-LLMenuItemCallGL::LLMenuItemCallGL(const std::string& name,
-								   menu_callback clicked_cb,
-								   enabled_callback enabled_cb,
-								   label_callback label_cb,
-								   void* user_data,
-								   KEY key, MASK mask,
-								   BOOL enabled,
-								   on_disabled_callback on_disabled_cb) :
-	LLMenuItemGL(name, name, key, mask),
-	mCallback(clicked_cb),
-	mEnabledCallback(enabled_cb),
-	mLabelCallback(label_cb),
-	mUserData(user_data),
-	mOnDisabledCallback(on_disabled_cb)
-{
-	if(!enabled) setEnabled(FALSE);
-}
-
-void LLMenuItemCallGL::setEnabledControl(std::string enabled_control, LLView *context)
-{
-	// Register new listener
-	if (!enabled_control.empty())
-	{
-		LLControlVariable *control = context->findControl(enabled_control);
-		if (!control)
-		{
-			context->addBoolControl(enabled_control, getEnabled());
-			control = context->findControl(enabled_control);
-			llassert_always(control);
-		}
-		control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("enabled")));
-		setEnabled(control->getValue());
-	}
-}
-
-void LLMenuItemCallGL::setVisibleControl(std::string visible_control, LLView *context)
+LLMenuItemCallGL::LLMenuItemCallGL(const LLMenuItemCallGL::Params& p)
+:	LLMenuItemGL(p)
 {
-	// Register new listener
-	if (!visible_control.empty())
-	{
-		LLControlVariable *control = context->findControl(visible_control);
-		if (!control)
-		{
-			context->addBoolControl(visible_control, getVisible());
-			control = context->findControl(visible_control);
-			llassert_always(control);
-		}
-		control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("visible")));
-		setVisible(control->getValue());
-	}
 }
 
-// virtual
-LLXMLNodePtr LLMenuItemCallGL::getXML(bool save_children) const
+void LLMenuItemCallGL::initFromParams(const Params& p)
 {
-	LLXMLNodePtr node = LLMenuItemGL::getXML();
-
-	// Contents
-
-	std::vector<LLListenerEntry> listeners = mDispatcher->getListeners();
-	std::vector<LLListenerEntry>::iterator itor;
-	for (itor = listeners.begin(); itor != listeners.end(); ++itor)
+	if (p.on_enable.isProvided())
 	{
-		std::string listener_name = findEventListener((LLSimpleListener*)itor->listener);
-		if (!listener_name.empty())
+		initEnableCallback(p.on_enable, mEnableSignal);
+		// Set the enabled control variable (for backwards compatability)
+		if (p.on_enable.control_name.isProvided() && !p.on_enable.control_name().empty())
 		{
-			LLXMLNodePtr child_node = node->createChild("on_click", FALSE);
-			child_node->createChild("function", TRUE)->setStringValue(listener_name);
-			child_node->createChild("filter", TRUE)->setStringValue(itor->filter.asString());
-			child_node->createChild("userdata", TRUE)->setStringValue(itor->userdata.asString());
+			LLControlVariable* control = findControl(p.on_enable.control_name());
+			if (control)
+				setEnabledControlVariable(control);
 		}
 	}
-
-	return node;
+	if (p.on_click.isProvided())
+		initCommitCallback(p.on_click, mCommitSignal);
+		
+	LLUICtrl::initFromParams(p);
 }
 
-// doIt() - Call the callback provided
-void LLMenuItemCallGL::doIt( void )
+void LLMenuItemCallGL::onCommit( void )
 {
 	// RN: menu item can be deleted in callback, so beware
 	getMenu()->setItemLastSelected( this );
+	
+	LLMenuItemGL::onCommit();
+}
 
-	if( mCallback )
+void LLMenuItemCallGL::updateEnabled( void )
+{
+	if (mEnableSignal.num_slots() > 0)
 	{
-		mCallback( mUserData );
+		bool enabled = mEnableSignal(this, LLSD());
+		if (mEnabledControlVariable)
+		{
+			if (!enabled)
+				mEnabledControlVariable->set(false); // callback overrides control variable; this will call setEnabled()
+		}
+		else
+		{
+			setEnabled(enabled);
+		}
 	}
-	LLPointer<LLEvent> fired_event = new LLEvent(this);
-	fireEvent(fired_event, "on_click");
-	LLMenuItemGL::doIt();
 }
 
 void LLMenuItemCallGL::buildDrawLabel( void )
 {
-	LLPointer<LLEvent> fired_event = new LLEvent(this);
-	fireEvent(fired_event, "on_build");
-	if( mEnabledCallback )
-	{
-		setEnabled( mEnabledCallback( mUserData ) );
-	}
-	if(mLabelCallback)
-	{
-		std::string label;
-		mLabelCallback(label, mUserData);
-		mLabel = label;
-	}
+	updateEnabled();
 	LLMenuItemGL::buildDrawLabel();
 }
 
+BOOL LLMenuItemCallGL::handleKeyHere( KEY key, MASK mask )
+{
+	return LLMenuItemGL::handleKeyHere(key, mask);
+}
+
 BOOL LLMenuItemCallGL::handleAcceleratorKey( KEY key, MASK mask )
 {
- 	if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
+	if( (!gKeyboard->getKeyRepeated(key) || getAllowKeyRepeat()) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) )
 	{
-		LLPointer<LLEvent> fired_event = new LLEvent(this);
-		fireEvent(fired_event, "on_build");
-		if( mEnabledCallback )
+		updateEnabled();
+		if (getEnabled())
 		{
-			setEnabled( mEnabledCallback( mUserData ) );
-		}
-		if( !getEnabled() )
-		{
-			if( mOnDisabledCallback )
-			{
-				mOnDisabledCallback( mUserData );
-			}
+			onCommit();
+			return TRUE;
 		}
 	}
-	return LLMenuItemGL::handleAcceleratorKey(key, mask);
+	return FALSE;
 }
 
 ///============================================================================
 /// Class LLMenuItemCheckGL
 ///============================================================================
+static LLRegisterWidget<LLMenuItemCheckGL> register_menu_item_check_gl("menu_item_check");
 
-LLMenuItemCheckGL::LLMenuItemCheckGL ( const std::string& name, 
-									   const std::string& label,
-									   menu_callback clicked_cb,
-									   enabled_callback enabled_cb,
-									   check_callback check_cb,
-									   void* user_data,
-									   KEY key, MASK mask ) :
-	LLMenuItemCallGL( name, label, clicked_cb, enabled_cb, user_data, key, mask ),
-	mCheckCallback( check_cb ), 
-	mChecked(FALSE)
+LLMenuItemCheckGL::LLMenuItemCheckGL (const LLMenuItemCheckGL::Params& p)
+:	LLMenuItemCallGL(p)
 {
 }
 
-LLMenuItemCheckGL::LLMenuItemCheckGL ( const std::string& name, 
-									   menu_callback clicked_cb,
-									   enabled_callback enabled_cb,
-									   check_callback check_cb,
-									   void* user_data,
-									   KEY key, MASK mask ) :
-	LLMenuItemCallGL( name, name, clicked_cb, enabled_cb, user_data, key, mask ),
-	mCheckCallback( check_cb ), 
-	mChecked(FALSE)
+void LLMenuItemCheckGL::initFromParams(const Params& p)
 {
+	if (p.on_check.isProvided())
+	{
+		initEnableCallback(p.on_check, mCheckSignal);
+		// Set the control name (for backwards compatability)
+		if (p.on_check.control_name.isProvided() && !p.on_check.control_name().empty())
+		{
+			setControlName(p.on_check.control_name());
+		}
+	}
+		
+	LLMenuItemCallGL::initFromParams(p);
 }
 
-LLMenuItemCheckGL::LLMenuItemCheckGL ( const std::string& name, 
-									   const std::string& label,
-									   menu_callback clicked_cb,
-									   enabled_callback enabled_cb,
-									   std::string control_name,
-									   LLView *context,
-									   void* user_data,
-									   KEY key, MASK mask ) :
-	LLMenuItemCallGL( name, label, clicked_cb, enabled_cb, user_data, key, mask ),
-	mCheckCallback( NULL ),
-	mChecked(FALSE)
+void LLMenuItemCheckGL::onCommit( void )
 {
-	setControlName(control_name, context);
+	LLMenuItemCallGL::onCommit();
 }
 
 //virtual
 void LLMenuItemCheckGL::setValue(const LLSD& value)
 {
-	mChecked = value.asBoolean();
-	if(mChecked)
+	LLUICtrl::setValue(value);
+	if(value.asBoolean())
 	{
 		mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
 	}
@@ -951,68 +826,21 @@ void LLMenuItemCheckGL::setValue(const LLSD& value)
 	}
 }
 
-void LLMenuItemCheckGL::setCheckedControl(std::string checked_control, LLView *context)
-{
-	// Register new listener
-	if (!checked_control.empty())
-	{
-		LLControlVariable *control = context->findControl(checked_control);
-		if (!control)
-		{
-			context->addBoolControl(checked_control, mChecked);
-			control = context->findControl(checked_control);
-			llassert_always(control);
-		}
-		control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("value")));
-		mChecked = control->getValue();
-	}
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemCheckGL::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLMenuItemCallGL::getXML();
-	return node;
-}
-
 // called to rebuild the draw label
 void LLMenuItemCheckGL::buildDrawLabel( void )
 {
-	if(mChecked || (mCheckCallback && mCheckCallback( getUserData() ) ) )
+	// Note: mCheckSignal() returns true if no callbacks are set
+	bool checked = mCheckSignal(this, LLSD());
+	if (mControlVariable)
 	{
-		mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
+		if (!checked) 
+			setControlValue(false); // callback overrides control variable; this will call setValue()
 	}
 	else
 	{
-		mDrawBoolLabel.clear();
+		setValue(checked);
 	}
-	LLMenuItemCallGL::buildDrawLabel();
-}
-
-
-///============================================================================
-/// Class LLMenuItemToggleGL
-///============================================================================
-
-LLMenuItemToggleGL::LLMenuItemToggleGL( const std::string& name, const std::string& label, BOOL* toggle,
-										KEY key, MASK mask ) :
-	LLMenuItemGL( name, label, key, mask ),
-	mToggle( toggle )
-{
-}
-
-LLMenuItemToggleGL::LLMenuItemToggleGL( const std::string& name, BOOL* toggle,
-										KEY key, MASK mask ) :
-	LLMenuItemGL( name, name, key, mask ),
-	mToggle( toggle )
-{
-}
-
-
-// called to rebuild the draw label
-void LLMenuItemToggleGL::buildDrawLabel( void )
-{
-	if( *mToggle )
+	if(getValue().asBoolean())
 	{
 		mDrawBoolLabel = BOOLEAN_TRUE_PREFIX;
 	}
@@ -1020,64 +848,48 @@ void LLMenuItemToggleGL::buildDrawLabel( void )
 	{
 		mDrawBoolLabel.clear();
 	}
-	mDrawAccelLabel.clear();
-	std::string st = mDrawAccelLabel;
-	appendAcceleratorString( st );
-	mDrawAccelLabel = st;
-}
-
-// doIt() - do the primary funcationality of the menu item.
-void LLMenuItemToggleGL::doIt( void )
-{
-	getMenu()->setItemLastSelected( this );
-	//llinfos << "LLMenuItemToggleGL::doIt " << mLabel.c_str() << llendl;
-	*mToggle = !(*mToggle);
-	buildDrawLabel();
-	LLMenuItemGL::doIt();
+	LLMenuItemCallGL::buildDrawLabel();
 }
 
-
-LLMenuItemBranchGL::LLMenuItemBranchGL( const std::string& name, const std::string& label, LLHandle<LLView> branch,
-										KEY key, MASK mask ) :
-	LLMenuItemGL( name, label, key, mask ),
-	mBranch( branch )
+///============================================================================
+/// Class LLMenuItemBranchGL
+///============================================================================
+LLMenuItemBranchGL::LLMenuItemBranchGL(const LLMenuItemBranchGL::Params& p)
+  : LLMenuItemGL(p)
 {
-	if(!dynamic_cast<LLMenuGL*>(branch.get()))
+	LLMenuGL* branch = p.branch;
+	if (branch)
 	{
-		llerrs << "Non-menu handle passed as branch reference." << llendl;
-	}
-
-	if(getBranch())
-	{
-		getBranch()->setVisible( FALSE );
-		getBranch()->setParentMenuItem(this);
+		mBranchHandle = branch->getHandle();
+		branch->setVisible(FALSE);
+		branch->setParentMenuItem(this);
 	}
 }
 
 LLMenuItemBranchGL::~LLMenuItemBranchGL()
 {
-	LLView::deleteViewByHandle(mBranch);
+	LLView::deleteViewByHandle(mBranchHandle);
 }
 
 // virtual
 LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const
 {
+	LLMenuGL* branch = getBranch();
+	if (!branch)
+		return LLView::getChildView(name, recurse, create_if_missing);
+
 	// richard: this is redundant with parent, remove
-	if (getBranch())
+	if (branch->getName() == name)
 	{
-		if(getBranch()->getName() == name)
-		{
-			return getBranch();
-		}
-
-		// Always recurse on branches
-		LLView* child = getBranch()->getChildView(name, recurse, FALSE);
-		if(child)
-		{
-			return child;
-		}
+		return branch;
+	}
+	// Always recurse on branches
+	LLView* child = branch->getChildView(name, recurse, FALSE);
+	if (!child)
+	{
+		child = LLView::getChildView(name, recurse, create_if_missing);
 	}
-	return LLView::getChildView(name, recurse, create_if_missing);;
+	return child;
 }
 
 // virtual
@@ -1086,49 +898,35 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
 	// switch to mouse navigation mode
 	LLMenuGL::setKeyboardMode(FALSE);
 
-	doIt();
+	onCommit();
 	make_ui_sound("UISndClickRelease");
 	return TRUE;
 }
 
 BOOL LLMenuItemBranchGL::handleAcceleratorKey(KEY key, MASK mask)
 {
-	if(getBranch())
-	{
-		return getBranch()->handleAcceleratorKey(key, mask);
-	}
-	return FALSE;
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemBranchGL::getXML(bool save_children) const
-{
-	if (getBranch())
-	{
-		return getBranch()->getXML();
-	}
-
-	return LLMenuItemGL::getXML();
+	return getBranch() && getBranch()->handleAcceleratorKey(key, mask);
 }
 
-
 // This function checks to see if the accelerator key is already in use;
 // if not, it will be added to the list
 BOOL LLMenuItemBranchGL::addToAcceleratorList(std::list<LLKeyBinding*> *listp)
 {
-	if(getBranch())
-	{
-		U32 item_count = getBranch()->getItemCount();
-		LLMenuItemGL *item;
+	LLMenuGL* branch = getBranch();
+	if (!branch)
+		return FALSE;
 
-		while (item_count--)
+	U32 item_count = branch->getItemCount();
+	LLMenuItemGL *item;
+	
+	while (item_count--)
+	{
+		if ((item = branch->getItem(item_count)))
 		{
-			if ((item = getBranch()->getItem(item_count)))
-			{
-				return item->addToAcceleratorList(listp);
-			}
+			return item->addToAcceleratorList(listp);
 		}
 	}
+
 	return FALSE;
 }
 
@@ -1143,23 +941,24 @@ void LLMenuItemBranchGL::buildDrawLabel( void )
 	mDrawBranchLabel = BRANCH_SUFFIX;
 }
 
-// doIt() - do the primary functionality of the menu item.
-void LLMenuItemBranchGL::doIt( void )
+void LLMenuItemBranchGL::onCommit( void )
 {
 	openMenu();
 
 	// keyboard navigation automatically propagates highlight to sub-menu
 	// to facilitate fast menu control via jump keys
-	if (getBranch() && LLMenuGL::getKeyboardMode() && !getBranch()->getHighlightedItem())
+	if (LLMenuGL::getKeyboardMode() && getBranch()&& !getBranch()->getHighlightedItem())
 	{
 		getBranch()->highlightNextItem(NULL);
 	}
+	
+	LLUICtrl::onCommit();
 }
 
 BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
-	if (called_from_parent && getBranch())
+	if (getBranch() && called_from_parent)
 	{
 		handled = getBranch()->handleKey(key, mask, called_from_parent);
 	}
@@ -1175,7 +974,7 @@ BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
-	if (called_from_parent && getBranch())
+	if (getBranch() && called_from_parent)
 	{
 		handled = getBranch()->handleUnicodeChar(uni_char, TRUE);
 	}
@@ -1191,21 +990,21 @@ BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa
 
 void LLMenuItemBranchGL::setHighlight( BOOL highlight )
 {
-	if (highlight == getHighlight()) return;
+	if (highlight == getHighlight())
+		return;
 
-	if(!getBranch())
-	{ 
+	LLMenuGL* branch = getBranch();
+	if (!branch)
 		return;
-	}
 
-	BOOL auto_open = getEnabled() && (!getBranch()->getVisible() || getBranch()->getTornOff());
+	BOOL auto_open = getEnabled() && (!branch->getVisible() || branch->getTornOff());
 	// torn off menus don't open sub menus on hover unless they have focus
 	if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus())
 	{
 		auto_open = FALSE;
 	}
 	// don't auto open torn off sub-menus (need to explicitly active menu item to give them focus)
-	if (getBranch()->getTornOff())
+	if (branch->getTornOff())
 	{
 		auto_open = FALSE;
 	}
@@ -1219,14 +1018,14 @@ void LLMenuItemBranchGL::setHighlight( BOOL highlight )
 	}
 	else
 	{
-		if (getBranch()->getTornOff())
+		if (branch->getTornOff())
 		{
-			((LLFloater*)getBranch()->getParent())->setFocus(FALSE);
-			getBranch()->clearHoverItem();
+			((LLFloater*)branch->getParent())->setFocus(FALSE);
+			branch->clearHoverItem();
 		}
 		else
 		{
-			getBranch()->setVisible( FALSE );
+			branch->setVisible( FALSE );
 		}
 	}
 }
@@ -1260,15 +1059,19 @@ void LLMenuItemBranchGL::onVisibilityChange( BOOL new_visibility )
 
 BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask )
 {
-	if (getMenu()->getVisible() && getBranch() && getBranch()->getVisible() && key == KEY_LEFT)
+	LLMenuGL* branch = getBranch();
+	if (!branch)
+		return LLMenuItemGL::handleKeyHere(key, mask);
+
+	if (getMenu()->getVisible() && branch->getVisible() && key == KEY_LEFT)
 	{
 		// switch to keyboard navigation mode
 		LLMenuGL::setKeyboardMode(TRUE);
 
-		BOOL handled = getBranch()->clearHoverItem();
-		if (getBranch()->getTornOff())
+		BOOL handled = branch->clearHoverItem();
+		if (branch->getTornOff())
 		{
-			((LLFloater*)getBranch()->getParent())->setFocus(FALSE);
+			((LLFloater*)branch->getParent())->setFocus(FALSE);
 		}
 		if (handled && getMenu()->getTornOff())
 		{
@@ -1279,12 +1082,12 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask )
 
 	if (getHighlight() && 
 		getMenu()->isOpen() && 
-		key == KEY_RIGHT && getBranch() && !getBranch()->getHighlightedItem())
+		key == KEY_RIGHT && !branch->getHighlightedItem())
 	{
 		// switch to keyboard navigation mode
 		LLMenuGL::setKeyboardMode(TRUE);
 
-		LLMenuItemGL* itemp = getBranch()->highlightNextItem(NULL);
+		LLMenuItemGL* itemp = branch->highlightNextItem(NULL);
 		if (itemp)
 		{
 			return TRUE;
@@ -1296,39 +1099,41 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask )
 
 void LLMenuItemBranchGL::openMenu()
 {
-	if(!getBranch()) return;
+	LLMenuGL* branch = getBranch();
+	if (!branch)
+		return;
 
-	if (getBranch()->getTornOff())
+	if (branch->getTornOff())
 	{
-		gFloaterView->bringToFront((LLFloater*)getBranch()->getParent());
+		gFloaterView->bringToFront((LLFloater*)branch->getParent());
 		// this might not be necessary, as torn off branches don't get focus and hence no highligth
-		getBranch()->highlightNextItem(NULL);
+		branch->highlightNextItem(NULL);
 	}
-	else if( !getBranch()->getVisible() )
+	else if( !branch->getVisible() )
 	{
 		// get valid rectangle for menus
 		const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
 
-		getBranch()->arrange();
+		branch->arrange();
 
-		LLRect rect = getBranch()->getRect();
+		LLRect rect = branch->getRect();
 		// calculate root-view relative position for branch menu
 		S32 left = getRect().mRight;
 		S32 top = getRect().mTop - getRect().mBottom;
 
-		localPointToOtherView(left, top, &left, &top, getBranch()->getParent());
+		localPointToOtherView(left, top, &left, &top, branch->getParent());
 
 		rect.setLeftTopAndSize( left, top,
 								rect.getWidth(), rect.getHeight() );
 
-		if (getBranch()->getCanTearOff())
+		if (branch->getCanTearOff())
 		{
 			rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
 		}
-		getBranch()->setRect( rect );
+		branch->setRect( rect );
 		S32 x = 0;
 		S32 y = 0;
-		getBranch()->localPointToOtherView( 0, 0, &x, &y, getBranch()->getParent() ); 
+		branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); 
 		S32 delta_x = 0;
 		S32 delta_y = 0;
 		if( y < menu_region_rect.mBottom )
@@ -1342,9 +1147,9 @@ void LLMenuItemBranchGL::openMenu()
 			// move sub-menu over to left side
 			delta_x = llmax(-x, (-1 * (rect.getWidth() + getRect().getWidth())));
 		}
-		getBranch()->translate( delta_x, delta_y );
-		getBranch()->setVisible( TRUE );
-		getBranch()->getParent()->sendChildToFront(getBranch());
+		branch->translate( delta_x, delta_y );
+		branch->setVisible( TRUE );
+		branch->getParent()->sendChildToFront(branch);
 	}
 }
 
@@ -1361,10 +1166,7 @@ class LLMenuItemBranchDownGL : public LLMenuItemBranchGL
 protected:
 
 public:
-	LLMenuItemBranchDownGL( const std::string& name, const std::string& label, LLHandle<LLView> branch,
-							KEY key = KEY_NONE, MASK mask = MASK_NONE );
-
-	virtual std::string getType() const	{ return "menu"; }
+	LLMenuItemBranchDownGL( const Params& );
 
 	// returns the normal width of this control in pixels - this is
 	// used for calculating the widest item, as well as for horizontal
@@ -1392,11 +1194,8 @@ public:
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 };
 
-LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const std::string& name,
-												const std::string& label,
-												LLHandle<LLView> branch, 
-												KEY key, MASK mask ) :
-	LLMenuItemBranchGL( name, label, branch, key, mask )
+LLMenuItemBranchDownGL::LLMenuItemBranchDownGL( const Params& p) :
+	LLMenuItemBranchGL(p)
 {
 }
 
@@ -1501,7 +1300,7 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
 {
 	// switch to mouse control mode
 	LLMenuGL::setKeyboardMode(FALSE);
-	doIt();
+	onCommit();
 	make_ui_sound("UISndClick");
 	return TRUE;
 }
@@ -1540,7 +1339,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
 			// open new menu only if previous menu was open
 			if (itemp && itemp->getEnabled() && menu_open)
 			{
-				itemp->doIt();
+				itemp->onCommit();
 			}
 
 			return TRUE;
@@ -1554,7 +1353,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
 			// open new menu only if previous menu was open
 			if (itemp && itemp->getEnabled() && menu_open)
 			{
-				itemp->doIt();
+				itemp->onCommit();
 			}
 
 			return TRUE;
@@ -1566,7 +1365,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
 
 			if (!isActive())
 			{
-				doIt();
+				onCommit();
 			}
 			getBranch()->highlightNextItem(NULL);
 			return TRUE;
@@ -1578,7 +1377,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
 
 			if (!isActive())
 			{
-				doIt();
+				onCommit();
 			}
 			getBranch()->highlightPrevItem(NULL);
 			return TRUE;
@@ -1598,31 +1397,31 @@ void LLMenuItemBranchDownGL::draw( void )
 
 	if( getHighlight() )
 	{
-		gGL.color4fv( getHighlightBGColor().mV );
+		gGL.color4fv( mHighlightBackground.get().mV );
 		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	}
 
-	U8 font_style = getFontStyle();
+	LLFontGL::ShadowType shadow_style = LLFontGL::NO_SHADOW;
 	if (getEnabled() && !getDrawTextDisabled() )
 	{
-		font_style |= LLFontGL::DROP_SHADOW_SOFT;
+		shadow_style = LLFontGL::DROP_SHADOW_SOFT;
 	}
 
 	LLColor4 color;
 	if (getHighlight())
 	{
-		color = getHighlightFGColor();
+		color = mHighlightForeground.get();
 	}
 	else if( getEnabled() )
 	{
-		color = getEnabledColor();
+		color = mEnabledColor.get();
 	}
 	else
 	{
-		color = getDisabledColor();
+		color = mDisabledColor.get();
 	}
 	getFont()->render( mLabel.getWString(), 0, (F32)getRect().getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
-				   LLFontGL::HCENTER, LLFontGL::BOTTOM, font_style );
+				   LLFontGL::HCENTER, LLFontGL::BOTTOM, LLFontGL::NORMAL, shadow_style );
 
 
 	// underline navigation key only when keyboard navigation has been initiated
@@ -1651,16 +1450,14 @@ void LLMenuItemBranchDownGL::draw( void )
 
 static LLRegisterWidget<LLMenuGL> r1("menu");
 
-// Default constructor
-LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle<LLFloater> parent_floater_handle )
-:	LLUICtrl( name, LLRect(), FALSE, NULL, NULL ),
-	mBackgroundColor( sDefaultBackgroundColor ),
-	mBgVisible( TRUE ),
-	mParentMenuItem( NULL ),
-	mLabel( label ),
-	mDropShadowed( TRUE ),
-	mHorizontalLayout( FALSE ),
-	mKeepFixedSize( FALSE ),
+LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)
+:	LLUICtrl(p),
+	mBackgroundColor( p.bg_color() ),
+	mBgVisible( p.bg_visible ),
+	mDropShadowed( p.drop_shadow ),
+	mHorizontalLayout( p.horizontal_layout ),
+	mKeepFixedSize( p.keep_fixed_size ),
+	mLabel (p.label),
 	mLastMouseX(0),
 	mLastMouseY(0),
 	mMouseVelX(0),
@@ -1669,37 +1466,36 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle<
 	mTearOffItem(NULL),
 	mSpilloverBranch(NULL),
 	mSpilloverMenu(NULL),
-	mParentFloaterHandle(parent_floater_handle),
-	mJumpKey(KEY_NONE)
+	mJumpKey(p.jump_key),
+	mCreateJumpKeys(p.create_jump_keys),
+	mParentFloaterHandle(p.parent_floater),
+	mNeedsArrange(FALSE)
 {
+	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+	boost::char_separator<char> sep("_");
+	tokenizer tokens(p.label(), sep);
+	tokenizer::iterator token_iter;
+
+	S32 token_count = 0;
+	std::string new_menu_label;
+	for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+	{
+		new_menu_label += (*token_iter);
+		if (token_count > 0)
+		{
+			setJumpKey((*token_iter).c_str()[0]);
+		}
+		++token_count;
+	}
+	setLabel(new_menu_label);
+
 	mFadeTimer.stop();
-	setCanTearOff(TRUE, parent_floater_handle);
-	setTabStop(FALSE);
-}
-
-LLMenuGL::LLMenuGL( const std::string& label, LLHandle<LLFloater> parent_floater_handle )
-:	LLUICtrl( label, LLRect(), FALSE, NULL, NULL ),
-	mBackgroundColor( sDefaultBackgroundColor ),
-	mBgVisible( TRUE ),
-	mParentMenuItem( NULL ),
-	mLabel( label ),
-	mDropShadowed( TRUE ),
-	mHorizontalLayout( FALSE ),
-	mKeepFixedSize( FALSE ),
-	mLastMouseX(0),
-	mLastMouseY(0),
-	mMouseVelX(0),
-	mMouseVelY(0),
-	mTornOff(FALSE),
-	mTearOffItem(NULL),
-	mSpilloverBranch(NULL),
-	mSpilloverMenu(NULL),
-	mParentFloaterHandle(parent_floater_handle),
-	mJumpKey(KEY_NONE)
+}
+
+void LLMenuGL::initFromParams(const LLMenuGL::Params& p)
 {
-	mFadeTimer.stop();
-	setCanTearOff(TRUE, parent_floater_handle);
-	setTabStop(FALSE);
+	LLUICtrl::initFromParams(p);
+	setCanTearOff(p.can_tear_off, p.parent_floater);
 }
 
 // Destroys the object
@@ -1715,10 +1511,10 @@ void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle<LLFloater> parent_floater_h
 {
 	if (tear_off && mTearOffItem == NULL)
 	{
-		mTearOffItem = new LLMenuItemTearOffGL(parent_floater_handle);
-		mItems.insert(mItems.begin(), mTearOffItem);
-		addChildAtEnd(mTearOffItem);
-		arrange();
+		LLMenuItemTearOffGL::Params p;
+		p.parent_floater_handle = parent_floater_handle;
+		mTearOffItem = LLUICtrlFactory::create<LLMenuItemTearOffGL>(p);
+		addChildInBack(mTearOffItem);
 	}
 	else if (!tear_off && mTearOffItem != NULL)
 	{
@@ -1726,337 +1522,68 @@ void LLMenuGL::setCanTearOff(BOOL tear_off, LLHandle<LLFloater> parent_floater_h
 		removeChild(mTearOffItem);
 		delete mTearOffItem;
 		mTearOffItem = NULL;
-		arrange();
+		needsArrange();
 	}
 }
 
-// virtual
-LLXMLNodePtr LLMenuGL::getXML(bool save_children) const
+bool LLMenuGL::addChild(LLView* view, S32 tab_group)
 {
-	LLXMLNodePtr node = LLView::getXML();
-
-	// Attributes
-
-	node->createChild("opaque", TRUE)->setBoolValue(mBgVisible);
-
-	node->createChild("drop_shadow", TRUE)->setBoolValue(mDropShadowed);
-
-	node->createChild("tear_off", TRUE)->setBoolValue((mTearOffItem != NULL));
-
-	if (mBgVisible)
+	if (LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view))
 	{
-		// TomY TODO: this should save out the color control name
-		node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
+		appendMenu(menup);
+		return true;
 	}
-
-	// Contents
-	item_list_t::const_iterator item_iter;
-	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+	else if (LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(view))
 	{
-		LLView* child = (*item_iter);
-		LLMenuItemGL* item = (LLMenuItemGL*)child;
-
-		LLXMLNodePtr child_node = item->getXML();
-
-		node->addChild(child_node);
+		append(itemp);
+		return true;
 	}
-
-	return node;
+	return false;
 }
 
-void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory)
+void LLMenuGL::removeChild( LLView* ctrl)
 {
-	if (child->hasName(LL_MENU_GL_TAG))
+	LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(ctrl);
+	if (itemp)
 	{
-		// SUBMENU
-		LLMenuGL *submenu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory);
-		appendMenu(submenu);
-		if (LLMenuGL::sMenuContainer != NULL)
-		{
-			submenu->updateParent(LLMenuGL::sMenuContainer);
-		}
-		else
+		item_list_t::iterator found_it = std::find(mItems.begin(), mItems.end(), (itemp));
+		if (found_it != mItems.end())
 		{
-			submenu->updateParent(parent);
+			mItems.erase(found_it);
 		}
 	}
-	else if (child->hasName(LL_MENU_ITEM_CALL_GL_TAG) || 
-			child->hasName(LL_MENU_ITEM_CHECK_GL_TAG) || 
-			child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG))
-	{
-		LLMenuItemGL *item = NULL;
+	return LLUICtrl::removeChild(ctrl);
+}
 
-		std::string type;
-		std::string item_name;
-		std::string source_label;
-		std::string item_label;
-		KEY		 jump_key = KEY_NONE;
+BOOL LLMenuGL::postBuild()
+{
+	createJumpKeys();
+	return LLUICtrl::postBuild();
+}
 
-		child->getAttributeString("type", type);
-		child->getAttributeString("name", item_name);
-		child->getAttributeString("label", source_label);
 
-		// parse jump key out of label
-		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-		boost::char_separator<char> sep("_");
-		tokenizer tokens(source_label, sep);
-		tokenizer::iterator token_iter;
-		S32 token_count = 0;
-		for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
-		{
-			item_label += (*token_iter);
-			if (token_count > 0)
-			{
-				jump_key = (*token_iter).c_str()[0];
-			}
-			++token_count;
-		}
+// are we the childmost active menu and hence our jump keys should be enabled?
+// or are we a free-standing torn-off menu (which uses jump keys too)
+BOOL LLMenuGL::jumpKeysActive()
+{
+	LLMenuItemGL* highlighted_item = getHighlightedItem();
+	BOOL active = getVisible() && getEnabled();
+	if (getTornOff())
+	{
+		// activation of jump keys on torn off menus controlled by keyboard focus
+		active = active && ((LLFloater*)getParent())->hasFocus();
 
-
-		if (child->hasName(LL_MENU_ITEM_SEPARATOR_GL_TAG))
-		{
-			appendSeparator(item_name);
-		}
-		else
-		{
-			// ITEM
-			if (child->hasName(LL_MENU_ITEM_CALL_GL_TAG) || 
-				child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
-			{
-				MASK mask = 0;
-							
-#ifdef LL_DARWIN
-				// See if this Mac accelerator should really use the ctrl key and not get mapped to cmd
-				BOOL useMacCtrl = FALSE;
-				child->getAttributeBOOL("useMacCtrl", useMacCtrl);
-#endif // LL_DARWIN
-				
-				std::string shortcut;
-				child->getAttributeString("shortcut", shortcut);
-				if (shortcut.find("control") != shortcut.npos)
-				{
-#ifdef LL_DARWIN
-					if ( useMacCtrl )
-					{
-						mask |= MASK_MAC_CONTROL;
-					}
-#endif // LL_DARWIN
-					mask |= MASK_CONTROL;
-				}
-				if (shortcut.find("alt") != shortcut.npos)
-				{
-					mask |= MASK_ALT;
-				}
-				if (shortcut.find("shift") != shortcut.npos)
-				{
-					mask |= MASK_SHIFT;
-				}
-				S32 pipe_pos = shortcut.rfind("|");
-				std::string key_str = shortcut.substr(pipe_pos+1);
-
-				KEY key = KEY_NONE;
-				LLKeyboard::keyFromString(key_str, &key);
-
-				LLMenuItemCallGL *new_item;
-				LLXMLNodePtr call_child;
-
-				if (child->hasName(LL_MENU_ITEM_CHECK_GL_TAG))
-				{
-					std::string control_name;
-					child->getAttributeString("control_name", control_name);
-
-					new_item = new LLMenuItemCheckGL(item_name, item_label, 0, 0, control_name, parent, 0, key, mask);
-
-					for (call_child = child->getFirstChild(); call_child.notNull(); call_child = call_child->getNextSibling())
-					{
-						if (call_child->hasName("on_check"))
-						{
-							std::string callback_name;
-							std::string control_name;
-							if (call_child->hasAttribute("function"))
-							{
-								call_child->getAttributeString("function", callback_name);
-
-								control_name = callback_name;
-
-								std::string callback_data = item_name;
-								if (call_child->hasAttribute("userdata"))
-								{
-									call_child->getAttributeString("userdata", callback_data);
-									if (!callback_data.empty())
-									{
-										control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
-									}
-								}
-
-								LLSD userdata;
-								userdata["control"] = control_name;
-								userdata["data"] = callback_data;
-
-								LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
-								if (!callback) continue;
-
-								new_item->addListener(callback, "on_build", userdata);
-							}
-							else if (call_child->hasAttribute("control"))
-							{
-								call_child->getAttributeString("control", control_name);
-							}
-							else
-							{
-								continue;
-							}
-							LLControlVariable *control = parent->findControl(control_name);
-							if (!control)
-							{
-								parent->addBoolControl(control_name, FALSE);
-							}
-							((LLMenuItemCheckGL*)new_item)->setCheckedControl(control_name, parent);
-						}
-					}
-				}
-				else
-				{
-					new_item = new LLMenuItemCallGL(item_name, item_label, 0, 0, 0, 0, key, mask);
-				}
-
-				for (call_child = child->getFirstChild(); call_child.notNull(); call_child = call_child->getNextSibling())
-				{
-					if (call_child->hasName("on_click"))
-					{
-						std::string callback_name;
-						call_child->getAttributeString("function", callback_name);
-
-						std::string callback_data = item_name;
-						if (call_child->hasAttribute("userdata"))
-						{
-							call_child->getAttributeString("userdata", callback_data);
-						}
-
-						LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
-						if (!callback) continue;
-
-						new_item->addListener(callback, "on_click", callback_data);
-					}
-					if (call_child->hasName("on_enable"))
-					{
-						std::string callback_name;
-						std::string control_name;
-						if (call_child->hasAttribute("function"))
-						{
-							call_child->getAttributeString("function", callback_name);
-
-							control_name = callback_name;
-
-							std::string callback_data;
-							if (call_child->hasAttribute("userdata"))
-							{
-								call_child->getAttributeString("userdata", callback_data);
-								if (!callback_data.empty())
-								{
-									control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
-								}
-							}
-
-							LLSD userdata;
-							userdata["control"] = control_name;
-							userdata["data"] = callback_data;
-
-							LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
-							if (!callback) continue;
-
-							new_item->addListener(callback, "on_build", userdata);
-						}
-						else if (call_child->hasAttribute("control"))
-						{
-							call_child->getAttributeString("control", control_name);
-						}
-						else
-						{
-							continue;
-						}
-						new_item->setEnabledControl(control_name, parent);
-					}
-					if (call_child->hasName("on_visible"))
-					{
-						std::string callback_name;
-						std::string control_name;
-						if (call_child->hasAttribute("function"))
-						{
-							call_child->getAttributeString("function", callback_name);
-
-							control_name = callback_name;
-
-							std::string callback_data;
-							if (call_child->hasAttribute("userdata"))
-							{
-								call_child->getAttributeString("userdata", callback_data);
-								if (!callback_data.empty())
-								{
-									control_name = llformat("%s(%s)", callback_name.c_str(), callback_data.c_str());
-								}
-							}
-
-							LLSD userdata;
-							userdata["control"] = control_name;
-							userdata["data"] = callback_data;
-
-							LLSimpleListener* callback = parent->getListenerByName(callback_name);
-
-							if (!callback) continue;
-
-							new_item->addListener(callback, "on_build", userdata);
-						}
-						else if (call_child->hasAttribute("control"))
-						{
-							call_child->getAttributeString("control", control_name);
-						}
-						else
-						{
-							continue;
-						}
-						new_item->setVisibleControl(control_name, parent);
-					}
-				}
-				item = new_item;
-				item->setLabel(item_label);
-				if (jump_key != KEY_NONE)
-					item->setJumpKey(jump_key);
-			}
-
-			if (item != NULL)
-			{
-				append(item);
-			}
-		}
-	}
-}
-
-// are we the childmost active menu and hence our jump keys should be enabled?
-// or are we a free-standing torn-off menu (which uses jump keys too)
-BOOL LLMenuGL::jumpKeysActive()
-{
-	LLMenuItemGL* highlighted_item = getHighlightedItem();
-	BOOL active = getVisible() && getEnabled();
-	if (getTornOff())
-	{
-		// activation of jump keys on torn off menus controlled by keyboard focus
-		active = active && ((LLFloater*)getParent())->hasFocus();
-
-	}
-	else
-	{
-		// Are we the terminal active menu?
-		// Yes, if parent menu item deems us to be active (just being visible is sufficient for top-level menus)
-		// and we don't have a highlighted menu item pointing to an active sub-menu
-		active = active && (!getParentMenuItem() || getParentMenuItem()->isActive()) // I have a parent that is active...
-		                && (!highlighted_item || !highlighted_item->isActive()); //... but no child that is active
-	}
-	return active;
-}
+	}
+	else
+	{
+		// Are we the terminal active menu?
+		// Yes, if parent menu item deems us to be active (just being visible is sufficient for top-level menus)
+		// and we don't have a highlighted menu item pointing to an active sub-menu
+		active = active && (!getParentMenuItem() || getParentMenuItem()->isActive()) // I have a parent that is active...
+		                && (!highlighted_item || !highlighted_item->isActive()); //... but no child that is active
+	}
+	return active;
+}
 
 BOOL LLMenuGL::isOpen()
 {
@@ -2079,75 +1606,6 @@ BOOL LLMenuGL::isOpen()
 		return getVisible();
 	}
 }
-// static
-LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("menu");
-	node->getAttributeString("name", name);
-
-	std::string label = name;
-	node->getAttributeString("label", label);
-
-	// parse jump key out of label
-	std::string new_menu_label;
-
-	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-	boost::char_separator<char> sep("_");
-	tokenizer tokens(label, sep);
-	tokenizer::iterator token_iter;
-
-	KEY jump_key = KEY_NONE;
-	S32 token_count = 0;
-	for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
-	{
-		new_menu_label += (*token_iter);
-		if (token_count > 0)
-		{
-			jump_key = (*token_iter).c_str()[0];
-		}
-		++token_count;
-	}
-
-	BOOL opaque = FALSE;
-	node->getAttributeBOOL("opaque", opaque);
-
-	LLMenuGL *menu = new LLMenuGL(name, new_menu_label);
-
-	menu->setJumpKey(jump_key);
-
-	BOOL tear_off = FALSE;
-	node->getAttributeBOOL("tear_off", tear_off);
-	menu->setCanTearOff(tear_off);
-
-	if (node->hasAttribute("drop_shadow"))
-	{
-		BOOL drop_shadow = FALSE;
-		node->getAttributeBOOL("drop_shadow", drop_shadow);
-		menu->setDropShadowed(drop_shadow);
-	}
-
-	menu->setBackgroundVisible(opaque);
-	LLColor4 color(0,0,0,1);
-	if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
-	{
-		menu->setBackgroundColor(color);
-	}
-
-	BOOL create_jump_keys = FALSE;
-	node->getAttributeBOOL("create_jump_keys", create_jump_keys);
-
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		menu->parseChildXML(child, parent, factory);
-	}
-
-	if (create_jump_keys)
-	{
-		menu->createJumpKeys();
-	}
-	return menu;
-}
 
 
 // rearrange the child rects so they fit the shape of the menu.
@@ -2169,7 +1627,7 @@ void LLMenuGL::arrange( void )
 		U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth();
 		U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight();
 		// *FIX: create the item first and then ask for its dimensions?
-		S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") );
+		S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate
 		S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING;
 
 		if (mHorizontalLayout)
@@ -2179,22 +1637,25 @@ void LLMenuGL::arrange( void )
 			{
 				if ((*item_iter)->getVisible())
 				{
-					if (!getTornOff() && width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width)
+					if (!getTornOff() 
+						&& *item_iter != mSpilloverBranch
+						&& width + (*item_iter)->getNominalWidth() > max_width - spillover_item_width)
 					{
 						// no room for any more items
 						createSpilloverBranch();
 
-						item_list_t::iterator spillover_iter;
-						for (spillover_iter = item_iter; spillover_iter != mItems.end(); ++spillover_iter)
+						std::vector<LLMenuItemGL*> items_to_remove;
+						std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove));
+						std::vector<LLMenuItemGL*>::iterator spillover_iter;
+						for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter)
 						{
 							LLMenuItemGL* itemp = (*spillover_iter);
 							removeChild(itemp);
-							mSpilloverMenu->append(itemp);
+							mSpilloverMenu->addChild(itemp);
 						}
-						mItems.erase(item_iter, mItems.end());
-						
-						mItems.push_back(mSpilloverBranch);
+
 						addChild(mSpilloverBranch);
+						
 						height = llmax(height, mSpilloverBranch->getNominalHeight());
 						width += mSpilloverBranch->getNominalWidth();
 
@@ -2216,21 +1677,26 @@ void LLMenuGL::arrange( void )
 			{
 				if ((*item_iter)->getVisible())
 				{
-					if (!getTornOff() && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height)
+					if (!getTornOff() 
+						&& *item_iter != mSpilloverBranch
+						&& height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height)
 					{
 						// no room for any more items
 						createSpilloverBranch();
 
-						item_list_t::iterator spillover_iter;
-						for (spillover_iter= item_iter; spillover_iter != mItems.end(); ++spillover_iter)
+						std::vector<LLMenuItemGL*> items_to_remove;
+						std::copy(item_iter, mItems.end(), std::back_inserter(items_to_remove));
+						std::vector<LLMenuItemGL*>::iterator spillover_iter;
+						for (spillover_iter= items_to_remove.begin(); spillover_iter != items_to_remove.end(); ++spillover_iter)
 						{
 							LLMenuItemGL* itemp = (*spillover_iter);
 							removeChild(itemp);
-							mSpilloverMenu->append(itemp);
+							mSpilloverMenu->addChild(itemp);
 						}
-						mItems.erase(item_iter, mItems.end());
-						mItems.push_back(mSpilloverBranch);
+
+
 						addChild(mSpilloverBranch);
+
 						height += mSpilloverBranch->getNominalHeight();
 						width = llmax( width, mSpilloverBranch->getNominalWidth() );
 
@@ -2278,6 +1744,15 @@ void LLMenuGL::arrange( void )
 	}
 }
 
+void LLMenuGL::arrangeAndClear( void )
+{
+	if (mNeedsArrange)
+	{
+		arrange();
+		mNeedsArrange = FALSE;
+	}
+}
+
 void LLMenuGL::createSpilloverBranch()
 {
 	if (!mSpilloverBranch)
@@ -2286,14 +1761,24 @@ void LLMenuGL::createSpilloverBranch()
 		delete mSpilloverMenu;
 		// technically, you can't tear off spillover menus, but we're passing the handle
 		// along just to be safe
-		mSpilloverMenu = new LLMenuGL(std::string("More"), std::string("More"), mParentFloaterHandle);
+		LLMenuGL::Params p;
+		p.name("More");
+		p.label("More"); // *TODO: Translate
+		p.parent_floater(mParentFloaterHandle);
+		p.bg_color(mBackgroundColor);
+		p.bg_visible(true);
+		p.can_tear_off(false);
+		mSpilloverMenu = new LLMenuGL(p);
 		mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer);
-		// Inherit colors
-		mSpilloverMenu->setBackgroundColor( mBackgroundColor );
-		mSpilloverMenu->setCanTearOff(FALSE);
 
-		mSpilloverBranch = new LLMenuItemBranchGL(std::string("More"), std::string("More"), mSpilloverMenu->getHandle());
-		mSpilloverBranch->setFontStyle(LLFontGL::ITALIC);
+		LLMenuItemBranchGL::Params branch_params;
+		branch_params.name = "More";
+		branch_params.label = "More"; // *TODO: Translate
+		branch_params.branch = mSpilloverMenu;
+		branch_params.font.style = "italic";
+
+
+		mSpilloverBranch = LLUICtrlFactory::create<LLMenuItemBranchGL>(branch_params);
 	}
 }
 
@@ -2304,25 +1789,15 @@ void LLMenuGL::cleanupSpilloverBranch()
 		// head-recursion to propagate items back up to root menu
 		mSpilloverMenu->cleanupSpilloverBranch();
 
-		removeChild(mSpilloverBranch);
-
-		item_list_t::iterator found_iter = std::find(mItems.begin(), mItems.end(), mSpilloverBranch);
-		if (found_iter != mItems.end())
-		{
-			mItems.erase(found_iter);
-		}
-
 		// pop off spillover items
 		while (mSpilloverMenu->getItemCount())
 		{
 			LLMenuItemGL* itemp = mSpilloverMenu->getItem(0);
 			mSpilloverMenu->removeChild(itemp);
-			mSpilloverMenu->mItems.erase(mSpilloverMenu->mItems.begin());
 			// put them at the end of our own list
-			mItems.push_back(itemp);
 			addChild(itemp);
 		}
-
+		
 		// Delete the branch, and since the branch will delete the menu,
 		// set the menu* to null.
 		delete mSpilloverBranch;
@@ -2333,6 +1808,9 @@ void LLMenuGL::cleanupSpilloverBranch()
 
 void LLMenuGL::createJumpKeys()
 {
+	if (!mCreateJumpKeys) return;
+	mCreateJumpKeys = FALSE;
+
 	mJumpKeys.clear();
 
 	std::set<std::string> unique_words;
@@ -2442,7 +1920,7 @@ void LLMenuGL::empty( void )
 void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom)
 {
 	setRect(LLRect(left, getRect().mTop, getRect().mRight, bottom));
-	arrange();
+	needsArrange();
 }
 
 BOOL LLMenuGL::handleJumpKey(KEY key)
@@ -2455,12 +1933,9 @@ BOOL LLMenuGL::handleJumpKey(KEY key)
 		// switch to keyboard navigation mode
 		LLMenuGL::setKeyboardMode(TRUE);
 
-		// force highlight to close old menus and any open sub-menus
-
-		//clearHoverItem();
 		// force highlight to close old menus and open and sub-menus
 		found_it->second->setHighlight(TRUE);
-		found_it->second->doIt();
+		found_it->second->onCommit();
 
 	}
 	// if we are navigating the menus, we need to eat the keystroke
@@ -2472,21 +1947,18 @@ BOOL LLMenuGL::handleJumpKey(KEY key)
 // Add the menu item to this menu.
 BOOL LLMenuGL::append( LLMenuItemGL* item )
 {
+	if (!item) return FALSE;
 	mItems.push_back( item );
-	addChild( item );
-	arrange();
+	LLUICtrl::addChild(item);
+	needsArrange();
 	return TRUE;
 }
 
 // add a separator to this menu
-BOOL LLMenuGL::appendSeparator( const std::string &separator_name )
+BOOL LLMenuGL::addSeparator()
 {
-	LLMenuItemGL* separator;
-	if (separator_name.empty())
-		separator = new LLMenuItemSeparatorGL(std::string("separator"));
-	else
-		separator = new LLMenuItemSeparatorGL(separator_name);
-	return append( separator );
+	LLMenuItemGL* separator = new LLMenuItemSeparatorGL();
+	return addChild(separator);
 }
 
 // add a menu - this will create a cascading menu
@@ -2499,14 +1971,22 @@ BOOL LLMenuGL::appendMenu( LLMenuGL* menu )
 	}
 	BOOL success = TRUE;
 
-	LLMenuItemBranchGL* branch = NULL;
-	branch = new LLMenuItemBranchGL( menu->getName(), menu->getLabel(), menu->getHandle() );
-	branch->setJumpKey(menu->getJumpKey());
+	LLMenuItemBranchGL::Params p;
+	p.name = menu->getName();
+	p.label = menu->getLabel();
+	p.branch = menu;
+	p.jump_key = menu->getJumpKey();
+	p.enabled_color=LLUI::getCachedColorFunctor("MenuItemEnabledColor");
+	p.disabled_color=LLUI::getCachedColorFunctor("MenuItemDisabledColor");
+	p.highlight_bg_color=LLUI::getCachedColorFunctor("MenuItemHighlightBgColor");
+	p.highlight_fg_color=LLUI::getCachedColorFunctor("MenuItemHighlightFgColor");
+
+	LLMenuItemBranchGL* branch = LLUICtrlFactory::create<LLMenuItemBranchGL>(p);
 	success &= append( branch );
 
 	// Inherit colors
 	menu->setBackgroundColor( mBackgroundColor );
-
+	menu->updateParent(LLMenuGL::sMenuContainer);
 	return success;
 }
 
@@ -2544,6 +2024,7 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible )
 		if( (*item_iter)->getName() == name )
 		{
 			(*item_iter)->setVisible( visible );
+			needsArrange();
 			break;
 		}
 	}
@@ -2556,7 +2037,7 @@ void LLMenuGL::setItemLastSelected(LLMenuItemGL* item)
 		LLMenuHolderGL::setActivatedItem(item);
 	}
 
-	// fix the checkmarks
+	// update enabled and checkmark status
 	item->buildDrawLabel();
 }
 
@@ -2654,7 +2135,7 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
 	while(1)
 	{
 		// skip separators and disabled/invisible items
-		if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && (*next_item_iter)->getType() != SEPARATOR_NAME)
+		if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getVisible() && !dynamic_cast<LLMenuItemSeparatorGL*>(*next_item_iter))
 		{
 			if (cur_item)
 			{
@@ -2761,7 +2242,10 @@ void LLMenuGL::updateParent(LLView* parentp)
 	{
 		getParent()->removeChild(this);
 	}
-	parentp->addChild(this);
+	if (parentp)
+	{
+		parentp->addChild(this);
+	}
 	item_list_t::iterator item_iter;
 	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
 	{
@@ -2864,29 +2348,39 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
 		}
 	}
 	getWindow()->setCursor(UI_CURSOR_ARROW);
+
+	//ProductEngine: what behavior is this addressing?
+	// *HACK Release the mouse capture
+	gFocusMgr.setMouseCapture( NULL );
+
 	return TRUE;
 }
 
 void LLMenuGL::draw( void )
 {
+	if (mNeedsArrange)
+	{
+		arrange();
+		mNeedsArrange = FALSE;
+	}
 	if (mDropShadowed && !mTornOff)
 	{
+		static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0);
+		static LLUICachedControl<LLColor4> color_drop_shadow ("ColorDropShadow", *(new LLColor4));
 		gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, 
-			LLUI::sColorsGroup->getColor("ColorDropShadow"), 
-			LLUI::sConfigGroup->getS32("DropShadowFloater") );
+			color_drop_shadow, drop_shadow_floater );
 	}
 
-	LLColor4 bg_color = mBackgroundColor;
-
 	if( mBgVisible )
 	{
-		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor );
+		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor.get() );
 	}
 	LLView::draw();
 }
 
-void LLMenuGL::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
+void LLMenuGL::drawBackground(LLMenuItemGL* itemp, F32 alpha)
 {
+	LLColor4 color = itemp->getHighlightBgColor() % alpha;
 	gGL.color4fv( color.mV );
 	LLRect item_rect = itemp->getRect();
 	gl_rect_2d( 0, item_rect.getHeight(), item_rect.getWidth(), 0);
@@ -2962,6 +2456,7 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
 	const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
 
 	const S32 HPAD = 2;
+	menu->arrangeAndClear(); // Fix menu rect if needed.
 	LLRect rect = menu->getRect();
 	//LLView* cur_view = spawning_view;
 	S32 left = x + HPAD;
@@ -3001,1461 +2496,956 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
 	menu->getParent()->sendChildToFront(menu);
 }
 
-//-----------------------------------------------------------------------------
-// class LLPieMenuBranch
-// A branch to another pie menu
-//-----------------------------------------------------------------------------
-class LLPieMenuBranch : public LLMenuItemGL
-{
-public:
-	LLPieMenuBranch(const std::string& name, const std::string& label, LLPieMenu* branch);
-
-	// called to rebuild the draw label
-	virtual void buildDrawLabel( void );
-
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void );
+///============================================================================
+/// Class LLMenuBarGL
+///============================================================================
 
-	LLPieMenu* getBranch() { return mBranch; }
+static LLRegisterWidget<LLMenuBarGL> r2("menu_bar");
 
-protected:
-	LLPieMenu* mBranch;
-};
+LLMenuBarGL::LLMenuBarGL( const Params& p )
+:	LLMenuGL(p),
+	mAltKeyTrigger(FALSE)
+{}
 
-LLPieMenuBranch::LLPieMenuBranch(const std::string& name,
-								 const std::string& label,
-								 LLPieMenu* branch) 
-:	LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ),
-	mBranch( branch )
+// Default destructor
+LLMenuBarGL::~LLMenuBarGL()
 {
-	mBranch->hide(FALSE);
-	mBranch->setParentMenuItem(this);
+	std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer());
+	mAccelerators.clear();
 }
 
-// called to rebuild the draw label
-void LLPieMenuBranch::buildDrawLabel( void )
+
+BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
 {
+	if (getHighlightedItem() && mask == MASK_NONE)
 	{
-		// default enablement is this -- if any of the subitems are
-		// enabled, this item is enabled. JC
-		U32 sub_count = mBranch->getItemCount();
-		U32 i;
-		BOOL any_enabled = FALSE;
-		for (i = 0; i < sub_count; i++)
-		{
-			LLMenuItemGL* item = mBranch->getItem(i);
-			item->buildDrawLabel();
-			if (item->getEnabled() && !item->getDrawTextDisabled() )
-			{
-				any_enabled = TRUE;
-				break;
-			}
-		}
-		setDrawTextDisabled(!any_enabled);
-		setEnabled(TRUE);
+		// unmodified key accelerators are ignored when navigating menu
+		// (but are used as jump keys so will still work when appropriate menu is up)
+		return FALSE;
+	}
+	BOOL result = LLMenuGL::handleAcceleratorKey(key, mask);
+	if (result && mask & MASK_ALT)
+	{
+		// ALT key used to trigger hotkey, don't use as shortcut to open menu
+		mAltKeyTrigger = FALSE;
 	}
 
-	mDrawAccelLabel.clear();
-	std::string st = mDrawAccelLabel;
-	appendAcceleratorString( st );
-	mDrawAccelLabel = st;
-	
-	// No special branch suffix
-	mDrawBranchLabel.clear();
-}
-
-// doIt() - do the primary funcationality of the menu item.
-void LLPieMenuBranch::doIt( void )
-{
-	LLPieMenu *parent = (LLPieMenu *)getParent();
-
-	LLRect rect = parent->getRect();
-	S32 center_x;
-	S32 center_y;
-	parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, &center_x, &center_y);
-
-	parent->hide(FALSE);
-	mBranch->show(	center_x, center_y, FALSE );
-}
-
-//-----------------------------------------------------------------------------
-// class LLPieMenu
-// A circular menu of items, icons, etc.
-//-----------------------------------------------------------------------------
-LLPieMenu::LLPieMenu(const std::string& name, const std::string& label)
-:	LLMenuGL(name, label),
-	mFirstMouseDown(FALSE),
-	mUseInfiniteRadius(FALSE),
-	mHoverItem(NULL),
-	mHoverThisFrame(FALSE),
-	mHoveredAnyItem(FALSE),
-	mOuterRingAlpha(1.f),
-	mCurRadius(0.f),
-	mRightMouseDown(FALSE)
-{ 
-	LLMenuGL::setVisible(FALSE);
-	setCanTearOff(FALSE);
-}
-
-LLPieMenu::LLPieMenu(const std::string& name)
-:	LLMenuGL(name, name),
-	mFirstMouseDown(FALSE),
-	mUseInfiniteRadius(FALSE),
-	mHoverItem(NULL),
-	mHoverThisFrame(FALSE),
-	mHoveredAnyItem(FALSE),
-	mOuterRingAlpha(1.f),
-	mCurRadius(0.f),
-	mRightMouseDown(FALSE)
-{ 
-	LLMenuGL::setVisible(FALSE);
-	setCanTearOff(FALSE);
-}
-
-
-void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory)
-{
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+	if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key))
 	{
-		if (child->hasName(LL_PIE_MENU_TAG))
+		if (getHighlightedItem())
 		{
-			// SUBMENU
-			std::string name("menu");
-			child->getAttributeString("name", name);
-			std::string label(name);
-			child->getAttributeString("label", label);
-
-			LLPieMenu *submenu = new LLPieMenu(name, label);
-			appendPieMenu(submenu);
-			submenu->initXML(child, context, factory);
+			clearHoverItem();
 		}
 		else
 		{
-			parseChildXML(child, context, factory);
+			// close menus originating from other menu bars when first opening menu via keyboard
+			LLMenuGL::sMenuContainer->hideMenus();
+			highlightNextItem(NULL);
+			LLMenuGL::setKeyboardMode(TRUE);
 		}
+		return TRUE;
 	}
-}
 
-// virtual
-void LLPieMenu::setVisible(BOOL visible)
-{
-	if (!visible)
-	{
-		hide(FALSE);
-	}
+	return result;
 }
 
-BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
+BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask)
 {
-	// This is mostly copied from the llview class, but it continues
-	// the hover handle code after a hover handler has been found.
-	BOOL handled = FALSE;
-
-	// If we got a hover event, we've already moved the cursor
-	// for any menu shifts, so subsequent mouseup messages will be in the
-	// correct position.  No need to correct them.
-	//mShiftHoriz = 0;
-	//mShiftVert = 0;
-
-	// release mouse capture after short period of visibility if we're using a finite boundary
-	// so that right click outside of boundary will trigger new pie menu
-	if (hasMouseCapture() && 
-		!mRightMouseDown && 
-		mShrinkBorderTimer.getStarted() && 
-		mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
-	{
-		gFocusMgr.setMouseCapture(NULL);
-		mUseInfiniteRadius = FALSE;
-	}
-
-	LLMenuItemGL *item = pieItemFromXY( x, y );
-
-	if (item && item->getEnabled())
+	static LLUICachedControl<bool> use_altkey_for_menus ("UseAltKeyForMenus", 0);
+	if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && use_altkey_for_menus)
 	{
-		getWindow()->setCursor(UI_CURSOR_ARROW);
-		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;		
-		handled = TRUE;
-
-		if (item != mHoverItem)
-		{
-			if (mHoverItem)
-			{
-				mHoverItem->setHighlight( FALSE );
-			}
-			mHoverItem = item;
-			mHoverItem->setHighlight( TRUE );
-
-			switch(pieItemIndexFromXY(x, y))
-			{
-			case 0:
-				make_ui_sound("UISndPieMenuSliceHighlight0");
-				break;
-			case 1:
-				make_ui_sound("UISndPieMenuSliceHighlight1");
-				break;
-			case 2:
-				make_ui_sound("UISndPieMenuSliceHighlight2");
-				break;
-			case 3:
-				make_ui_sound("UISndPieMenuSliceHighlight3");
-				break;
-			case 4:
-				make_ui_sound("UISndPieMenuSliceHighlight4");
-				break;
-			case 5:
-				make_ui_sound("UISndPieMenuSliceHighlight5");
-				break;
-			case 6:
-				make_ui_sound("UISndPieMenuSliceHighlight6");
-				break;
-			case 7:
-				make_ui_sound("UISndPieMenuSliceHighlight7");
-				break;
-			default:
-				make_ui_sound("UISndPieMenuSliceHighlight0");
-				break;
-			}
-		}
-		mHoveredAnyItem = TRUE;
+		mAltKeyTrigger = TRUE;
 	}
-	else
+	else // if any key other than ALT hit, clear out waiting for Alt key mode
 	{
-		// clear out our selection
-		if (mHoverItem)
-		{
-			mHoverItem->setHighlight(FALSE);
-			mHoverItem = NULL;
-		}
+		mAltKeyTrigger = FALSE;
 	}
-
-	if( !handled && pointInView( x, y ) )
+	
+	if (key == KEY_ESCAPE && mask == MASK_NONE)
 	{
-		getWindow()->setCursor(UI_CURSOR_ARROW);
-		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;		
-		handled = TRUE;
+		LLMenuGL::setKeyboardMode(FALSE);
+		// if any menus are visible, this will return TRUE, stopping further processing of ESCAPE key
+		return LLMenuGL::sMenuContainer->hideMenus();
 	}
 
-	mHoverThisFrame = TRUE;
+	// before processing any other key, check to see if ALT key has triggered menu access
+	checkMenuTrigger();
 
-	return handled;
+	return LLMenuGL::handleKeyHere(key, mask);
 }
 
-BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask )
+BOOL LLMenuBarGL::handleJumpKey(KEY key)
 {
-	BOOL handled = FALSE;
-	// The click was somewhere within our rectangle
-	LLMenuItemGL *item = pieItemFromXY( x, y );
-
-	if (item)
+	// perform case-insensitive comparison
+	key = toupper(key);
+	navigation_key_map_t::iterator found_it = mJumpKeys.find(key);
+	if(found_it != mJumpKeys.end() && found_it->second->getEnabled())
 	{
-		// lie to the item about where the click happened
-		// to make sure it's within the item's rectangle
-		handled = item->handleMouseDown( 0, 0, mask );
+		// switch to keyboard navigation mode
+		LLMenuGL::setKeyboardMode(TRUE);
+
+		found_it->second->setHighlight(TRUE);
+		found_it->second->onCommit();
 	}
-	else if (!mRightMouseDown)
+	return TRUE;
+}
+
+BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	// clicks on menu bar closes existing menus from other contexts but leave
+	// own menu open so that we get toggle behavior
+	if (!getHighlightedItem() || !getHighlightedItem()->isActive())
 	{
-		// call hidemenus to make sure transient selections get cleared
-		((LLMenuHolderGL*)getParent())->hideMenus();
+		LLMenuGL::sMenuContainer->hideMenus();
 	}
 
-	// always handle mouse down as mouse up will close open menus
-	return handled;
+	return LLMenuGL::handleMouseDown(x, y, mask);
 }
 
-BOOL LLPieMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
+BOOL LLMenuBarGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = FALSE;
-
-	mRightMouseDown = TRUE;
-
-	// The click was somewhere within our rectangle
-	LLMenuItemGL *item = pieItemFromXY( x, y );
-	S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
-	S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
-	BOOL clicked_in_pie = ((delta_x * delta_x) + (delta_y * delta_y) < mCurRadius*mCurRadius) || mUseInfiniteRadius;
-
-	// grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
-	if (clicked_in_pie)
-	{
-		// capture mouse cursor as if on initial menu show
-		gFocusMgr.setMouseCapture(this);
-		mShrinkBorderTimer.stop();
-		mUseInfiniteRadius = TRUE;
-		handled = TRUE;
-	}
-	
-	if (item)
+	// clicks on menu bar closes existing menus from other contexts but leave
+	// own menu open so that we get toggle behavior
+	if (!getHighlightedItem() || !getHighlightedItem()->isActive())
 	{
-		// lie to the item about where the click happened
-		// to make sure it's within the item's rectangle
-		if (item->handleMouseDown( 0, 0, mask ))
-		{
-			handled = TRUE;
-		}
+		LLMenuGL::sMenuContainer->hideMenus();
 	}
 
-	return handled;
+	return LLMenuGL::handleMouseDown(x, y, mask);
 }
 
-BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
+
+void LLMenuBarGL::draw()
 {
-	// release mouse capture when right mouse button released, and we're past the shrink time
-	if (mShrinkBorderTimer.getStarted() && 
-		mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME)
+	LLMenuItemGL* itemp = getHighlightedItem();
+	// If we are in mouse-control mode and the mouse cursor is not hovering over
+	// the current highlighted menu item and it isn't open, then remove the
+	// highlight. This is done via a polling mechanism here, as we don't receive
+    // notifications when the mouse cursor moves off of us
+	if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode())
 	{
-		mUseInfiniteRadius = FALSE;
-		gFocusMgr.setMouseCapture(NULL);
+		clearHoverItem();
 	}
 
-	S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
-	S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
-	if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE)
-	{
-		// user released right mouse button in middle of pie, interpret this as closing the menu
-		sMenuContainer->hideMenus();
-		return TRUE;
-	}
+	checkMenuTrigger();
 
+	LLMenuGL::draw();
+}
 
-	BOOL result = handleMouseUp( x, y, mask );
-	mRightMouseDown = FALSE;
-	mHoveredAnyItem = FALSE;
 
-	return result;
+void LLMenuBarGL::checkMenuTrigger()
+{
+	// has the ALT key been pressed and subsequently released?
+	if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT))
+	{
+		// if alt key was released quickly, treat it as a menu access key
+		// otherwise it was probably an Alt-zoom or similar action
+		static LLUICachedControl<F32> menu_access_key_time ("MenuAccessKeyTime", 0);
+		if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= menu_access_key_time ||
+			gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2)
+		{
+			if (getHighlightedItem())
+			{
+				clearHoverItem();
+			}
+			else
+			{
+				// close menus originating from other menu bars
+				LLMenuGL::sMenuContainer->hideMenus();
+
+				highlightNextItem(NULL);
+				LLMenuGL::setKeyboardMode(TRUE);
+			}
+		}
+		mAltKeyTrigger = FALSE;
+	}
 }
 
-BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask )
+BOOL LLMenuBarGL::jumpKeysActive()
 {
-	BOOL handled = FALSE;
-
-	// The click was somewhere within our rectangle
-	LLMenuItemGL *item = pieItemFromXY( x, y );
+	// require user to be in keyboard navigation mode to activate key triggers
+	// as menu bars are always visible and it is easy to leave the mouse cursor over them
+	return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive();
+}
 
-	if (item)
+// rearrange the child rects so they fit the shape of the menu bar.
+void LLMenuBarGL::arrange( void )
+{
+	U32 pos = 0;
+	LLRect rect( 0, getRect().getHeight(), 0, 0 );
+	item_list_t::const_iterator item_iter;
+	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
 	{
-		// lie to the item about where the click happened
-		// to make sure it's within the item's rectangle
-		if (item->getEnabled())
+		LLMenuItemGL* item = *item_iter;
+		if (item->getVisible())
 		{
-			handled = item->handleMouseUp( 0, 0, mask );
-			hide(TRUE);
+			rect.mLeft = pos;
+			pos += item->getNominalWidth();
+			rect.mRight = pos;
+			item->setRect( rect );
+			item->buildDrawLabel();
 		}
 	}
-	else if (!mRightMouseDown)
-	{
-		// call hidemenus to make sure transient selections get cleared
-		((LLMenuHolderGL*)getParent())->hideMenus();
-	}
+	reshape(rect.mRight, rect.getHeight());
+}
 
-	if (handled)
-	{
-		make_ui_sound("UISndClickRelease");
-	}
 
-	if (!handled && !mUseInfiniteRadius)
+S32 LLMenuBarGL::getRightmostMenuEdge()
+{
+	// Find the last visible menu
+	item_list_t::reverse_iterator item_iter;
+	for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter)
 	{
-		// call hidemenus to make sure transient selections get cleared
-		sMenuContainer->hideMenus();
+		if ((*item_iter)->getVisible())
+		{
+			break;
+		}
 	}
 
-	if (mFirstMouseDown)
-	{
-		make_ui_sound("UISndPieMenuAppear");
-		mFirstMouseDown = FALSE;
-	}
-	
-	// *FIX: is this necessary?
-	if (!mShrinkBorderTimer.getStarted())
+	if (item_iter == mItems.rend())
 	{
-		mShrinkBorderTimer.start();
+		return 0;
 	}
-
-	return handled;
+	return (*item_iter)->getRect().mRight;
 }
 
-
-// virtual
-void LLPieMenu::draw()
+// add a vertical separator to this menu
+BOOL LLMenuBarGL::addSeparator()
 {
-	// clear hover if mouse moved away
-	if (!mHoverThisFrame && mHoverItem)
-	{
-		mHoverItem->setHighlight(FALSE);
-		mHoverItem = NULL;
-	}
-
-	F32 width = (F32) getRect().getWidth();
-	F32 height = (F32) getRect().getHeight();
-	mCurRadius = PIE_SCALE_FACTOR * llmax( width/2, height/2 );
+	LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL();
+	return append( separator );
+}
 
-	mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f;
-	if (mShrinkBorderTimer.getStarted())
+// add a menu - this will create a drop down menu.
+BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu )
+{
+	if( menu == this )
 	{
-		mOuterRingAlpha = clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 0.f, 1.f);
-		mCurRadius *= clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR);
+		llerrs << "** Attempt to attach menu to itself. This is certainly "
+			   << "a logic error." << llendl;
 	}
 
-	// correct for non-square pixels
-	F32 center_x = width/2;
-	F32 center_y = height/2;
-	S32 steps = 100;
+	BOOL success = TRUE;
 
-	gGL.pushMatrix();
-	{
-		gGL.translatef(center_x, center_y, 0.f);
+	// *TODO: Hack! Fix this
+	LLMenuItemBranchDownGL::Params p;
+	p.name = menu->getName();
+	p.label = menu->getLabel();
+	p.visible = menu->getVisible();
+	p.branch = menu;
+	p.enabled_color=LLUI::getCachedColorFunctor("MenuItemEnabledColor");
+	p.disabled_color=LLUI::getCachedColorFunctor("MenuItemDisabledColor");
+	p.highlight_bg_color=LLUI::getCachedColorFunctor("MenuItemHighlightBgColor");
+	p.highlight_fg_color=LLUI::getCachedColorFunctor("MenuItemHighlightFgColor");
+
+	LLMenuItemBranchDownGL* branch = LLUICtrlFactory::create<LLMenuItemBranchDownGL>(p);
+	success &= branch->addToAcceleratorList(&mAccelerators);
+	success &= append( branch );
+	branch->setJumpKey(branch->getJumpKey());
+	menu->updateParent(LLMenuGL::sMenuContainer);
+	
+	return success;
+}
 
-		F32 line_width = LLUI::sConfigGroup->getF32("PieMenuLineWidth");
-		LLColor4 line_color = LLUI::sColorsGroup->getColor("PieMenuLineColor");
-		LLColor4 bg_color = LLUI::sColorsGroup->getColor("PieMenuBgColor");
-		LLColor4 selected_color = LLUI::sColorsGroup->getColor("PieMenuSelectedColor");
+BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
+{
+	BOOL handled = FALSE;
+	LLView* active_menu = NULL;
 
-		// main body
-		LLColor4 outer_color = bg_color;
-		outer_color.mV[VALPHA] *= mOuterRingAlpha;
-		gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color );
+	BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0;
+	S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX;
+	S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY;
+	mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2);
+	mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2);
+	mLastMouseX = x;
+	mLastMouseY = y;
 
-		// selected wedge
-		item_list_t::iterator item_iter;
-		S32 i = 0;
-		for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
-		{
-			if ((*item_iter)->getHighlight())
-			{
-				F32 arc_size = F_PI * 0.25f;
-
-				F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
-				F32 end_radians = start_radians + arc_size;
-
-				LLColor4 outer_color = selected_color;
-				outer_color.mV[VALPHA] *= mOuterRingAlpha;
-				gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
+	// if nothing currently selected or mouse has moved since last call, pick menu item via mouse
+	// otherwise let keyboard control it
+	if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0)
+	{
+		// find current active menu
+		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+		{
+			LLView* viewp = *child_it;
+			if (((LLMenuItemGL*)viewp)->isOpen())
+			{
+				active_menu = viewp;
 			}
-			i++;
 		}
 
-		LLUI::setLineWidth( line_width );
-
-		// inner lines
-		outer_color = line_color;
-		outer_color.mV[VALPHA] *= mOuterRingAlpha;
-		gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color );
-
-		// inner circle
-		gGL.color4fv( line_color.mV );
-		gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE );
-
-		// outer circle
-		gGL.color4fv( outer_color.mV );
-		gl_circle_2d( 0, 0, mCurRadius, steps, FALSE );
-
-		LLUI::setLineWidth(1.0f);
-	}
-	gGL.popMatrix();
-
-	mHoverThisFrame = FALSE;
-
-	LLView::draw();
-}
-
-void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
-{
-	F32 width = (F32) getRect().getWidth();
-	F32 height = (F32) getRect().getHeight();
-	F32 center_x = width/2;
-	F32 center_y = height/2;
-	S32 steps = 100;
-
-	gGL.color4fv( color.mV );
-	gGL.pushMatrix();
-	{
-		gGL.translatef(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
-
-		item_list_t::iterator item_iter;
-		S32 i = 0;
-		for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+		// check for new active menu
+		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 		{
-			if ((*item_iter) == itemp)
+			LLView* viewp = *child_it;
+			S32 local_x = x - viewp->getRect().mLeft;
+			S32 local_y = y - viewp->getRect().mBottom;
+			if( viewp->getVisible() && 
+				viewp->getEnabled() &&
+				viewp->pointInView(local_x, local_y) && 
+				viewp->handleHover(local_x, local_y, mask))
 			{
-				F32 arc_size = F_PI * 0.25f;
-
-				F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
-				F32 end_radians = start_radians + arc_size;
+				((LLMenuItemGL*)viewp)->setHighlight(TRUE);
+				handled = TRUE;
+				if (active_menu && active_menu != viewp)
+				{
+					((LLMenuItemGL*)viewp)->onCommit();
+					LLMenuGL::setKeyboardMode(FALSE);
+				}
+				LLMenuGL::setKeyboardMode(FALSE);
+			}
+		}
 
-				LLColor4 outer_color = color;
-				outer_color.mV[VALPHA] *= mOuterRingAlpha;
-				gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color );
+		if (handled)
+		{
+			// set hover false on inactive menus
+			for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+			{
+				LLView* viewp = *child_it;
+				S32 local_x = x - viewp->getRect().mLeft;
+				S32 local_y = y - viewp->getRect().mBottom;
+				if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight())
+				{
+					((LLMenuItemGL*)viewp)->setHighlight(FALSE);
+				}
 			}
-			i++;
 		}
 	}
-	gGL.popMatrix();
-}
 
-// virtual
-BOOL LLPieMenu::append(LLMenuItemGL *item)
-{
-	item->setBriefItem(TRUE);
-	item->setFont( LLFontGL::getFontSansSerifSmall() );
-	return LLMenuGL::append(item);
+	getWindow()->setCursor(UI_CURSOR_ARROW);
+	
+	return TRUE;
 }
 
-// virtual
-BOOL LLPieMenu::appendSeparator(const std::string &separator_name)
+///============================================================================
+/// Class LLMenuHolderGL
+///============================================================================
+LLMenuHolderGL::LLMenuHolderGL()
+	: LLPanel()
 {
-	LLMenuItemGL* separator = new LLMenuItemBlankGL();
-	separator->setFont( LLFontGL::getFontSansSerifSmall() );
-	return append( separator );
+	setName("Menu Holder");
+	setMouseOpaque(FALSE);
+	sItemActivationTimer.stop();
+	mCanHide = TRUE;
 }
 
-
-BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
+void LLMenuHolderGL::draw()
 {
-	if (menu == this)
+	LLView::draw();
+	// now draw last selected item as overlay
+	LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get();
+	if (selecteditem && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME)
 	{
-		llerrs << "Can't attach a pie menu to itself" << llendl;
+		// make sure toggle items, for example, show the proper state when fading out
+		selecteditem->buildDrawLabel();
+
+		LLRect item_rect;
+		selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this);
+
+		F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME;
+		
+		LLUI::pushMatrix();
+		{
+			LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f);
+			selecteditem->getMenu()->drawBackground(selecteditem, interpolant);
+			selecteditem->draw();
+		}
+		LLUI::popMatrix();
 	}
-	LLPieMenuBranch *item;
-	item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu);
-	getParent()->addChild(item->getBranch());
-	item->setFont( LLFontGL::getFontSansSerifSmall() );
-	return append( item );
 }
 
-// virtual
-void LLPieMenu::arrange()
+BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask )
 {
-	const S32 rect_height = 190;
-	const S32 rect_width = 190;
-
-	// all divide by 6
-	const S32 CARD_X = 60;
-	const S32 DIAG_X = 48;
-	const S32 CARD_Y = 76;
-	const S32 DIAG_Y = 42;
-
-	const S32 ITEM_CENTER_X[] = { CARD_X, DIAG_X,      0, -DIAG_X, -CARD_X, -DIAG_X,       0,  DIAG_X };
-	const S32 ITEM_CENTER_Y[] = {      0, DIAG_Y, CARD_Y,  DIAG_Y,       0, -DIAG_Y, -CARD_Y, -DIAG_Y };
-
-	LLRect rect;
-	
-	S32 font_height = 0;
-	if( mItems.size() )
+	BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+	if (!handled)
 	{
-		font_height = (*mItems.begin())->getNominalHeight();
+		// clicked off of menu, hide them all
+		hideMenus();
 	}
-	S32 item_width = 0;
-
-//	F32 sin_delta = OO_SQRT2;	// sin(45 deg)
-//	F32 cos_delta = OO_SQRT2;	// cos(45 deg)
-
-	// TODO: Compute actual bounding rect for menu
-
-	// HACK: casting away const.  Should use setRect or some helper function instead.
-	const_cast<LLRect&>(getRect()).setOriginAndSize(getRect().mLeft, getRect().mBottom, rect_width, rect_height );
+	return handled;
+}
 
-	// place items around a circle, with item 0 at positive X,
-	// rotating counter-clockwise
-	item_list_t::iterator item_iter;
-	S32 i = 0;
-	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask )
+{
+	BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL;
+	if (!handled)
 	{
-		LLMenuItemGL *item = *item_iter;
-
-		item_width = item->getNominalWidth();
-
-		// Put in the right place around a circle centered at 0,0
-		rect.setCenterAndSize(ITEM_CENTER_X[i],
-							  ITEM_CENTER_Y[i], 
-							  item_width, font_height );
-
-		// Correct for the actual rectangle size
-		rect.translate( rect_width/2, rect_height/2 );
-
-		item->setRect( rect );
-
-		// Make sure enablement is correct
-		item->buildDrawLabel();
-		i++;
+		// clicked off of menu, hide them all
+		hideMenus();
 	}
+	return handled;
 }
 
-LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
+void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
-	// We might have shifted this menu on draw.  If so, we need
-	// to shift over mouseup events until we get a hover event.
-	//x += mShiftHoriz;
-	//y += mShiftVert; 
-
-	// An arc of the pie menu is 45 degrees
-	const F32 ARC_DEG = 45.f;
-	S32 delta_x = x - getRect().getWidth() / 2;
-	S32 delta_y = y - getRect().getHeight() / 2;
-
-	// circle safe zone in the center
-	S32 dist_squared = delta_x*delta_x + delta_y*delta_y;
-	if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
+	if (width != getRect().getWidth() || height != getRect().getHeight())
 	{
-		return NULL;
+		hideMenus();
 	}
+	LLView::reshape(width, height, called_from_parent);
+}
 
-	// infinite radius is only used with right clicks
-	S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 );
-	if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius)
+BOOL LLMenuHolderGL::hasVisibleMenu() const
+{
+	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 	{
-		return NULL;
+		LLView* viewp = *child_it;
+		if (viewp->getVisible() && dynamic_cast<LLMenuBarGL*>(viewp) == NULL)
+		{
+			return TRUE;
+		}
 	}
+	return FALSE;
+}
 
-	F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
-	
-	// rotate marks CCW so that east = [0, ARC_DEG) instead of
-	// [-ARC_DEG/2, ARC_DEG/2)
-	angle += ARC_DEG / 2.f;
-
-	// make sure we're only using positive angles
-	if (angle < 0.f) angle += 360.f;
-
-	S32 which = S32( angle / ARC_DEG );
 
-	if (0 <= which && which < (S32)mItems.size() )
+BOOL LLMenuHolderGL::hideMenus()
+{
+	if (!mCanHide)
 	{
-		item_list_t::iterator item_iter;
-		for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
+		return FALSE;
+	}
+	BOOL menu_visible = hasVisibleMenu();
+	if (menu_visible)
+	{
+		LLMenuGL::setKeyboardMode(FALSE);
+		// clicked off of menu, hide them all
+		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 		{
-			if (which == 0)
+			LLView* viewp = *child_it;
+			// clicks off of menu do not hide menu bar
+			if (dynamic_cast<LLMenuBarGL*>(viewp) == NULL && viewp->getVisible())
 			{
-				return (*item_iter);
+				viewp->setVisible(FALSE);
 			}
-			which--;
 		}
 	}
+	//if (gFocusMgr.childHasKeyboardFocus(this))
+	//{
+	//	gFocusMgr.setKeyboardFocus(NULL);
+	//}
 
-	return NULL;
+	return menu_visible;
 }
 
-S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
+void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
 {
-	// An arc of the pie menu is 45 degrees
-	const F32 ARC_DEG = 45.f;
-	// correct for non-square pixels
-	S32 delta_x = x - getRect().getWidth() / 2;
-	S32 delta_y = y - getRect().getHeight() / 2;
-
-	// circle safe zone in the center
-	if (delta_x*delta_x + delta_y*delta_y < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
-	{
-		return -1;
-	}
-
-	F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
-	
-	// rotate marks CCW so that east = [0, ARC_DEG) instead of
-	// [-ARC_DEG/2, ARC_DEG/2)
-	angle += ARC_DEG / 2.f;
-
-	// make sure we're only using positive angles
-	if (angle < 0.f) angle += 360.f;
-
-	S32 which = S32( angle / ARC_DEG );
-	return which;
+	sItemLastSelectedHandle = item->getHandle();
+	sItemActivationTimer.start();
 }
 
-void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
+///============================================================================
+/// Class LLTearOffMenu
+///============================================================================
+LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : 
+	LLFloater()
 {
-	S32 width = getRect().getWidth();
-	S32 height = getRect().getHeight();
-
-	const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
-
-	LLView* parent_view = getParent();
-	BOOL moved = FALSE;
-
-	S32 local_x, local_y;
-	parent_view->screenPointToLocal(x, y, &local_x, &local_y);
-
-	// HACK: casting away const.  Should use setRect or some helper function instead.
-	const_cast<LLRect&>(getRect()).setCenterAndSize(local_x, local_y, width, height);
-	arrange();
-
-	// Adjust the pie rectangle to keep it on screen
-	if (getRect().mLeft < menu_region_rect.mLeft) 
-	{
-		//mShiftHoriz = menu_region_rect.mLeft - getRect().mLeft;
-		//getRect().translate( mShiftHoriz, 0 );
-		// HACK: casting away const.  Should use setRect or some helper function instead.
-		const_cast<LLRect&>(getRect()).translate( menu_region_rect.mLeft - getRect().mLeft, 0 );
-		moved = TRUE;
-	}
-
-	if (getRect().mRight > menu_region_rect.mRight) 
-	{
-		//mShiftHoriz = menu_region_rect.mRight - getRect().mRight;
-		//getRect().translate( mShiftHoriz, 0);
-		// HACK: casting away const.  Should use setRect or some helper function instead.
-		const_cast<LLRect&>(getRect()).translate( menu_region_rect.mRight - getRect().mRight, 0 );
-		moved = TRUE;
-	}
-
-	if (getRect().mBottom < menu_region_rect.mBottom)
-	{
-		//mShiftVert = menu_region_rect.mBottom - getRect().mBottom;
-		//getRect().translate( 0, mShiftVert );
-		// HACK: casting away const.  Should use setRect or some helper function instead.
-		const_cast<LLRect&>(getRect()).translate( 0, menu_region_rect.mBottom - getRect().mBottom );
-		moved = TRUE;
-	}
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
 
+	setName(menup->getName());
+	setTitle(menup->getLabel());
+	setCanMinimize(FALSE);
+	// flag menu as being torn off
+	menup->setTornOff(TRUE);
+	// update menu layout as torn off menu (no spillover menus)
+	menup->needsArrange();
 
-	if (getRect().mTop > menu_region_rect.mTop)
-	{
-		//mShiftVert = menu_region_rect.mTop - getRect().mTop;
-		//getRect().translate( 0, mShiftVert );
-		// HACK: casting away const. Should use setRect or some helper function instead.
-		const_cast<LLRect&>(getRect()).translate( 0, menu_region_rect.mTop - getRect().mTop );
-		moved = TRUE;
-	}
-
-	// If we had to relocate the pie menu, put the cursor in the
-	// center of its rectangle
-	if (moved)
-	{
-		LLCoordGL center;
-		center.mX = (getRect().mLeft + getRect().mRight) / 2;
-		center.mY = (getRect().mTop + getRect().mBottom) / 2;
+	LLRect rect;
+	menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView);
+	// make sure this floater is big enough for menu
+	mTargetHeight = (F32)(rect.getHeight() + floater_header_size + 5);
+	reshape(rect.getWidth(), rect.getHeight());
+	setRect(rect);
 
-		LLUI::setCursorPositionLocal(getParent(), center.mX, center.mY);
-	}
+	// attach menu to floater
+	menup->setFollowsAll();
+	mOldParent = menup->getParent();
+	addChild(menup);
+	menup->setVisible(TRUE);
+	menup->translate(-menup->getRect().mLeft + 1, -menup->getRect().mBottom + 1);
+	menup->setDropShadowed(FALSE);
 
-	// *FIX: what happens when mouse buttons reversed?
-	mRightMouseDown = mouse_down;
-	mFirstMouseDown = mouse_down;
-	mUseInfiniteRadius = TRUE;
-	mHoveredAnyItem = FALSE;
+	mMenu = menup;
 
-	if (!mFirstMouseDown)
-	{
-		make_ui_sound("UISndPieMenuAppear");
-	}
+	// highlight first item (tear off item will be disabled)
+	mMenu->highlightNextItem(NULL);
+}
 
-	LLView::setVisible(TRUE);
 
-	// we want all mouse events in case user does quick right click again off of pie menu
-	// rectangle, to support gestural menu traversal
-	gFocusMgr.setMouseCapture(this);
+void LLTearOffMenu::draw()
+{
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	mMenu->setBackgroundVisible(isBackgroundOpaque());
+	mMenu->needsArrange();
 
-	if (mouse_down)
+	if (getRect().getHeight() != mTargetHeight)
 	{
-		mShrinkBorderTimer.stop();
+		// animate towards target height
+		reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), mTargetHeight, LLCriticalDamp::getInterpolant(0.05f))));
 	}
-	else 
+	else
 	{
-		mShrinkBorderTimer.start();
+		// when in stasis, remain big enough to hold menu contents
+		mTargetHeight = (F32)(mMenu->getRect().getHeight() + floater_header_size + 4);
+		reshape(mMenu->getRect().getWidth() + 3, mMenu->getRect().getHeight() + floater_header_size + 5);
 	}
+	LLFloater::draw();
 }
 
-void LLPieMenu::hide(BOOL item_selected)
+void LLTearOffMenu::onFocusReceived()
 {
-	if (!getVisible()) return;
-
-	if (mHoverItem)
+	// if nothing is highlighted, just highlight first item
+	if (!mMenu->getHighlightedItem())
 	{
-		mHoverItem->setHighlight( FALSE );
-		mHoverItem = NULL;
+		mMenu->highlightNextItem(NULL);
 	}
 
-	make_ui_sound("UISndPieMenuHide");
-
-	mFirstMouseDown = FALSE;
-	mRightMouseDown = FALSE;
-	mUseInfiniteRadius = FALSE;
-	mHoveredAnyItem = FALSE;
-
-	LLView::setVisible(FALSE);
-
-	gFocusMgr.setMouseCapture(NULL);
-}
-
-///============================================================================
-/// Class LLMenuBarGL
-///============================================================================
-
-static LLRegisterWidget<LLMenuBarGL> r2("menu_bar");
-
-// Default constructor
-LLMenuBarGL::LLMenuBarGL( const std::string& name ) : LLMenuGL ( name, name )
-{
-	mHorizontalLayout = TRUE;
-	setCanTearOff(FALSE);
-	mKeepFixedSize = TRUE;
-	mAltKeyTrigger = FALSE;
-}
-
-// Default destructor
-LLMenuBarGL::~LLMenuBarGL()
-{
-	std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer());
-	mAccelerators.clear();
-}
-
-// virtual
-LLXMLNodePtr LLMenuBarGL::getXML(bool save_children) const
-{
-	// Sorty of hacky: reparent items to this and then back at the end of the export
-	LLView *orig_parent = NULL;
-	item_list_t::const_iterator item_iter;
-	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
-	{
-		LLMenuItemGL* child = *item_iter;
-		LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child;
-		LLMenuGL *menu = branch->getBranch();
-		orig_parent = menu->getParent();
-		menu->updateParent((LLView *)this);
-	}
-
-	LLXMLNodePtr node = LLMenuGL::getXML();
-
-	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
-	{
-		LLMenuItemGL* child = *item_iter;
-		LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child;
-		LLMenuGL *menu = branch->getBranch();
-		menu->updateParent(orig_parent);
-	}
-
-	return node;
-}
-
-LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("menu");
-	node->getAttributeString("name", name);
-
-	BOOL opaque = FALSE;
-	node->getAttributeBOOL("opaque", opaque);
-
-	LLMenuBarGL *menubar = new LLMenuBarGL(name);
-
-	LLHandle<LLFloater> parent_handle;
-	LLFloater* parent_floater = dynamic_cast<LLFloater*>(parent);
-	if (parent_floater)
-	{
-		parent_handle = parent_floater->getHandle();
-	}
-
-	// We need to have the rect early so that it's around when building
-	// the menu items
-	LLRect view_rect;
-	createRect(node, view_rect, parent, menubar->getRequiredRect());
-	menubar->setRect(view_rect);
-
-	if (node->hasAttribute("drop_shadow"))
-	{
-		BOOL drop_shadow = FALSE;
-		node->getAttributeBOOL("drop_shadow", drop_shadow);
-		menubar->setDropShadowed(drop_shadow);
-	}
-
-	menubar->setBackgroundVisible(opaque);
-	LLColor4 color(0,0,0,0);
-	if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
-	{
-		menubar->setBackgroundColor(color);
-	}
-
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+	// parent menu items get highlights so navigation logic keeps working
+	LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem();
+	while(parent_menu_item)
 	{
-		if (child->hasName("menu"))
+		if (parent_menu_item->getMenu()->getVisible())
 		{
-			LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory);
-			// because of lazy initialization, have to disable tear off functionality
-			// and then re-enable with proper parent handle
-			if (menu->getCanTearOff())
-			{
-				menu->setCanTearOff(FALSE);
-				menu->setCanTearOff(TRUE, parent_handle);
-			}
-			menubar->appendMenu(menu);
-			if (LLMenuGL::sMenuContainer != NULL)
-			{
-				menu->updateParent(LLMenuGL::sMenuContainer);
-			}
-			else
-			{
-				menu->updateParent(parent);
-			}
+			parent_menu_item->setHighlight(TRUE);
+			parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem();
+		}
+		else
+		{
+			break;
 		}
 	}
+	LLFloater::onFocusReceived();
+}
 
-	menubar->initFromXML(node, parent);
-
-	BOOL create_jump_keys = FALSE;
-	node->getAttributeBOOL("create_jump_keys", create_jump_keys);
-	if (create_jump_keys)
-	{
-		menubar->createJumpKeys();
-	}
-
-	return menubar;
+void LLTearOffMenu::onFocusLost()
+{
+	// remove highlight from parent item and our own menu
+	mMenu->clearHoverItem();
+	LLFloater::onFocusLost();
 }
 
-BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
+BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
-	if (getHighlightedItem() && mask == MASK_NONE)
-	{
-		// unmodified key accelerators are ignored when navigating menu
-		// (but are used as jump keys so will still work when appropriate menu is up)
-		return FALSE;
-	}
-	BOOL result = LLMenuGL::handleAcceleratorKey(key, mask);
-	if (result && mask & MASK_ALT)
-	{
-		// ALT key used to trigger hotkey, don't use as shortcut to open menu
-		mAltKeyTrigger = FALSE;
-	}
+	// pass keystrokes down to menu
+	return mMenu->handleUnicodeChar(uni_char, TRUE);
+}
 
-	if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key))
+BOOL LLTearOffMenu::handleKeyHere(KEY key, MASK mask)
+{
+	if (!mMenu->getHighlightedItem())
 	{
-		if (getHighlightedItem())
+		if (key == KEY_UP)
 		{
-			clearHoverItem();
+			mMenu->highlightPrevItem(NULL);		
+			return TRUE;
 		}
-		else
+		else if (key == KEY_DOWN)
 		{
-			// close menus originating from other menu bars when first opening menu via keyboard
-			LLMenuGL::sMenuContainer->hideMenus();
-			highlightNextItem(NULL);
-			LLMenuGL::setKeyboardMode(TRUE);
+			mMenu->highlightNextItem(NULL);
+			return TRUE;
 		}
-		return TRUE;
 	}
-
-	return result;
+	// pass keystrokes down to menu
+	return mMenu->handleKey(key, mask, TRUE);
 }
 
-BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask)
+void LLTearOffMenu::translate(S32 x, S32 y)
 {
-	if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && LLUI::sConfigGroup->getBOOL("UseAltKeyForMenus"))
-	{
-		mAltKeyTrigger = TRUE;
-	}
-	else // if any key other than ALT hit, clear out waiting for Alt key mode
-	{
-		mAltKeyTrigger = FALSE;
-	}
-	
-	if (key == KEY_ESCAPE && mask == MASK_NONE)
+	if (x != 0 && y != 0)
 	{
-		LLMenuGL::setKeyboardMode(FALSE);
-		// if any menus are visible, this will return TRUE, stopping further processing of ESCAPE key
-		return LLMenuGL::sMenuContainer->hideMenus();
+		// hide open sub-menus by clearing current hover item
+		mMenu->clearHoverItem();
 	}
-
-	// before processing any other key, check to see if ALT key has triggered menu access
-	checkMenuTrigger();
-
-	return LLMenuGL::handleKeyHere(key, mask);
+	LLFloater::translate(x, y);
 }
 
-BOOL LLMenuBarGL::handleJumpKey(KEY key)
+//static
+LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
 {
-	// perform case-insensitive comparison
-	key = toupper(key);
-	navigation_key_map_t::iterator found_it = mJumpKeys.find(key);
-	if(found_it != mJumpKeys.end() && found_it->second->getEnabled())
-	{
-		// switch to keyboard navigation mode
-		LLMenuGL::setKeyboardMode(TRUE);
+	LLTearOffMenu* tearoffp = new LLTearOffMenu(menup);
+	// keep onscreen
+	gFloaterView->adjustToFitScreen(tearoffp, FALSE);
+	tearoffp->openFloater(LLSD());
 
-		found_it->second->setHighlight(TRUE);
-		found_it->second->doIt();
-	}
-	return TRUE;
+	return tearoffp;
 }
 
-BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask)
+void LLTearOffMenu::onClose(bool app_quitting)
 {
-	// clicks on menu bar closes existing menus from other contexts but leave
-	// own menu open so that we get toggle behavior
-	if (!getHighlightedItem() || !getHighlightedItem()->isActive())
-	{
-		LLMenuGL::sMenuContainer->hideMenus();
-	}
-
-	return LLMenuGL::handleMouseDown(x, y, mask);
+	removeChild(mMenu);
+	mOldParent->addChild(mMenu);
+	mMenu->clearHoverItem();
+	mMenu->setFollowsNone();
+	mMenu->setBackgroundVisible(TRUE);
+	mMenu->setVisible(FALSE);
+	mMenu->setTornOff(FALSE);
+	mMenu->setDropShadowed(TRUE);
+	destroy();
 }
 
-BOOL LLMenuBarGL::handleRightMouseDown(S32 x, S32 y, MASK mask)
+
+//-----------------------------------------------------------------------------
+// class LLContextMenuBranch
+// A branch to another context menu
+//-----------------------------------------------------------------------------
+class LLContextMenuBranch : public LLMenuItemGL
 {
-	// clicks on menu bar closes existing menus from other contexts but leave
-	// own menu open so that we get toggle behavior
-	if (!getHighlightedItem() || !getHighlightedItem()->isActive())
+public:
+	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
 	{
-		LLMenuGL::sMenuContainer->hideMenus();
-	}
-
-	return LLMenuGL::handleMouseDown(x, y, mask);
-}
+		Mandatory<LLContextMenu*> branch;
+	};
 
+	LLContextMenuBranch(const Params&);
 
-void LLMenuBarGL::draw()
-{
-	LLMenuItemGL* itemp = getHighlightedItem();
-	// If we are in mouse-control mode and the mouse cursor is not hovering over
-	// the current highlighted menu item and it isn't open, then remove the
-	// highlight. This is done via a polling mechanism here, as we don't receive
-    // notifications when the mouse cursor moves off of us
-	if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode())
-	{
-		clearHoverItem();
-	}
+	// called to rebuild the draw label
+	virtual void	buildDrawLabel( void );
 
-	checkMenuTrigger();
+	// onCommit() - do the primary funcationality of the menu item.
+	virtual void	onCommit( void );
 
-	LLMenuGL::draw();
-}
+	LLContextMenu*	getBranch() { return mBranch; }
+	void			setHighlight( BOOL highlight );
 
-void LLMenuBarGL::checkMenuTrigger()
-{
-	// has the ALT key been pressed and subsequently released?
-	if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT))
-	{
-		// if alt key was released quickly, treat it as a menu access key
-		// otherwise it was probably an Alt-zoom or similar action
-		if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= LLUI::sConfigGroup->getF32("MenuAccessKeyTime") ||
-			gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2)
-		{
-			if (getHighlightedItem())
-			{
-				clearHoverItem();
-			}
-			else
-			{
-				// close menus originating from other menu bars
-				LLMenuGL::sMenuContainer->hideMenus();
+protected:
+	void	showSubMenu();
 
-				highlightNextItem(NULL);
-				LLMenuGL::setKeyboardMode(TRUE);
-			}
-		}
-		mAltKeyTrigger = FALSE;
-	}
-}
+	LLContextMenu* mBranch;
+};
 
-BOOL LLMenuBarGL::jumpKeysActive()
+LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p) 
+:	LLMenuItemGL(p),
+	mBranch( p.branch )
 {
-	// require user to be in keyboard navigation mode to activate key triggers
-	// as menu bars are always visible and it is easy to leave the mouse cursor over them
-	return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive();
+	mBranch->hide();
+	mBranch->setParentMenuItem(this);
 }
 
-// rearrange the child rects so they fit the shape of the menu bar.
-void LLMenuBarGL::arrange( void )
+// called to rebuild the draw label
+void LLContextMenuBranch::buildDrawLabel( void )
 {
-	U32 pos = 0;
-	LLRect rect( 0, getRect().getHeight(), 0, 0 );
-	item_list_t::const_iterator item_iter;
-	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
 	{
-		LLMenuItemGL* item = *item_iter;
-		if (item->getVisible())
+		// default enablement is this -- if any of the subitems are
+		// enabled, this item is enabled. JC
+		U32 sub_count = mBranch->getItemCount();
+		U32 i;
+		BOOL any_enabled = FALSE;
+		for (i = 0; i < sub_count; i++)
 		{
-			rect.mLeft = pos;
-			pos += item->getNominalWidth();
-			rect.mRight = pos;
-			item->setRect( rect );
+			LLMenuItemGL* item = mBranch->getItem(i);
 			item->buildDrawLabel();
+			if (item->getEnabled() && !item->getDrawTextDisabled() )
+			{
+				any_enabled = TRUE;
+				break;
+			}
 		}
-	}
-	reshape(rect.mRight, rect.getHeight());
-}
-
-
-S32 LLMenuBarGL::getRightmostMenuEdge()
-{
-	// Find the last visible menu
-	item_list_t::reverse_iterator item_iter;
-	for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter)
-	{
-		if ((*item_iter)->getVisible())
-		{
-			break;
-		}
+		setDrawTextDisabled(!any_enabled);
+		setEnabled(TRUE);
 	}
 
-	if (item_iter == mItems.rend())
-	{
-		return 0;
-	}
-	return (*item_iter)->getRect().mRight;
+	mDrawAccelLabel.clear();
+	std::string st = mDrawAccelLabel;
+	appendAcceleratorString( st );
+	mDrawAccelLabel = st;
+	
+	// No special branch suffix
+	mDrawBranchLabel.clear();
 }
 
-// add a vertical separator to this menu
-BOOL LLMenuBarGL::appendSeparator( const std::string &separator_name )
+void	LLContextMenuBranch::showSubMenu()
 {
-	LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL();
-	return append( separator );
+	S32 center_x;
+	S32 center_y;
+	localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
+	mBranch->show(	center_x, center_y, FALSE);
 }
 
-// add a menu - this will create a drop down menu.
-BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu )
+// onCommit() - do the primary funcationality of the menu item.
+void LLContextMenuBranch::onCommit( void )
 {
-	if( menu == this )
-	{
-		llerrs << "** Attempt to attach menu to itself. This is certainly "
-			   << "a logic error." << llendl;
-	}
-
-	BOOL success = TRUE;
+	showSubMenu();
 
-	LLMenuItemBranchGL* branch = NULL;
-	branch = new LLMenuItemBranchDownGL( menu->getName(), menu->getLabel(), menu->getHandle());
-	success &= branch->addToAcceleratorList(&mAccelerators);
-	success &= append( branch );
-	branch->setJumpKey(branch->getJumpKey());
-	return success;
 }
-
-BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
+void LLContextMenuBranch::setHighlight( BOOL highlight )
 {
-	BOOL handled = FALSE;
-	LLView* active_menu = NULL;
-
-	BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0;
-	S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX;
-	S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY;
-	mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2);
-	mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2);
-	mLastMouseX = x;
-	mLastMouseY = y;
-
-	// if nothing currently selected or mouse has moved since last call, pick menu item via mouse
-	// otherwise let keyboard control it
-	if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0)
+	if (highlight == getHighlight()) return;
+	LLMenuItemGL::setHighlight(highlight);
+	if( highlight )
 	{
-		// find current active menu
-		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			if (((LLMenuItemGL*)viewp)->isOpen())
-			{
-				active_menu = viewp;
-			}
-		}
+		showSubMenu();
+	}
+	else
+	{
+		mBranch->hide();
+	}
+}
 
-		// check for new active menu
-		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
-		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if( viewp->getVisible() && 
-				viewp->getEnabled() &&
-				viewp->pointInView(local_x, local_y) && 
-				viewp->handleHover(local_x, local_y, mask))
-			{
-				((LLMenuItemGL*)viewp)->setHighlight(TRUE);
-				handled = TRUE;
-				if (active_menu && active_menu != viewp)
-				{
-					((LLMenuItemGL*)viewp)->doIt();
-					LLMenuGL::setKeyboardMode(FALSE);
-				}
-				LLMenuGL::setKeyboardMode(FALSE);
-			}
-		}
 
-		if (handled)
-		{
-			// set hover false on inactive menus
-			for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
-			{
-				LLView* viewp = *child_it;
-				S32 local_x = x - viewp->getRect().mLeft;
-				S32 local_y = y - viewp->getRect().mBottom;
-				if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight())
-				{
-					((LLMenuItemGL*)viewp)->setHighlight(FALSE);
-				}
-			}
-		}
-	}
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//-----------------------------------------------------------------------------
+// class LLContextMenu
+// A context menu
+//-----------------------------------------------------------------------------
+static LLRegisterWidget<LLContextMenu> context_menu_register("context_menu");
 
-	getWindow()->setCursor(UI_CURSOR_ARROW);
-	
-	return TRUE;
-}
+LLContextMenu::LLContextMenu(const Params& p)
+:	LLMenuGL(p),
+	mHoveredAnyItem(FALSE),
+	mHoverItem(NULL)
 
-///============================================================================
-/// Class LLMenuHolderGL
-///============================================================================
-LLMenuHolderGL::LLMenuHolderGL()
-	:	LLPanel(std::string("Menu Holder"))
 {
-	setMouseOpaque(FALSE);
-	sItemActivationTimer.stop();
-	mCanHide = TRUE;
+	//setBackgroundVisible(TRUE);
 }
 
-LLMenuHolderGL::LLMenuHolderGL(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows) 
-:	LLPanel(name, rect, FALSE)
+void LLContextMenu::setVisible(BOOL visible)
 {
-	setMouseOpaque(mouse_opaque);
-	sItemActivationTimer.stop();
-	mCanHide = TRUE;
+	if (!visible)
+		hide();
 }
 
-
-void LLMenuHolderGL::draw()
+void LLContextMenu::show(S32 x, S32 y,BOOL adjustCursor)
 {
-	LLView::draw();
-	// now draw last selected item as overlay
-	LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get();
-	if (selecteditem && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME)
-	{
-		// make sure toggle items, for example, show the proper state when fading out
-		selecteditem->buildDrawLabel();
+	S32 width = getRect().getWidth();
+	S32 height = getRect().getHeight();
 
-		LLRect item_rect;
-		selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this);
+	const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
 
-		F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME;
-		F32 alpha = lerp(LLMenuItemGL::getHighlightBGColor().mV[VALPHA], 0.f, interpolant);
-		LLColor4 bg_color(LLMenuItemGL::getHighlightBGColor().mV[VRED], 
-			LLMenuItemGL::getHighlightBGColor().mV[VGREEN], 
-			LLMenuItemGL::getHighlightBGColor().mV[VBLUE], 
-			alpha);
-		
-		LLUI::pushMatrix();
-		{
-			LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f);
-			selecteditem->getMenu()->drawBackground(selecteditem, bg_color);
-			selecteditem->draw();
-		}
-		LLUI::popMatrix();
-	}
-}
+	LLView* parent_view = getParent();
 
-BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask )
-{
-	BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
-	if (!handled)
-	{
-		// clicked off of menu, hide them all
-		hideMenus();
-	}
-	return handled;
-}
+	S32 local_x, local_y;
+	parent_view->screenPointToLocal(x, y, &local_x, &local_y);
 
-BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask )
-{
-	BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL;
-	if (!handled)
-	{
-		// clicked off of menu, hide them all
-		hideMenus();
-	}
-	return handled;
-}
+	// HACK: casting away const.  Should use setRect or some helper function instead.
+	const_cast<LLRect&>(getRect()).setCenterAndSize(local_x + width/2, local_y - height/2, width, height);
+	arrange();
 
-void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	if (width != getRect().getWidth() || height != getRect().getHeight())
+
+	if (translateIntoRect(menu_region_rect,FALSE) && adjustCursor)
 	{
-		hideMenus();
+		LLUI::setCursorPositionLocal(getParent(), getRect().mLeft , getRect().mTop);
 	}
-	LLView::reshape(width, height, called_from_parent);
+
+	LLView::setVisible(TRUE);
+
 }
 
-BOOL LLMenuHolderGL::hasVisibleMenu() const
+void LLContextMenu::hide()
 {
-	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+	if (!getVisible()) return;
+
+	LLView::setVisible(FALSE);
+
+	gFocusMgr.setMouseCapture(NULL);
+	
+	if (mHoverItem)
 	{
-		LLView* viewp = *child_it;
-		if (viewp->getVisible() && dynamic_cast<LLMenuBarGL*>(viewp) == NULL)
-		{
-			return TRUE;
-		}
+		mHoverItem->setHighlight( FALSE );
 	}
-	return FALSE;
+	mHoverItem = NULL;
 }
 
 
-BOOL LLMenuHolderGL::hideMenus()
+BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask )
 {
-	if (!mCanHide)
-	{
-		return FALSE;
-	}
-	BOOL menu_visible = hasVisibleMenu();
-	if (menu_visible)
+	BOOL handled = FALSE;
+
+	LLMenuItemGL *item = getItemFromXY( x, y );
+
+	if (item && item->getEnabled())
 	{
-		LLMenuGL::setKeyboardMode(FALSE);
-		// clicked off of menu, hide them all
-		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+		getWindow()->setCursor(UI_CURSOR_ARROW);
+		handled = TRUE;
+
+		if (item != mHoverItem)
 		{
-			LLView* viewp = *child_it;
-			// clicks off of menu do not hide menu bar
-			if (dynamic_cast<LLMenuBarGL*>(viewp) == NULL && viewp->getVisible())
+			if (mHoverItem)
 			{
-				viewp->setVisible(FALSE);
+				mHoverItem->setHighlight( FALSE );
 			}
+			mHoverItem = item;
+			mHoverItem->setHighlight( TRUE );
+		}
+		mHoveredAnyItem = TRUE;
+	}
+	else
+	{
+		// clear out our selection
+		if (mHoverItem)
+		{
+			mHoverItem->setHighlight(FALSE);
+			mHoverItem = NULL;
 		}
 	}
-	//if (gFocusMgr.childHasKeyboardFocus(this))
-	//{
-	//	gFocusMgr.setKeyboardFocus(NULL);
-	//}
 
-	return menu_visible;
-}
+	if( !handled && pointInView( x, y ) )
+	{
+		getWindow()->setCursor(UI_CURSOR_ARROW);
+		handled = TRUE;
+	}
 
-void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
-{
-	sItemLastSelectedHandle = item->getHandle();
-	sItemActivationTimer.start();
+	return handled;
 }
 
-///============================================================================
-/// Class LLTearOffMenu
-///============================================================================
-LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : 
-	LLFloater(menup->getName(), LLRect(0, 100, 100, 0), menup->getLabel(), FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, FALSE)
+BOOL LLContextMenu::handleMouseDown( S32 x, S32 y, MASK mask )
 {
-	// flag menu as being torn off
-	menup->setTornOff(TRUE);
-	// update menu layout as torn off menu (no spillover menus)
-	menup->arrange();
-
-	LLRect rect;
-	menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView);
-	// make sure this floater is big enough for menu
-	mTargetHeight = (F32)(rect.getHeight() + LLFLOATER_HEADER_SIZE + 5);
-	reshape(rect.getWidth(), rect.getHeight());
-	setRect(rect);
-
-	// attach menu to floater
-	menup->setFollowsAll();
-	mOldParent = menup->getParent();
-	addChild(menup);
-	menup->setVisible(TRUE);
-	menup->translate(-menup->getRect().mLeft + 1, -menup->getRect().mBottom + 1);
-	menup->setDropShadowed(FALSE);
+	BOOL handled = FALSE;
+	// The click was somewhere within our rectangle
+	LLMenuItemGL *item = getItemFromXY( x, y );
 
-	mMenu = menup;
+	if (item)
+	{
+		// lie to the item about where the click happened
+		// to make sure it's within the item's rectangle
+		handled = item->handleMouseDown( 0, 0, mask );
+	}
+	else 
+	{
+		// call hidemenus to make sure transient selections get cleared
+		((LLMenuHolderGL*)getParent())->hideMenus();
+	}
 
-	// highlight first item (tear off item will be disabled)
-	mMenu->highlightNextItem(NULL);
+	// always handle mouse down as mouse up will close open menus
+	return handled;
 }
-
-
-void LLTearOffMenu::draw()
+BOOL LLContextMenu::handleMouseUp( S32 x, S32 y, MASK mask )
 {
-	mMenu->setBackgroundVisible(isBackgroundOpaque());
-	mMenu->arrange();
+	BOOL handled = FALSE;
 
-	if (getRect().getHeight() != mTargetHeight)
+	// The click was somewhere within our rectangle
+	LLMenuItemGL *item = getItemFromXY( x, y );
+
+	if (item)
 	{
-		// animate towards target height
-		reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), mTargetHeight, LLCriticalDamp::getInterpolant(0.05f))));
+		// lie to the item about where the click happened
+		// to make sure it's within the item's rectangle
+		if (item->getEnabled())
+		{
+			handled = item->handleMouseUp( 0, 0, mask );
+			hide();
+		}
 	}
-	else
+	else 
 	{
-		// when in stasis, remain big enough to hold menu contents
-		mTargetHeight = (F32)(mMenu->getRect().getHeight() + LLFLOATER_HEADER_SIZE + 4);
-		reshape(mMenu->getRect().getWidth() + 3, mMenu->getRect().getHeight() + LLFLOATER_HEADER_SIZE + 5);
+		// call hidemenus to make sure transient selections get cleared
+		((LLMenuHolderGL*)getParent())->hideMenus();
 	}
-	LLFloater::draw();
+
+	if (!handled)
+	{
+		// call hidemenus to make sure transient selections get cleared
+		sMenuContainer->hideMenus();
+	}
+
+	return handled;
 }
 
-void LLTearOffMenu::onFocusReceived()
+BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
-	// if nothing is highlighted, just highlight first item
-	if (!mMenu->getHighlightedItem())
+	BOOL handled = FALSE;
+
+	// The click was somewhere within our rectangle
+	LLMenuItemGL *item = getItemFromXY( x, y );
+
+	S32 local_x = x - getRect().mLeft;
+	S32 local_y = y - getRect().mBottom;
+
+	BOOL clicked_in_menu = pointInView(local_x, local_y) ;
+
+	// grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
+	if (clicked_in_menu)
 	{
-		mMenu->highlightNextItem(NULL);
+		// capture mouse cursor as if on initial menu show
+		handled = TRUE;
 	}
-
-	// parent menu items get highlights so navigation logic keeps working
-	LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem();
-	while(parent_menu_item)
+	
+	if (item)
 	{
-		if (parent_menu_item->getMenu()->getVisible())
-		{
-			parent_menu_item->setHighlight(TRUE);
-			parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem();
-		}
-		else
+		// lie to the item about where the click happened
+		// to make sure it's within the item's rectangle
+		if (item->handleMouseDown( 0, 0, mask ))
 		{
-			break;
+			handled = TRUE;
 		}
 	}
-	LLFloater::onFocusReceived();
-}
 
-void LLTearOffMenu::onFocusLost()
-{
-	// remove highlight from parent item and our own menu
-	mMenu->clearHoverItem();
-	LLFloater::onFocusLost();
+	return handled;
 }
 
-BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
+BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
 {
-	// pass keystrokes down to menu
-	return mMenu->handleUnicodeChar(uni_char, TRUE);
-}
+	// release mouse capture when right mouse button released, and we're past the shrink time
 
-BOOL LLTearOffMenu::handleKeyHere(KEY key, MASK mask)
-{
-	if (!mMenu->getHighlightedItem())
+	S32 local_x = x - getRect().mLeft;
+	S32 local_y = y - getRect().mBottom;
+
+	if (!mHoveredAnyItem && !pointInView(local_x, local_y))
 	{
-		if (key == KEY_UP)
-		{
-			mMenu->highlightPrevItem(NULL);		
-			return TRUE;
-		}
-		else if (key == KEY_DOWN)
-		{
-			mMenu->highlightNextItem(NULL);
-			return TRUE;
-		}
+		gFocusMgr.setMouseCapture(NULL);
+		sMenuContainer->hideMenus();
+		return TRUE;
 	}
-	// pass keystrokes down to menu
-	return mMenu->handleKey(key, mask, TRUE);
+
+
+	BOOL result = handleMouseUp( x, y, mask );
+	mHoveredAnyItem = FALSE;
+	
+	return result;
 }
 
-void LLTearOffMenu::translate(S32 x, S32 y)
+LLMenuItemGL*	LLContextMenu::getItemFromXY		(S32 x, S32 y)
 {
-	if (x != 0 && y != 0)
+	item_list_t::iterator item_iter;
+	for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
 	{
-		// hide open sub-menus by clearing current hover item
-		mMenu->clearHoverItem();
+		S32 local_x = x - (**item_iter).getRect().mLeft;
+		S32 local_y = y - (**item_iter).getRect().mBottom;
+		if((**item_iter).pointInView(local_x,local_y))
+			return *item_iter;
 	}
-	LLFloater::translate(x, y);
+	return NULL;
 }
 
-//static
-LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
+void	LLContextMenu::draw				()
 {
-	LLTearOffMenu* tearoffp = new LLTearOffMenu(menup);
-	// keep onscreen
-	gFloaterView->adjustToFitScreen(tearoffp, FALSE);
-	tearoffp->open();	/* Flawfinder: ignore */
+	LLMenuGL::draw();
+}
 
-	return tearoffp;
+BOOL	LLContextMenu::appendContextSubMenu(LLContextMenu *menu)
+{
+	
+	if (menu == this)
+	{
+		llerrs << "Can't attach a context menu to itself" << llendl;
+	}
+
+	LLContextMenuBranch *item;
+	LLContextMenuBranch::Params p;
+	p.name = menu->getName();
+	p.label = menu->getLabel();
+	p.branch = menu;
+
+	item = LLUICtrlFactory::create<LLContextMenuBranch>(p);
+	LLMenuGL::sMenuContainer->addChild(item->getBranch());
+	item->setFont( LLFontGL::getFontSansSerifSmall() );
+
+	return append( item );
 }
 
-void LLTearOffMenu::onClose(bool app_quitting)
+bool LLContextMenu::addChild(LLView* view, S32 tab_group)
 {
-	removeChild(mMenu);
-	mOldParent->addChild(mMenu);
-	mMenu->clearHoverItem();
-	mMenu->setFollowsNone();
-	mMenu->setBackgroundVisible(TRUE);
-	mMenu->setVisible(FALSE);
-	mMenu->setTornOff(FALSE);
-	mMenu->setDropShadowed(TRUE);
-	destroy();
+	LLContextMenu* context = dynamic_cast<LLContextMenu*>(view);
+	if (context)
+		return appendContextSubMenu(context);
+
+	LLMenuItemSeparatorGL* separator = dynamic_cast<LLMenuItemSeparatorGL*>(view);
+	if (separator)
+		return append(separator);
+
+	LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view);
+	if (item)
+		return append(item);
+
+	return false;
 }
 
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index a2ef968bcd..3cb76efce0 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -38,78 +38,87 @@
 #include "llstring.h"
 #include "v4color.h"
 #include "llframetimer.h"
-#include "llevent.h"
 
 #include "llkeyboard.h"
 #include "llfloater.h"
 #include "lluistring.h"
 #include "llview.h"
-
+#include <boost/function.hpp>
 
 extern S32 MENU_BAR_HEIGHT;
 extern S32 MENU_BAR_WIDTH;
 
-// These callbacks are used by the LLMenuItemCallGL and LLMenuItemCheckGL
-// classes during their work.
-typedef void (*menu_callback)(void*);
-
-// These callbacks are used by the LLMenuItemCallGL 
-// classes during their work.
-typedef void (*on_disabled_callback)(void*);
-
-// This callback is used by the LLMenuItemCallGL and LLMenuItemCheckGL
-// to determine if the current menu is enabled.
-typedef BOOL (*enabled_callback)(void*);
-
-// This callback is used by LLMenuItemCheckGL to determine it's
-// 'checked' state.
-typedef BOOL (*check_callback)(void*);
-
-// This callback is potentially used by LLMenuItemCallGL. If provided,
-// this function is called whenever it's time to determine the label's
-// contents. Put the contents of the label in the provided parameter.
-typedef void (*label_callback)(std::string&,void*);
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemGL
 //
 // The LLMenuItemGL represents a single menu item in a menu. 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-class LLMenuItemGL : public LLView
+class LLMenuItemGL : public LLUICtrl
 {
 public:
-	// static functions to control the global color scheme.
-	static void setEnabledColor( const LLColor4& color ) { sEnabledColor = color; }
-	static const LLColor4& getEnabledColor() { return sEnabledColor; }
-	static void setDisabledColor( const LLColor4& color ) { sDisabledColor = color; }
-	static const LLColor4& getDisabledColor() { return sDisabledColor; }
-	static void setHighlightBGColor( const LLColor4& color ) { sHighlightBackground = color; }
-	static const LLColor4& getHighlightBGColor() { return sHighlightBackground; }
-	static void setHighlightFGColor( const LLColor4& color ) { sHighlightForeground = color; }
-	static const LLColor4& getHighlightFGColor() { return sHighlightForeground; }
-
-	LLMenuItemGL( const std::string& name, const std::string& label, KEY key = KEY_NONE, MASK = MASK_NONE );
-	virtual ~LLMenuItemGL() {};
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<std::string>	shortcut;
+		Optional<KEY>			jump_key;
+		Optional<bool>			use_mac_ctrl;
+
+		Deprecated				rect,
+								left,
+								top,
+								right,
+								bottom,
+								width,
+								height,
+								bottom_delta,
+								left_delta;
+
+		Optional<LLUIColor>		enabled_color,
+								disabled_color,
+								highlight_bg_color,
+								highlight_fg_color;
+
+
+		Params()
+		:	shortcut("shortcut"),
+			jump_key("", KEY_NONE),
+			use_mac_ctrl("use_mac_ctrl", false),
+			rect("rect"),
+			left("left"),
+			top("top"),
+			right("right"),
+			bottom("bottom"),
+			width("width"),
+			height("height"),
+			bottom_delta("bottom_delta"),
+			left_delta("left_delta"),
+			enabled_color("enabled_color"),
+			disabled_color("disabled_color"),
+			highlight_bg_color("highlight_bg_color"),
+			highlight_fg_color("highlight_fg_color")
+		{	
+			mouse_opaque = true;
+		}
+	};
 
+protected:
+	LLMenuItemGL(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual void setValue(const LLSD& value) { setLabel(value.asString()); }
-
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-
-	virtual std::string getType() const	{ return "item"; }
+	/*virtual*/ void onVisibilityChange(BOOL new_visibility);
 
 	virtual BOOL handleHover(S32 x, S32 y, MASK mask);
-
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
+	LLColor4 getHighlightBgColor() { return mHighlightBackground.get(); }
+
 	void setJumpKey(KEY key);
 	KEY getJumpKey() const { return mJumpKey; }
 	
 	// set the font used by this item.
 	void setFont(const LLFontGL* font) { mFont = font; }
 	const LLFontGL* getFont() const { return mFont; }
-	void setFontStyle(U8 style) { mStyle = style; }
-	U8 getFontStyle() const { return mStyle; }
 
 	// returns the height in pixels for the current font.
 	virtual U32 getNominalHeight( void ) const;
@@ -140,7 +149,7 @@ public:
 	// lead to visual errors if the state of the object changes
 	// without the knowledge of the menu item. For example, if a
 	// boolean being watched is changed outside of the menu item's
-	// doIt() function, the draw buffer will not be updated and will
+	// onCommit() function, the draw buffer will not be updated and will
 	// reflect the wrong value. If this ever becomes an issue, there
 	// are ways to fix this.
 	// Returns the enabled state of the item.
@@ -149,8 +158,7 @@ public:
 	// for branching menu items, bring sub menus up to root level of menu hierarchy
 	virtual void updateBranchParent( LLView* parentp ){};
 	
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void );
+	virtual void onCommit( void );
 
 	virtual void setHighlight( BOOL highlight );
 	virtual BOOL getHighlight() const { return mHighlight; }
@@ -180,7 +188,10 @@ protected:
 	// This function appends the character string representation of
 	// the current accelerator key and mask to the provided string.
 	void appendAcceleratorString( std::string& st ) const;
-
+	
+	void initMenuEnableCallback(const EnableCallbackParam& cb, enable_signal_t& sig);
+	
+protected:
 	KEY mAcceleratorKey;
 	MASK mAcceleratorMask;
 	// mLabel contains the actual label specified by the user.
@@ -193,13 +204,13 @@ protected:
 	LLUIString mDrawAccelLabel;
 	LLUIString mDrawBranchLabel;
 
+	LLUIColor mEnabledColor;
+	LLUIColor mDisabledColor;
+	LLUIColor mHighlightBackground;
+	LLUIColor mHighlightForeground;
+
 	BOOL mHighlight;
 private:
-	static LLColor4 sEnabledColor;
-	static LLColor4 sDisabledColor;
-	static LLColor4 sHighlightBackground;
-	static LLColor4 sHighlightForeground;
-
 	// Keyboard and mouse variables
 	BOOL mAllowKeyRepeat;
 	BOOL mGotHover;
@@ -210,12 +221,32 @@ private:
 
 	// Font for this item
 	const LLFontGL* mFont;
-	U8	mStyle;
 	BOOL mDrawTextDisabled;
 
 	KEY mJumpKey;
 };
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLMenuItemSeparatorGL
+//
+// This class represents a separator.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLMenuItemSeparatorGL : public LLMenuItemGL
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
+	{
+		Params();
+	};
+	LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());
+
+	/*virtual*/ void draw( void );
+	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
+
+	/*virtual*/ U32 getNominalHeight( void ) const;
+};
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemCallGL
@@ -224,78 +255,48 @@ private:
 // calls a user defined callback.
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-class LLMenuItemCallGL : public LLMenuItemGL, public LLObservable
+class LLMenuItemCallGL : public LLMenuItemGL
 {
 public:
-	// normal constructor
-	LLMenuItemCallGL( const std::string& name,
- 					  menu_callback clicked_cb, 
-					  enabled_callback enabled_cb = NULL,
-					  void* user_data = NULL, 
-					  KEY key = KEY_NONE, MASK mask = MASK_NONE,
-					  BOOL enabled = TRUE,
-					  on_disabled_callback on_disabled_cb = NULL);
-	LLMenuItemCallGL( const std::string& name,
-					  const std::string& label,
- 					  menu_callback clicked_cb, 
-					  enabled_callback enabled_cb = NULL,
-					  void* user_data = NULL, 
-					  KEY key = KEY_NONE, MASK mask = MASK_NONE,
-					  BOOL enabled = TRUE,
-					  on_disabled_callback on_disabled_cb = NULL);
-
-	// constructor for when you want to trap the arrange method.
-	LLMenuItemCallGL( const std::string& name,
-					  const std::string& label,
-					  menu_callback clicked_cb,
-					  enabled_callback enabled_cb,
-					  label_callback label_cb,
-					  void* user_data,
-					  KEY key = KEY_NONE, MASK mask = MASK_NONE,
-					  BOOL enabled = TRUE,
-					  on_disabled_callback on_disabled_c = NULL);
-	LLMenuItemCallGL( const std::string& name,
-					  menu_callback clicked_cb,
-					  enabled_callback enabled_cb,
-					  label_callback label_cb,
-					  void* user_data,
-					  KEY key = KEY_NONE, MASK mask = MASK_NONE,
-					  BOOL enabled = TRUE,
-					  on_disabled_callback on_disabled_c = NULL);
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-
-	virtual std::string getType() const	{ return "call"; }
-
-
-	void setEnabledControl(std::string enabled_control, LLView *context);
-	void setVisibleControl(std::string enabled_control, LLView *context);
-
-	void setMenuCallback(menu_callback callback, void* data) { mCallback = callback;  mUserData = data; };
-	menu_callback getMenuCallback() const { return mCallback; }
-
-	void setEnabledCallback(enabled_callback callback) { mEnabledCallback = callback; };
-
-	void setUserData(void *userdata)	{ mUserData = userdata; }
-	void* getUserData() const { return mUserData; }
+	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
+	{
+		Optional<EnableCallbackParam > on_enable;
+		Optional<CommitCallbackParam > on_click;
+		Params()
+			: on_enable("on_enable"),
+			  on_click("on_click")
+		{}
+	};
+protected:
+	LLMenuItemCallGL(const Params&);
+	friend class LLUICtrlFactory;
+	void updateEnabled( void );
 
+public:
+	void initFromParams(const Params& p);
+	
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
 
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void );
+	virtual void onCommit( void );
 
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
-
+	virtual BOOL handleKeyHere(KEY key, MASK mask);
+	
 	//virtual void draw();
-
-
+	
+	boost::signals::connection setClickCallback( const commit_signal_t::slot_type& cb )
+	{
+		return setCommitCallback(cb);
+	}
+	
+	boost::signals::connection setEnableCallback( const enable_signal_t::slot_type& cb )
+	{
+		return mEnableSignal.connect(cb);
+	}
+	
 private:
-	menu_callback			mCallback;
-	// mEnabledCallback should return TRUE if the item should be enabled
-	enabled_callback		mEnabledCallback;	
-	label_callback			mLabelCallback;
-	void*					mUserData;
-	on_disabled_callback	mOnDisabledCallback;
+	enable_signal_t mEnableSignal;
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -312,78 +313,37 @@ class LLMenuItemCheckGL
 :	public LLMenuItemCallGL
 {
 public:
-	LLMenuItemCheckGL( const std::string& name, 
-					   const std::string& label,
-					   menu_callback callback,
-					   enabled_callback enabled_cb,
-					   check_callback check,
-					   void* user_data,
-					   KEY key = KEY_NONE, MASK mask = MASK_NONE );
-	LLMenuItemCheckGL( const std::string& name, 
-					   menu_callback callback,
-					   enabled_callback enabled_cb,
-					   check_callback check,
-					   void* user_data,
-					   KEY key = KEY_NONE, MASK mask = MASK_NONE );
-	LLMenuItemCheckGL( const std::string& name, 
-					   const std::string& label,
-					   menu_callback callback,
-					   enabled_callback enabled_cb,
-					   std::string control_name,
-					   LLView *context,
-					   void* user_data,
-					   KEY key = KEY_NONE, MASK mask = MASK_NONE );
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-
-	void setCheckedControl(std::string checked_control, LLView *context);
-
-	virtual void setValue(const LLSD& value);
-
-	virtual std::string getType() const	{ return "check"; }
-
-	// called to rebuild the draw label
-	virtual void buildDrawLabel( void );
-
-private:
-	check_callback mCheckCallback;
-	BOOL mChecked;
-};
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLMenuItemToggleGL
-//
-// The LLMenuItemToggleGL is a menu item that wraps around a user
-// specified and controlled boolean.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
+	{
+		Optional<EnableCallbackParam > on_check;
+		Params()
+		:	on_check("on_check")
+		{}
+	};
 
-class LLMenuItemToggleGL : public LLMenuItemGL
-{
+protected:
+	LLMenuItemCheckGL(const Params&);
+	friend class LLUICtrlFactory;
 public:
-	LLMenuItemToggleGL( const std::string& name, const std::string& label,
-						BOOL* toggle, 
-						KEY key = KEY_NONE, MASK mask = MASK_NONE );
-
-	LLMenuItemToggleGL( const std::string& name,
-						BOOL* toggle, 
-						KEY key = KEY_NONE, MASK mask = MASK_NONE );
+	
+	void initFromParams(const Params& p);
 
-	virtual std::string getType() const	{ return "toggle"; }
+	virtual void onCommit( void );
+	
+	virtual void setValue(const LLSD& value);
 
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
-
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void );
-
-	// LLView Functionality
-	//virtual void draw( void );
-
+	
+	boost::signals::connection setCheckCallback( const enable_signal_t::slot_type& cb )
+	{
+		return mCheckSignal.connect(cb);
+	}
+	
 private:
-	BOOL* mToggle;
+	enable_signal_t mCheckSignal;
 };
 
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuGL
 //
@@ -397,27 +357,55 @@ private:
 
 class LLMenuGL 
 :	public LLUICtrl
-// TODO: The menu and menu item classes share a great deal of functionality and perhaps should be united.
-// I think it may make the most sense to make LLMenuGL be a subclass of LLMenuItemGL. -MG
 {
+public:
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<LLHandle<LLFloater> >	parent_floater;
+		Optional<KEY>					jump_key;
+		Optional<bool>					horizontal_layout,
+										can_tear_off,
+										drop_shadow,
+										bg_visible,
+										create_jump_keys,
+										keep_fixed_size;
+		Optional<LLUIColor>				bg_color;
+
+		Params()
+		:	jump_key("", KEY_NONE),
+			can_tear_off("tear_off", false),
+			drop_shadow("drop_shadow", true),
+			bg_visible("bg_visible", true),
+			create_jump_keys("create_jump_keys", false),
+			bg_color("bg_color",  LLUI::getCachedColorFunctor( "MenuDefaultBgColor" ))
+		{
+			addSynonym(bg_visible, "opaque");
+			addSynonym(bg_color, "color");
+
+			name = "menu";
+		}
+	};
+	void initFromParams(const Params&);
+
+protected:
+	LLMenuGL(const LLMenuGL::Params& p);
+	friend class LLUICtrlFactory;
 	// let branching menu items use my protected traversal methods
 	friend class LLMenuItemBranchGL;
 public:
-	LLMenuGL( const std::string& name, const std::string& label, LLHandle<LLFloater> parent_floater = LLHandle<LLFloater>());
-	LLMenuGL( const std::string& label, LLHandle<LLFloater> parent_floater = LLHandle<LLFloater>() );
 	virtual ~LLMenuGL( void );
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-
-	void parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory);
 
+	void parseChildXML(LLXMLNodePtr child, LLView* parent);
 
 	// LLView Functionality
-	virtual BOOL handleUnicodeCharHere( llwchar uni_char );
-	virtual BOOL handleHover( S32 x, S32 y, MASK mask );
-	virtual void draw( void );
-	virtual void drawBackground(LLMenuItemGL* itemp, LLColor4& color);
-	virtual void setVisible(BOOL visible);
+	/*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char );
+	/*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask );
+	/*virtual*/ void draw( void );
+	/*virtual*/ void drawBackground(LLMenuItemGL* itemp, F32 alpha);
+	/*virtual*/ void setVisible(BOOL visible);
+	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
+	/*virtual*/ void removeChild( LLView* ctrl);
+	/*virtual*/ BOOL postBuild();
 
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 
@@ -430,20 +418,13 @@ public:
 	void setLabel(const LLStringExplicit& label) { mLabel = label; }
 
 	// background colors
-	static void setDefaultBackgroundColor( const LLColor4& color ) { sDefaultBackgroundColor = color; }
-	void setBackgroundColor( const LLColor4& color ) { mBackgroundColor = color; }
-	const LLColor4& getBackgroundColor() const { return mBackgroundColor; }
+	void setBackgroundColor( const LLUIColor& color ) { mBackgroundColor = color; }
+	const LLUIColor& getBackgroundColor() const { return mBackgroundColor; }
 	void setBackgroundVisible( BOOL b )	{ mBgVisible = b; }
 	void setCanTearOff(BOOL tear_off, LLHandle<LLFloater> parent_floater_handle = LLHandle<LLFloater>());
 
-	// Add the menu item to this menu.
-	virtual BOOL append( LLMenuItemGL* item );
-
 	// add a separator to this menu
-	virtual BOOL appendSeparator( const std::string &separator_name = LLStringUtil::null );
-
-	// add a menu - this will create a cascading menu
-	virtual BOOL appendMenu( LLMenuGL* menu );
+	virtual BOOL addSeparator();
 
 	// for branching menu items, bring sub menus up to root level of menu hierarchy
 	virtual void updateParent( LLView* parentp );
@@ -467,19 +448,17 @@ public:
 
 	virtual BOOL isOpen();
 
+	void needsArrange() { mNeedsArrange = TRUE; }
 	// Shape this menu to fit the current state of the children, and
 	// adjust the child rects to fit. This is called automatically
 	// when you add items. *FIX: We may need to deal with visibility
 	// arrangement.
 	virtual void arrange( void );
+	void arrangeAndClear( void );
 
 	// remove all items on the menu
 	void empty( void );
 
-	// Rearrange the components, and do the right thing if the menu doesn't
-	// fit in the bounds.
-	// virtual void arrangeWithBounds(LLRect bounds);
-
 	void			setItemLastSelected(LLMenuItemGL* item);	// must be in menu
 	U32				getItemCount();				// number of menu items
 	LLMenuItemGL*	getItem(S32 number);		// 0 = first item
@@ -500,8 +479,8 @@ public:
 	// Whether to drop shadow menu bar 
 	void setDropShadowed( const BOOL shadowed );
 
-	void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item; }
-	LLMenuItemGL* getParentMenuItem() const { return mParentMenuItem; }
+	void setParentMenuItem( LLMenuItemGL* parent_menu_item ) { mParentMenuItem = parent_menu_item->getHandle(); }
+	LLMenuItemGL* getParentMenuItem() const { return dynamic_cast<LLMenuItemGL*>(mParentMenuItem.get()); }
 
 	void setTornOff(BOOL torn_off);
 	BOOL getTornOff() { return mTornOff; }
@@ -519,6 +498,11 @@ public:
 protected:
 	void createSpilloverBranch();
 	void cleanupSpilloverBranch();
+	// Add the menu item to this menu.
+	virtual BOOL append( LLMenuItemGL* item );
+
+	// add a menu - this will create a cascading menu
+	virtual BOOL appendMenu( LLMenuGL* menu );
 
 	// TODO: create accessor methods for these?
 	typedef std::list< LLMenuItemGL* > item_list_t;
@@ -531,14 +515,17 @@ protected:
 	S32				mMouseVelY;
 	BOOL			mHorizontalLayout;
 	BOOL			mKeepFixedSize;
+	BOOL			mNeedsArrange;
 
 private:
+
+
 	static LLColor4 sDefaultBackgroundColor;
 	static BOOL		sKeyboardMode;
 
-	LLColor4		mBackgroundColor;
+	LLUIColor		mBackgroundColor;
 	BOOL			mBgVisible;
-	LLMenuItemGL*	mParentMenuItem;
+	LLHandle<LLView> mParentMenuItem;
 	LLUIString		mLabel;
 	BOOL mDropShadowed; 	//  Whether to drop shadow 
 	BOOL			mHasSelection;
@@ -549,6 +536,7 @@ private:
 	LLMenuGL*		mSpilloverMenu;
 	LLHandle<LLFloater>	mParentFloaterHandle;
 	KEY				mJumpKey;
+	BOOL			mCreateJumpKeys;
 }; // end class LLMenuGL
 
 
@@ -563,15 +551,17 @@ private:
 class LLMenuItemBranchGL : public LLMenuItemGL
 {
 public:
-	LLMenuItemBranchGL( const std::string& name, const std::string& label, LLHandle<LLView> branch,
-						KEY key = KEY_NONE, MASK mask = MASK_NONE );
+	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
+	{
+		Optional<LLMenuGL*>	branch;
+	};
 
+protected:
+	LLMenuItemBranchGL(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual ~LLMenuItemBranchGL();
-
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-
-	virtual std::string getType() const { return "menu"; }
-
+	
 	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
@@ -582,8 +572,7 @@ public:
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
 
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void );
+	virtual void onCommit( void );
 
 	virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
 	virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
@@ -594,11 +583,11 @@ public:
 
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 
-	virtual BOOL isActive() const { return isOpen() && getBranch()->getHighlightedItem(); }
+	virtual BOOL isActive() const { return isOpen() && getBranch() && getBranch()->getHighlightedItem(); }
 
 	virtual BOOL isOpen() const { return getBranch() && getBranch()->isOpen(); }
 
-	LLMenuGL *getBranch() const { return (LLMenuGL*)(mBranch.get()); }
+	LLMenuGL* getBranch() const { return (LLMenuGL*)mBranchHandle.get(); }
 
 	virtual void updateBranchParent( LLView* parentp );
 
@@ -607,77 +596,72 @@ public:
 
 	virtual void draw();
 
-	virtual void setEnabledSubMenus(BOOL enabled) { if(getBranch()) getBranch()->setEnabledSubMenus(enabled); }
+	virtual void setEnabledSubMenus(BOOL enabled) { if (getBranch()) getBranch()->setEnabledSubMenus(enabled); }
 
 	virtual void openMenu();
 
 	virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
 
 private:
-	LLHandle<LLView> mBranch;
+	LLHandle<LLView> mBranchHandle;
 }; // end class LLMenuItemBranchGL
 
 
-
 //-----------------------------------------------------------------------------
-// class LLPieMenu
-// A circular menu of items, icons, etc.
+// class LLContextMenu
+// A context menu
 //-----------------------------------------------------------------------------
 
-class LLPieMenu
+class LLContextMenu
 : public LLMenuGL
 {
 public:
-	LLPieMenu(const std::string& name, const std::string& label);
-	LLPieMenu(const std::string& name);
-	virtual ~LLPieMenu() {}
+	struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
+	{
+		Params()
+		{
+			visible = false;
+		}
+	};
 
-	void initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory);
+protected:
+	LLContextMenu(const Params& p);
+	friend class LLUICtrlFactory;
+
+public:
+	virtual ~LLContextMenu() {}
 
 	// LLView Functionality
 	// can't set visibility directly, must call show or hide
-	virtual void setVisible(BOOL visible);
+	virtual void	setVisible			(BOOL visible);
 	
-	virtual BOOL handleHover( S32 x, S32 y, MASK mask );
-	virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
-	virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
-	virtual BOOL handleRightMouseUp( S32 x, S32 y, MASK mask );
-	virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
-	virtual void draw();
-	virtual void drawBackground(LLMenuItemGL* itemp, LLColor4& color);
+	virtual void	draw				();
+	
+	virtual void	show				(S32 x, S32 y, BOOL adjustCursor = TRUE);
+	virtual void	hide				();
 
-	virtual BOOL append(LLMenuItemGL* item);
-	virtual BOOL appendSeparator( const std::string &separator_name = LLStringUtil::null );
+	
 
-	BOOL appendPieMenu(LLPieMenu *menu);
+	virtual BOOL	handleHover			( S32 x, S32 y, MASK mask );
+	virtual BOOL	handleMouseDown		( S32 x, S32 y, MASK mask );
+	virtual BOOL	handleRightMouseDown( S32 x, S32 y, MASK mask );
+	virtual BOOL	handleRightMouseUp	( S32 x, S32 y, MASK mask );
+	virtual BOOL	handleMouseUp		( S32 x, S32 y, MASK mask );
 
-	virtual void arrange( void );
+	virtual bool	addChild			(LLView* view, S32 tab_group = 0);
 
-	// Display the menu centered on this point on the screen.
-	void show(S32 x, S32 y, BOOL mouse_down);
-	void hide(BOOL item_selected);
+			BOOL	appendContextSubMenu(LLContextMenu *menu);
 
-private:
-	LLMenuItemGL *pieItemFromXY(S32 x, S32 y);
-	S32			  pieItemIndexFromXY(S32 x, S32 y);
-
-	// These cause menu items to be spuriously selected by right-clicks
-	// near the window edge at low frame rates.  I don't think they are
-	// needed unless you shift the menu position in the draw() function. JC
-	//S32				mShiftHoriz;	// non-zero if menu had to shift this frame
-	//S32				mShiftVert;		// non-zero if menu had to shift this frame
-	BOOL			mFirstMouseDown;	// true from show until mouse up
-	BOOL			mUseInfiniteRadius;	// allow picking pie menu items anywhere outside of center circle
-	LLMenuItemGL*	mHoverItem;
-	BOOL			mHoverThisFrame;
+protected:
+	LLMenuItemGL*	getItemFromXY		(S32 x, S32 y);
+
+protected:
 	BOOL			mHoveredAnyItem;
-	LLFrameTimer	mShrinkBorderTimer;
-	F32				mOuterRingAlpha; // for rendering pie menus as both bounded and unbounded
-	F32				mCurRadius;
-	BOOL			mRightMouseDown;
+	LLMenuItemGL*	mHoverItem;
 };
 
 
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuBarGL
 //
@@ -687,10 +671,19 @@ private:
 class LLMenuBarGL : public LLMenuGL
 {
 public:
-	LLMenuBarGL( const std::string& name );
+	struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
+	{
+		Params()
+		{
+			can_tear_off = false;
+			keep_fixed_size = true;
+			horizontal_layout = true;
+			visible = true;
+			drop_shadow = false;
+		}
+	};
+	LLMenuBarGL( const Params& p );
 	virtual ~LLMenuBarGL();
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
 
 	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
@@ -698,17 +691,11 @@ public:
 	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
 
-	// rearrange the child rects so they fit the shape of the menu
-	// bar.
-	virtual void arrange( void );
 	virtual void draw();
 	virtual BOOL jumpKeysActive();
 
 	// add a vertical separator to this menu
-	virtual BOOL appendSeparator( const std::string &separator_name = LLStringUtil::null );
-
-	// add a menu - this will create a drop down menu.
-	virtual BOOL appendMenu( LLMenuGL* menu );
+	virtual BOOL addSeparator();
 
 	// LLView Functionality
 	virtual BOOL handleHover( S32 x, S32 y, MASK mask );
@@ -719,6 +706,12 @@ public:
 	void resetMenuTrigger() { mAltKeyTrigger = FALSE; }
 
 private:
+	// add a menu - this will create a drop down menu.
+	virtual BOOL appendMenu( LLMenuGL* menu );
+	// rearrange the child rects so they fit the shape of the menu
+	// bar.
+	virtual void arrange( void );
+
 	void checkMenuTrigger();
 
 	std::list <LLKeyBinding*>	mAccelerators;
@@ -734,7 +727,6 @@ class LLMenuHolderGL : public LLPanel
 {
 public:
 	LLMenuHolderGL();
-	LLMenuHolderGL(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows = FOLLOWS_NONE);
 	virtual ~LLMenuHolderGL() {}
 
 	virtual BOOL hideMenus();
@@ -794,11 +786,19 @@ private:
 class LLMenuItemTearOffGL : public LLMenuItemGL
 {
 public:
-	LLMenuItemTearOffGL( LLHandle<LLFloater> parent_floater_handle = LLHandle<LLFloater>());
-
-	virtual std::string getType() const { return "tearoff_menu"; }
-
-	virtual void doIt(void);
+	struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
+	{
+		Optional<LLHandle<LLFloater> > parent_floater_handle;
+		Params()
+		{
+			name = "tear off";
+			label = "~~~~~~~~~~~";
+		}
+	};
+
+	LLMenuItemTearOffGL( const Params& );
+
+	virtual void onCommit(void);
 	virtual void draw(void);
 	virtual U32 getNominalHeight() const;
 
@@ -820,4 +820,31 @@ private:
 	LLEditMenuHandlerMgr() {};
 };
 
+
+// *TODO: Eliminate
+// For backwards compatability only; generally just use boost::bind
+class view_listener_t : public boost::signals::trackable
+{
+public:
+	virtual bool handleEvent(const LLSD& userdata) = 0;
+	virtual ~view_listener_t() {}
+	
+	static void addEnable(view_listener_t* listener, const std::string& name)
+	{
+		LLUICtrl::EnableCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
+	}
+	
+	static void addCommit(view_listener_t* listener, const std::string& name)
+	{
+		LLUICtrl::CommitCallbackRegistry::currentRegistrar().add(name, boost::bind(&view_listener_t::handleEvent, listener, _2));
+	}
+	
+	static void addMenu(view_listener_t* listener, const std::string& name)
+	{
+		// For now, add to both click and enable registries
+		addEnable(listener, name);
+		addCommit(listener, name);
+	}
+};
+
 #endif // LL_LLMENUGL_H
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index 1662ff7db6..8779eee28d 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -45,17 +45,16 @@
 std::list<LLModalDialog*> LLModalDialog::sModalStack;
 
 LLModalDialog::LLModalDialog( const std::string& title, S32 width, S32 height, BOOL modal )
-	: LLFloater( std::string("modal container"),
-				 LLRect( 0, height, width, 0 ),
-				 title,
-				 FALSE, // resizable
-				 DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT,
-				 FALSE, // drag_on_left
-				 modal ? FALSE : TRUE, // minimizable
-				 modal ? FALSE : TRUE, // close button
-				 TRUE), // bordered
+	: LLFloater(),
 	  mModal( modal )
 {
+	setRect(LLRect( 0, height, width, 0 ));
+	setTitle(title);
+	if (modal)
+	{
+		setCanMinimize(FALSE);
+		setCanClose(FALSE);
+	}
 	setVisible( FALSE );
 	setBackgroundVisible(TRUE);
 	setBackgroundOpaque(TRUE);
@@ -72,12 +71,12 @@ LLModalDialog::~LLModalDialog()
 }
 
 // virtual
-void LLModalDialog::open()	/* Flawfinder: ignore */
+void LLModalDialog::openFloater(const LLSD& key)
 {
 	// SJB: Hack! Make sure we don't ever host a modal dialog
 	LLMultiFloater* thost = LLFloater::getFloaterHost();
 	LLFloater::setFloaterHost(NULL);
-	LLFloater::open();
+	LLFloater::openFloater(key);
 	LLFloater::setFloaterHost(thost);
 }
 
@@ -229,7 +228,7 @@ BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask )
 		BOOL enough_time_elapsed = mVisibleTime.getElapsedTimeF32() > 1.0f;
 		if (enough_time_elapsed && key == KEY_ESCAPE)
 		{
-			close();
+			closeFloater();
 			return TRUE;
 		}
 		return FALSE;
@@ -245,32 +244,15 @@ void LLModalDialog::onClose(bool app_quitting)
 // virtual
 void LLModalDialog::draw()
 {
-	LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow");
-	S32 shadow_lines = LLUI::sConfigGroup->getS32("DropShadowFloater");
+	static LLUICachedControl<LLColor4> shadow_color ("ColorDropShadow", *(new LLColor4));
+	static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 0);
 
 	gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
 		shadow_color, shadow_lines);
 
 	LLFloater::draw();
-
-	if (mModal)
-	{
-		// If we've lost focus to a non-child, get it back ASAP.
-		if( gFocusMgr.getTopCtrl() != this )
-		{
-			gFocusMgr.setTopCtrl( this );
-		}
-
-		if( !gFocusMgr.childHasKeyboardFocus( this ) )
-		{
-			setFocus(TRUE);
-		}
-
-		if( !gFocusMgr.childHasMouseCapture( this ) )
-		{
-			gFocusMgr.setMouseCapture( this );
-		}
-	}
+	
+	// Focus retrieval moved to LLFloaterView::refresh()
 }
 
 void LLModalDialog::centerOnScreen()
diff --git a/indra/llui/llmodaldialog.h b/indra/llui/llmodaldialog.h
index f6abd0a7ac..dad92ab82a 100644
--- a/indra/llui/llmodaldialog.h
+++ b/indra/llui/llmodaldialog.h
@@ -48,7 +48,7 @@ public:
 	LLModalDialog( const std::string& title, S32 width, S32 height, BOOL modal = true );
 	/*virtual*/ ~LLModalDialog();
 
-	/*virtual*/ void	open();	/* Flawfinder: ignore */
+	/*virtual*/ void	openFloater(const LLSD& key = LLSD());
 	
 	/*virtual*/ void 	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	
diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp
new file mode 100644
index 0000000000..c0fe7ff32d
--- /dev/null
+++ b/indra/llui/llmultifloater.cpp
@@ -0,0 +1,510 @@
+/** 
+ * @file llmultifloater.cpp
+ * @brief LLFloater that hosts other floaters
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Floating "windows" within the GL display, like the inventory floater,
+// mini-map floater, etc.
+
+#include "linden_common.h"
+
+#include "llmultifloater.h"
+#include "llresizehandle.h"
+
+//
+// LLMultiFloater
+//
+
+LLMultiFloater::LLMultiFloater(const LLFloater::Params& params)
+	: LLFloater(),
+	  mTabContainer(NULL),
+	  mTabPos(LLTabContainer::TOP),
+	  mAutoResize(TRUE),
+	  mOrigMinWidth(0),
+	  mOrigMinHeight(0)
+{
+}
+
+void LLMultiFloater::buildTabContainer()
+{
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	
+	LLTabContainer::Params p;
+	p.name(std::string("Preview Tabs"));
+	p.rect(LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - floater_header_size, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0));
+	p.tab_position(mTabPos);
+	p.follows.flags(FOLLOWS_ALL);
+	p.commit_callback.function(boost::bind(&LLMultiFloater::onTabSelected, this));
+
+	mTabContainer = LLUICtrlFactory::create<LLTabContainer>(p);
+	addChild(mTabContainer);
+	
+	if (isResizable())
+	{
+		mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
+	}
+}
+
+void LLMultiFloater::onOpen(const LLSD& key)
+{
+	if (mTabContainer->getTabCount() <= 0)
+	{
+		// for now, don't allow multifloaters
+		// without any child floaters
+		closeFloater();
+	}
+}
+
+void LLMultiFloater::onClose(bool app_quitting)
+{
+	if(closeAllFloaters() == TRUE)
+	{
+		LLFloater::onClose(app_quitting);
+	}//else not all tabs could be closed...
+}
+
+void LLMultiFloater::draw()
+{
+	if (mTabContainer->getTabCount() == 0)
+	{
+		//RN: could this potentially crash in draw hierarchy?
+		closeFloater();
+	}
+	else
+	{
+		for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
+		{
+			LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
+			if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i))
+			{
+				mTabContainer->setPanelTitle(i, floaterp->getShortTitle());
+			}
+		}
+		LLFloater::draw();
+	}
+}
+
+BOOL LLMultiFloater::closeAllFloaters()
+{
+	S32	tabToClose = 0;
+	S32	lastTabCount = mTabContainer->getTabCount();
+	while (tabToClose < mTabContainer->getTabCount())
+	{
+		LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
+		first_floater->closeFloater();
+		if(lastTabCount == mTabContainer->getTabCount())
+		{
+			//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
+			//so try and close the next one in the list...
+			tabToClose++;
+		}else
+		{
+			//Tab closed ok.
+			lastTabCount = mTabContainer->getTabCount();
+		}
+	}
+	if( mTabContainer->getTabCount() != 0 )
+		return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE.
+	return TRUE; //else all tabs were successfully closed...
+}
+
+void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
+{
+	static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
+	S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
+	S32 new_height = llmax(getRect().getHeight(), content_height + floater_header_size + tabcntr_header_height);
+
+    if (isMinimized())
+    {
+        LLRect newrect;
+        newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height);
+        setExpandedRect(newrect);
+    }
+	else
+	{
+		S32 old_height = getRect().getHeight();
+		reshape(new_width, new_height);
+		// keep top left corner in same position
+		translate(0, old_height - new_height);
+	}
+}
+
+/**
+  void addFloater(LLFloater* floaterp, BOOL select_added_floater)
+
+  Adds the LLFloater pointed to by floaterp to this.
+  If floaterp is already hosted by this, then it is re-added to get
+  new titles, etc.
+  If select_added_floater is true, the LLFloater pointed to by floaterp will
+  become the selected tab in this
+
+  Affects: mTabContainer, floaterp
+**/
+void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
+{
+	if (!floaterp)
+	{
+		return;
+	}
+
+	if (!mTabContainer)
+	{
+		llerrs << "Tab Container used without having been initialized." << llendl;
+		return;
+	}
+
+	if (floaterp->getHost() == this)
+	{
+		// already hosted by me, remove
+		// do this so we get updated title, etc.
+		mFloaterDataMap.erase(floaterp->getHandle());
+		mTabContainer->removeTabPanel(floaterp);
+	}
+	else if (floaterp->getHost())
+	{
+		// floaterp is hosted by somebody else and
+		// this is adding it, so remove it from it's old host
+		floaterp->getHost()->removeFloater(floaterp);
+	}
+	else if (floaterp->getParent() == gFloaterView)
+	{
+		// rehost preview floater as child panel
+		gFloaterView->removeChild(floaterp);
+	}
+
+	// store original configuration
+	LLFloaterData floater_data;
+	floater_data.mWidth = floaterp->getRect().getWidth();
+	floater_data.mHeight = floaterp->getRect().getHeight();
+	floater_data.mCanMinimize = floaterp->isMinimizeable();
+	floater_data.mCanResize = floaterp->isResizable();
+
+	// remove minimize and close buttons
+	floaterp->setCanMinimize(FALSE);
+	floaterp->setCanResize(FALSE);
+	floaterp->setCanDrag(FALSE);
+	floaterp->storeRectControl();
+	// avoid double rendering of floater background (makes it more opaque)
+	floaterp->setBackgroundVisible(FALSE);
+
+	if (mAutoResize)
+	{
+		growToFit(floater_data.mWidth, floater_data.mHeight);
+	}
+
+	//add the panel, add it to proper maps
+	mTabContainer->addTabPanel(
+		LLTabContainer::TabPanelParams()
+			.panel(floaterp)
+			.label(floaterp->getShortTitle())
+			.insert_at(insertion_point));
+	mFloaterDataMap[floaterp->getHandle()] = floater_data;
+
+	updateResizeLimits();
+
+	if ( select_added_floater )
+	{
+		mTabContainer->selectTabPanel(floaterp);
+	}
+	else
+	{
+		// reassert visible tab (hiding new floater if necessary)
+		mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
+	}
+
+	floaterp->setHost(this);
+	if (isMinimized())
+	{
+		floaterp->setVisible(FALSE);
+	}
+}
+
+/**
+	BOOL selectFloater(LLFloater* floaterp)
+
+	If the LLFloater pointed to by floaterp is hosted by this,
+	then its tab is selected and returns true.  Otherwise returns false.
+
+	Affects: mTabContainer
+**/
+BOOL LLMultiFloater::selectFloater(LLFloater* floaterp)
+{
+	return mTabContainer->selectTabPanel(floaterp);
+}
+
+// virtual
+void LLMultiFloater::selectNextFloater()
+{
+	mTabContainer->selectNextTab();
+}
+
+// virtual
+void LLMultiFloater::selectPrevFloater()
+{
+	mTabContainer->selectPrevTab();
+}
+
+void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point)
+{
+	// we won't select a panel that already is selected
+	// it is hard to do this internally to tab container
+	// as tab selection is handled via index and the tab at a given
+	// index might have changed
+	if (floaterp != mTabContainer->getCurrentPanel() &&
+		!mTabContainer->selectTabPanel(floaterp))
+	{
+		addFloater(floaterp, TRUE, insertion_point);
+	}
+}
+
+void LLMultiFloater::removeFloater(LLFloater* floaterp)
+{
+	if ( floaterp->getHost() != this )
+		return;
+
+	floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
+	if (found_data_it != mFloaterDataMap.end())
+	{
+		LLFloaterData& floater_data = found_data_it->second;
+		floaterp->setCanMinimize(floater_data.mCanMinimize);
+		if (!floater_data.mCanResize)
+		{
+			// restore original size
+			floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
+		}
+		floaterp->setCanResize(floater_data.mCanResize);
+		mFloaterDataMap.erase(found_data_it);
+	}
+	mTabContainer->removeTabPanel(floaterp);
+	floaterp->setBackgroundVisible(TRUE);
+	floaterp->setCanDrag(TRUE);
+	floaterp->setHost(NULL);
+	floaterp->applyRectControl();
+
+	updateResizeLimits();
+
+	tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
+}
+
+void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
+{
+	// default implementation does nothing
+}
+
+void LLMultiFloater::tabClose()
+{
+	if (mTabContainer->getTabCount() == 0)
+	{
+		// no more children, close myself
+		closeFloater();
+	}
+}
+
+void LLMultiFloater::setVisible(BOOL visible)
+{
+	// *FIX: shouldn't have to do this, fix adding to minimized multifloater
+	LLFloater::setVisible(visible);
+	
+	if (mTabContainer)
+	{
+		LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
+
+		if (cur_floaterp)
+		{
+			cur_floaterp->setVisible(visible);
+		}
+
+		// if no tab selected, and we're being shown,
+		// select last tab to be added
+		if (visible && !cur_floaterp)
+		{
+			mTabContainer->selectLastTab();
+		}
+	}
+}
+
+BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
+{
+	if (key == 'W' && mask == MASK_CONTROL)
+	{
+		LLFloater* floater = getActiveFloater();
+		// is user closeable and is system closeable
+		if (floater && floater->canClose() && floater->isCloseable())
+		{
+			floater->closeFloater();
+		}
+		return TRUE;
+	}
+
+	return LLFloater::handleKeyHere(key, mask);
+}
+
+bool LLMultiFloater::addChild(LLView* child, S32 tab_group)
+{
+	LLTabContainer* tab_container = dynamic_cast<LLTabContainer*>(child);
+	if (tab_container)
+	{
+		// store pointer to tab container
+		setTabContainer(tab_container);
+	}
+
+	// then go ahead and add child as usual
+	return LLFloater::addChild(child, tab_group);
+}
+
+LLFloater* LLMultiFloater::getActiveFloater()
+{
+	return (LLFloater*)mTabContainer->getCurrentPanel();
+}
+
+S32	LLMultiFloater::getFloaterCount()
+{
+	return mTabContainer->getTabCount();
+}
+
+/**
+	BOOL isFloaterFlashing(LLFloater* floaterp)
+
+	Returns true if the LLFloater pointed to by floaterp
+	is currently in a flashing state and is hosted by this.
+	False otherwise.
+
+	Requires: floaterp != NULL
+**/
+BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
+{
+	if ( floaterp && floaterp->getHost() == this )
+		return mTabContainer->getTabPanelFlashing(floaterp);
+
+	return FALSE;
+}
+
+/**
+	BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
+
+	Sets the current flashing state of the LLFloater pointed
+	to by floaterp to be the BOOL flashing if the LLFloater pointed
+	to by floaterp is hosted by this.
+
+	Requires: floaterp != NULL
+**/
+void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
+{
+	if ( floaterp && floaterp->getHost() == this )
+		mTabContainer->setTabPanelFlashing(floaterp, flashing);
+}
+
+void LLMultiFloater::onTabSelected()
+{
+	LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel());
+	if (floaterp)
+	{
+		tabOpen(floaterp, true);
+	}
+}
+
+void LLMultiFloater::setCanResize(BOOL can_resize)
+{
+	LLFloater::setCanResize(can_resize);
+	if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
+	{
+		mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
+	}
+	else
+	{
+		mTabContainer->setRightTabBtnOffset(0);
+	}
+}
+
+BOOL LLMultiFloater::postBuild()
+{
+	// remember any original xml minimum size
+	getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
+
+	if (mTabContainer)
+	{
+		return TRUE;
+	}
+
+	requires<LLTabContainer>("Preview Tabs");
+	if (checkRequirements())
+	{
+		mTabContainer = getChild<LLTabContainer>("Preview Tabs");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void LLMultiFloater::updateResizeLimits()
+{
+	static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
+	static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
+	S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
+	// initialize minimum size constraint to the original xml values.
+	S32 new_min_width = mOrigMinWidth;
+	S32 new_min_height = mOrigMinHeight;
+	// possibly increase minimum size constraint due to children's minimums.
+	for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
+	{
+		LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
+		if (floaterp)
+		{
+			new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
+			new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height);
+		}
+	}
+	setResizeLimits(new_min_width, new_min_height);
+
+	S32 cur_height = getRect().getHeight();
+	S32 new_width = llmax(getRect().getWidth(), new_min_width);
+	S32 new_height = llmax(getRect().getHeight(), new_min_height);
+
+	if (isMinimized())
+	{
+		const LLRect& expanded = getExpandedRect();
+		LLRect newrect;
+		newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height));
+		setExpandedRect(newrect);
+	}
+	else
+	{
+		reshape(new_width, new_height);
+
+		// make sure upper left corner doesn't move
+		translate(0, cur_height - getRect().getHeight());
+
+		// make sure this window is visible on screen when it has been modified
+		// (tab added, etc)
+		gFloaterView->adjustToFitScreen(this, TRUE);
+	}
+}
diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h
new file mode 100644
index 0000000000..ea8a9841e3
--- /dev/null
+++ b/indra/llui/llmultifloater.h
@@ -0,0 +1,107 @@
+/** 
+ * @file llmultifloater.h
+ * @brief LLFloater that hosts other floaters
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Floating "windows" within the GL display, like the inventory floater,
+// mini-map floater, etc.
+
+
+#ifndef LL_MULTI_FLOATER_H
+#define LL_MULTI_FLOATER_H
+
+#include "llfloater.h"
+#include "lltabcontainer.h" // for LLTabContainer::eInsertionPoint
+
+// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376
+class LLMultiFloater : public LLFloater
+{
+public:
+	LLMultiFloater(const LLFloater::Params& params = LLFloater::Params());
+	virtual ~LLMultiFloater() {};
+	
+	void buildTabContainer();
+	
+	virtual BOOL postBuild();
+	/*virtual*/ void onOpen(const LLSD& key);
+	/*virtual*/ void onClose(bool app_quitting);
+	/*virtual*/ void draw();
+	/*virtual*/ void setVisible(BOOL visible);
+	/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
+
+	virtual void setCanResize(BOOL can_resize);
+	virtual void growToFit(S32 content_width, S32 content_height);
+	virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
+
+	virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
+	virtual void removeFloater(LLFloater* floaterp);
+
+	virtual void tabOpen(LLFloater* opened_floater, bool from_click);
+	virtual void tabClose();
+
+	virtual BOOL selectFloater(LLFloater* floaterp);
+	virtual void selectNextFloater();
+	virtual void selectPrevFloater();
+
+	virtual LLFloater*	getActiveFloater();
+	virtual BOOL		isFloaterFlashing(LLFloater* floaterp);
+	virtual S32			getFloaterCount();
+
+	virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing);
+	virtual BOOL closeAllFloaters();	//Returns FALSE if the floater could not be closed due to pending confirmation dialogs
+	void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; }
+	void onTabSelected();
+
+	virtual void updateResizeLimits();
+
+protected:
+	struct LLFloaterData
+	{
+		S32		mWidth;
+		S32		mHeight;
+		BOOL	mCanMinimize;
+		BOOL	mCanResize;
+	};
+
+	LLTabContainer*		mTabContainer;
+	
+	typedef std::map<LLHandle<LLFloater>, LLFloaterData> floater_data_map_t;
+	floater_data_map_t	mFloaterDataMap;
+	
+	LLTabContainer::TabPosition mTabPos;
+	BOOL				mAutoResize;
+	S32					mOrigMinWidth, mOrigMinHeight;  // logically const but initialized late
+};
+
+#endif  // LL_MULTI_FLOATER_H
+
+
+
diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp
index c1487be553..24b83b0120 100644
--- a/indra/llui/llmultislider.cpp
+++ b/indra/llui/llmultislider.cpp
@@ -41,64 +41,59 @@
 #include "llkeyboard.h"			// for the MASK constants
 #include "llcontrol.h"
 #include "llimagegl.h"
+#include "lluictrlfactory.h"
 
 #include <sstream>
 
 static LLRegisterWidget<LLMultiSlider> r("multi_slider_bar");
 
-const S32 MULTI_THUMB_WIDTH = 8;
-const S32 MULTI_TRACK_HEIGHT = 6;
 const F32 FLOAT_THRESHOLD = 0.00001f;
-const S32 EXTRA_TRIANGLE_WIDTH = 2;
-const S32 EXTRA_TRIANGLE_HEIGHT = -2;
 
 S32 LLMultiSlider::mNameCounter = 0;
 
-LLMultiSlider::LLMultiSlider( 
-	const std::string& name,
-	const LLRect& rect,
-	void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
-	void* callback_userdata,
-	F32 initial_value,
-	F32 min_value,
-	F32 max_value,
-	F32 increment,
-	S32 max_sliders,
-	BOOL allow_overlap,
-	BOOL draw_track,
-	BOOL use_triangle,
-	const std::string& control_name)
-	:
-	LLUICtrl( name, rect, TRUE,	on_commit_callback, callback_userdata, 
-		FOLLOWS_LEFT | FOLLOWS_TOP),
-
-	mInitialValue( initial_value ),
-	mMinValue( min_value ),
-	mMaxValue( max_value ),
-	mIncrement( increment ),
-	mMaxNumSliders(max_sliders),
-	mAllowOverlap(allow_overlap),
-	mDrawTrack(draw_track),
-	mUseTriangle(use_triangle),
+LLMultiSlider::Params::Params()
+:	max_sliders("max_sliders", 1),
+	allow_overlap("allow_overlap", false),
+	draw_track("draw_track", true),
+	use_triangle("use_triangle", false),
+	track_color("track_color"),
+	thumb_disabled_color("thumb_disabled_color"),
+	thumb_outline_color("thumb_outline_color"),
+	thumb_center_color("thumb_center_color"),
+	thumb_center_selected_color("thumb_center_selected_color"),
+	triangle_color("triangle_color"),
+	mouse_down_callback("mouse_down_callback"),
+	mouse_up_callback("mouse_up_callback"),
+	thumb_width("thumb_width")
+{
+	name = "multi_slider_bar";
+	mouse_opaque(true);
+	follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+}
+
+LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p)
+:	LLF32UICtrl(p),
 	mMouseOffset( 0 ),
-	mDragStartThumbRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 ),
-	mTrackColor(		LLUI::sColorsGroup->getColor( "MultiSliderTrackColor" ) ),
-	mThumbOutlineColor(	LLUI::sColorsGroup->getColor( "MultiSliderThumbOutlineColor" ) ),
-	mThumbCenterColor(	LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterColor" ) ),
-	mThumbCenterSelectedColor(	LLUI::sColorsGroup->getColor( "MultiSliderThumbCenterSelectedColor" ) ),
-	mDisabledThumbColor(LLUI::sColorsGroup->getColor( "MultiSliderDisabledThumbColor" ) ),
-	mTriangleColor(LLUI::sColorsGroup->getColor( "MultiSliderTriangleColor" ) ),
-	mMouseDownCallback( NULL ),
-	mMouseUpCallback( NULL )
+	mDragStartThumbRect( 0, getRect().getHeight(), p.thumb_width, 0 ),
+	mMaxNumSliders(p.max_sliders),
+	mAllowOverlap(p.allow_overlap),
+	mDrawTrack(p.draw_track),
+	mUseTriangle(p.use_triangle),
+	mTrackColor(p.track_color()),
+	mThumbOutlineColor(p.thumb_outline_color()),
+	mThumbCenterColor(p.thumb_center_color()),
+	mThumbCenterSelectedColor(p.thumb_center_selected_color()),
+	mDisabledThumbColor(p.thumb_disabled_color()),
+	mTriangleColor(p.triangle_color()),
+	mThumbWidth(p.thumb_width)
 {
 	mValue.emptyMap();
 	mCurSlider = LLStringUtil::null;
-
-	// properly handle setting the starting thumb rect
-	// do it this way to handle both the operating-on-settings
-	// and standalone ways of using this
-	setControlName(control_name, NULL);
-	setValue(getValue());
+	
+	if (p.mouse_down_callback.isProvided())
+		initCommitCallback(p.mouse_down_callback, mMouseDownSignal);
+	if (p.mouse_up_callback.isProvided())
+		initCommitCallback(p.mouse_up_callback, mMouseUpSignal);
 }
 
 void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from_event)
@@ -152,12 +147,12 @@ void LLMultiSlider::setSliderValue(const std::string& name, F32 value, BOOL from
 	
 	F32 t = (newValue - mMinValue) / (mMaxValue - mMinValue);
 
-	S32 left_edge = MULTI_THUMB_WIDTH/2;
-	S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2);
+	S32 left_edge = mThumbWidth/2;
+	S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
 
 	S32 x = left_edge + S32( t * (right_edge - left_edge) );
-	mThumbRects[name].mLeft = x - (MULTI_THUMB_WIDTH/2);
-	mThumbRects[name].mRight = x + (MULTI_THUMB_WIDTH/2);
+	mThumbRects[name].mLeft = x - (mThumbWidth/2);
+	mThumbRects[name].mRight = x + (mThumbWidth/2);
 }
 
 void LLMultiSlider::setValue(const LLSD& value)
@@ -211,7 +206,7 @@ const std::string& LLMultiSlider::addSlider(F32 val)
 	}
 
 	// add a new thumb rect
-	mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), MULTI_THUMB_WIDTH, 0 );
+	mThumbRects[newName.str()] = LLRect( 0, getRect().getHeight(), mThumbWidth, 0 );
 
 	// add the value and set the current slider to this one
 	mValue.insert(newName.str(), initVal);
@@ -295,15 +290,15 @@ void LLMultiSlider::clear()
 		deleteCurSlider();
 	}
 
-	LLUICtrl::clear();
+	LLF32UICtrl::clear();
 }
 
 BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask)
 {
 	if( gFocusMgr.getMouseCapture() == this )
 	{
-		S32 left_edge = MULTI_THUMB_WIDTH/2;
-		S32 right_edge = getRect().getWidth() - (MULTI_THUMB_WIDTH/2);
+		S32 left_edge = mThumbWidth/2;
+		S32 right_edge = getRect().getWidth() - (mThumbWidth/2);
 
 		x += mMouseOffset;
 		x = llclamp( x, left_edge, right_edge );
@@ -331,10 +326,8 @@ BOOL LLMultiSlider::handleMouseUp(S32 x, S32 y, MASK mask)
 	{
 		gFocusMgr.setMouseCapture( NULL );
 
-		if( mMouseUpCallback )
-		{
-			mMouseUpCallback( this, mCallbackUserData );
-		}
+		mMouseUpSignal( this, LLSD() );
+
 		handled = TRUE;
 		make_ui_sound("UISndClickRelease");
 	}
@@ -353,10 +346,7 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
 	{
 		setFocus(TRUE);
 	}
-	if( mMouseDownCallback )
-	{
-		mMouseDownCallback( this, mCallbackUserData );
-	}
+	mMouseDownSignal( this, LLSD() );
 
 	if (MASK_CONTROL & mask) // if CTRL is modifying
 	{
@@ -379,7 +369,7 @@ BOOL LLMultiSlider::handleMouseDown(S32 x, S32 y, MASK mask)
 		// Find the offset of the actual mouse location from the center of the thumb.
 		if (mThumbRects[mCurSlider].pointInRect(x,y))
 		{
-			mMouseOffset = (mThumbRects[mCurSlider].mLeft + MULTI_THUMB_WIDTH/2) - x;
+			mMouseOffset = (mThumbRects[mCurSlider].mLeft + mThumbWidth/2) - x;
 		}
 		else
 		{
@@ -424,6 +414,8 @@ BOOL	LLMultiSlider::handleKeyHere(KEY key, MASK mask)
 
 void LLMultiSlider::draw()
 {
+	static LLUICachedControl<S32> extra_triangle_height ("UIExtraTriangleHeight", 0);
+	static LLUICachedControl<S32> extra_triangle_width ("UIExtraTriangleWidth", 0);
 	LLColor4 curThumbColor;
 
 	std::map<std::string, LLRect>::iterator mIt;
@@ -439,16 +431,17 @@ void LLMultiSlider::draw()
 	F32 opacity = getEnabled() ? 1.f : 0.3f;
 
 	// Track
-	LLUIImagePtr thumb_imagep = LLUI::sImageProvider->getUIImage("rounded_square.tga");
+	LLUIImagePtr thumb_imagep = LLUI::getUIImage("rounded_square.tga");
 
-	S32 height_offset = (getRect().getHeight() - MULTI_TRACK_HEIGHT) / 2;
+	static LLUICachedControl<S32> multi_track_height ("UIMultiTrackHeight", 0);
+	S32 height_offset = (getRect().getHeight() - multi_track_height) / 2;
 	LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset );
 
 
 	if(mDrawTrack)
 	{
 		track_rect.stretch(-1);
-		thumb_imagep->draw(track_rect, mTrackColor % opacity);
+		thumb_imagep->draw(track_rect, mTrackColor.get() % opacity);
 	}
 
 	// if we're supposed to use a drawn triangle
@@ -458,13 +451,13 @@ void LLMultiSlider::draw()
 		for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
 
 			gl_triangle_2d(
-				mIt->second.mLeft - EXTRA_TRIANGLE_WIDTH, 
-				mIt->second.mTop + EXTRA_TRIANGLE_HEIGHT,
-				mIt->second.mRight + EXTRA_TRIANGLE_WIDTH, 
-				mIt->second.mTop + EXTRA_TRIANGLE_HEIGHT,
+				mIt->second.mLeft - extra_triangle_width, 
+				mIt->second.mTop + extra_triangle_height,
+				mIt->second.mRight + extra_triangle_width, 
+				mIt->second.mTop + extra_triangle_height,
 				mIt->second.mLeft + mIt->second.getWidth() / 2, 
-				mIt->second.mBottom - EXTRA_TRIANGLE_HEIGHT,
-				mTriangleColor, TRUE);
+				mIt->second.mBottom - extra_triangle_height,
+				mTriangleColor.get(), TRUE);
 		}
 	}
 	else if (!thumb_imagep)
@@ -474,7 +467,7 @@ void LLMultiSlider::draw()
 		for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) {
 			
 			// choose the color
-			curThumbColor = mThumbCenterColor;
+			curThumbColor = mThumbCenterColor.get();
 			if(mIt->first == mCurSlider) {
 				
 				curSldrIt = mIt;
@@ -488,19 +481,19 @@ void LLMultiSlider::draw()
 
 		// now draw the current slider
 		if(curSldrIt != mThumbRects.end()) {
-			gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor, TRUE);
+			gl_rect_2d(curSldrIt->second, mThumbCenterSelectedColor.get(), TRUE);
 		}
 
 		// and draw the drag start
 		if (gFocusMgr.getMouseCapture() == this)
 		{
-			gl_rect_2d(mDragStartThumbRect, mThumbCenterColor % opacity, FALSE);
+			gl_rect_2d(mDragStartThumbRect, mThumbCenterColor.get() % opacity, FALSE);
 		}
 	}
 	else if( gFocusMgr.getMouseCapture() == this )
 	{
 		// draw drag start
-		thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor % 0.3f);
+		thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
 
 		// draw the highlight
 		if (hasFocus())
@@ -513,7 +506,7 @@ void LLMultiSlider::draw()
 		for(mIt = mThumbRects.begin(); mIt != mThumbRects.end(); mIt++) 
 		{
 			// choose the color
-			curThumbColor = mThumbCenterColor;
+			curThumbColor = mThumbCenterColor.get();
 			if(mIt->first == mCurSlider) 
 			{
 				// don't draw now, draw last
@@ -528,7 +521,7 @@ void LLMultiSlider::draw()
 		// draw cur slider last
 		if(curSldrIt != mThumbRects.end()) 
 		{
-			thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor);
+			thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get());
 		}
 		
 	}
@@ -546,7 +539,7 @@ void LLMultiSlider::draw()
 		{
 			
 			// choose the color
-			curThumbColor = mThumbCenterColor;
+			curThumbColor = mThumbCenterColor.get();
 			if(mIt->first == mCurSlider) 
 			{
 				curSldrIt = mIt;
@@ -559,74 +552,9 @@ void LLMultiSlider::draw()
 
 		if(curSldrIt != mThumbRects.end()) 
 		{
-			thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor % opacity);
+			thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity);
 		}
 	}
 
-	LLUICtrl::draw();
-}
-
-// virtual
-LLXMLNodePtr LLMultiSlider::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue());
-	node->createChild("min_val", TRUE)->setFloatValue(getMinValue());
-	node->createChild("max_val", TRUE)->setFloatValue(getMaxValue());
-	node->createChild("increment", TRUE)->setFloatValue(getIncrement());
-
-	return node;
-}
-
-
-//static
-LLView* LLMultiSlider::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("multi_slider_bar");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	F32 initial_value = 0.f;
-	node->getAttributeF32("initial_val", initial_value);
-
-	F32 min_value = 0.f;
-	node->getAttributeF32("min_val", min_value);
-
-	F32 max_value = 1.f; 
-	node->getAttributeF32("max_val", max_value);
-
-	F32 increment = 0.1f;
-	node->getAttributeF32("increment", increment);
-
-	S32 max_sliders = 1;
-	node->getAttributeS32("max_sliders", max_sliders);
-
-	BOOL allow_overlap = FALSE;
-	node->getAttributeBOOL("allow_overlap", allow_overlap);
-
-	BOOL draw_track = TRUE;
-	node->getAttributeBOOL("draw_track", draw_track);
-
-	BOOL use_triangle = FALSE;
-	node->getAttributeBOOL("use_triangle", use_triangle);
-
-	LLMultiSlider* multiSlider = new LLMultiSlider(name,
-							rect,
-							NULL,
-							NULL,
-							initial_value,
-							min_value,
-							max_value,
-							increment,
-							max_sliders,
-							allow_overlap,
-							draw_track,
-							use_triangle);
-
-	multiSlider->initFromXML(node, parent);
-
-	return multiSlider;
+	LLF32UICtrl::draw();
 }
diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h
index cdbdb597f9..9c01b528a7 100644
--- a/indra/llui/llmultislider.h
+++ b/indra/llui/llmultislider.h
@@ -33,32 +33,40 @@
 #ifndef LL_MULTI_SLIDER_H
 #define LL_MULTI_SLIDER_H
 
-#include "lluictrl.h"
+#include "llf32uictrl.h"
 #include "v4color.h"
 
 class LLUICtrlFactory;
 
-class LLMultiSlider : public LLUICtrl
+class LLMultiSlider : public LLF32UICtrl
 {
 public:
-	LLMultiSlider( 
-		const std::string& name,
-		const LLRect& rect,
-		void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
-		void* callback_userdata,
-		F32 initial_value,
-		F32 min_value,
-		F32 max_value,
-		F32 increment,
-		S32 max_sliders,
-		BOOL allow_overlap,
-		BOOL draw_track,
-		BOOL use_triangle,
-		const std::string& control_name = LLStringUtil::null );
-
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static  LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
+	{
+		Optional<S32>	max_sliders;
 
+		Optional<bool>	allow_overlap,
+						draw_track,
+						use_triangle;
+
+		Optional<LLUIColor>	track_color,
+							thumb_disabled_color,
+							thumb_outline_color,
+							thumb_center_color,
+							thumb_center_selected_color,
+							triangle_color;
+
+		Optional<CommitCallbackParam>	mouse_down_callback,
+										mouse_up_callback;
+		Optional<S32>		thumb_width;
+
+		Params();
+	};
+
+protected:
+	LLMultiSlider(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	void			setSliderValue(const std::string& name, F32 value, BOOL from_event = FALSE);
 	F32				getSliderValue(const std::string& name) const;
 
@@ -67,41 +75,27 @@ public:
 	void			setCurSlider(const std::string& name);
 	void			setCurSliderValue(F32 val, BOOL from_event = false) { setSliderValue(mCurSlider, val, from_event); }
 
-	virtual void	setValue(const LLSD& value);
-	virtual LLSD	getValue() const		{ return mValue; }
-
-	virtual void	setMinValue(LLSD min_value)	{ setMinValue((F32)min_value.asReal()); }
-	virtual void	setMaxValue(LLSD max_value)	{ setMaxValue((F32)max_value.asReal());  }
+	/*virtual*/ void	setValue(const LLSD& value);
+	/*virtual*/ LLSD	getValue() const		{ return mValue; }
 
-	F32				getInitialValue() const { return mInitialValue; }
-	F32				getMinValue() const		{ return mMinValue; }
-	F32				getMaxValue() const		{ return mMaxValue; }
-	F32				getIncrement() const	{ return mIncrement; }
-	void			setMinValue(F32 min_value) { mMinValue = min_value; }
-	void			setMaxValue(F32 max_value) { mMaxValue = max_value; }
-	void			setIncrement(F32 increment) { mIncrement = increment; }
-	void			setMouseDownCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseDownCallback = cb; }
-	void			setMouseUpCallback(	void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseUpCallback = cb; }
+	boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ) { return mMouseDownSignal.connect(cb); }
+	boost::signals::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb )   { return mMouseUpSignal.connect(cb); }
 
-	bool findUnusedValue(F32& initVal);
+	bool			findUnusedValue(F32& initVal);
 	const std::string&	addSlider();
 	const std::string&	addSlider(F32 val);
 	void			deleteSlider(const std::string& name);
 	void			deleteCurSlider()			{ deleteSlider(mCurSlider); }
 	void			clear();
 
-	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleKeyHere(KEY key, MASK mask);
-	virtual void	draw();
+	/*virtual*/ BOOL	handleHover(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask);
+	/*virtual*/ void	draw();
 
 protected:
 	LLSD			mValue;
-	F32				mInitialValue;
-	F32				mMinValue;
-	F32				mMaxValue;
-	F32				mIncrement;
 	std::string		mCurSlider;
 	static S32		mNameCounter;
 
@@ -112,17 +106,18 @@ protected:
 
 	S32				mMouseOffset;
 	LLRect			mDragStartThumbRect;
+	S32				mThumbWidth;
 
 	std::map<std::string, LLRect>	mThumbRects;
-	LLColor4		mTrackColor;
-	LLColor4		mThumbOutlineColor;
-	LLColor4		mThumbCenterColor;
-	LLColor4		mThumbCenterSelectedColor;
-	LLColor4		mDisabledThumbColor;
-	LLColor4		mTriangleColor;
+	LLUIColor		mTrackColor;
+	LLUIColor		mThumbOutlineColor;
+	LLUIColor		mThumbCenterColor;
+	LLUIColor		mThumbCenterSelectedColor;
+	LLUIColor		mDisabledThumbColor;
+	LLUIColor		mTriangleColor;
 	
-	void			(*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
-	void			(*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
+	commit_signal_t	mMouseDownSignal;
+	commit_signal_t	mMouseUpSignal;
 };
 
 #endif  // LL_LLSLIDER_H
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index 8bcf9f9b76..14584e6df5 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -50,90 +50,100 @@
 #include "llcontrol.h"
 #include "llfocusmgr.h"
 #include "llresmgr.h"
+#include "lluictrlfactory.h"
 
 static LLRegisterWidget<LLMultiSliderCtrl> r("multi_slider");
 
 const U32 MAX_STRING_LENGTH = 10;
-
+LLMultiSliderCtrl::Params::Params()
+:	text_width("text_width"),
+	label_width("label_width"),
+	show_text("show_text", true),
+	can_edit_text("can_edit_text", false),
+	max_sliders("max_sliders", 1),
+	allow_overlap("allow_overlap", false),
+	draw_track("draw_track", true),
+	use_triangle("use_triangle", false),
+	decimal_digits("decimal_digits", 3),
+	text_color("text_color"),
+	text_disabled_color("text_disabled_color"),
+	mouse_down_callback("mouse_down_callback"),
+	mouse_up_callback("mouse_up_callback")
+{
+	mouse_opaque = true;
+}
  
-LLMultiSliderCtrl::LLMultiSliderCtrl(const std::string& name, const LLRect& rect, 
-						   const std::string& label,
-						   const LLFontGL* font,
-						   S32 label_width,
-						   S32 text_left,
-						   BOOL show_text,
-						   BOOL can_edit_text,
-						   void (*commit_callback)(LLUICtrl*, void*),
-						   void* callback_user_data,
-						   F32 initial_value, F32 min_value, F32 max_value, F32 increment,
-						   S32 max_sliders, BOOL allow_overlap,
-						   BOOL draw_track,
-						   BOOL use_triangle,
-						   const std::string& control_which)
-	: LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data ),
-	  mFont(font),
-	  mShowText( show_text ),
-	  mCanEditText( can_edit_text ),
-	  mPrecision( 3 ),
-	  mLabelBox( NULL ),
-	  mLabelWidth( label_width ),
-
-	  mEditor( NULL ),
-	  mTextBox( NULL ),
-	  mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
-	  mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
-	  mSliderMouseUpCallback( NULL ),
-	  mSliderMouseDownCallback( NULL )
+LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
+:	LLF32UICtrl(p),
+	mLabelBox( NULL ),
+	mEditor( NULL ),
+	mTextBox( NULL ),
+	mTextEnabledColor(p.text_color()),
+	mTextDisabledColor(p.text_disabled_color())
 {
+	static LLUICachedControl<S32> multi_sliderctrl_spacing ("UIMultiSliderctrlSpacing", 0);
+
 	S32 top = getRect().getHeight();
 	S32 bottom = 0;
 	S32 left = 0;
 
+	S32 label_width = p.label_width;
+	S32 text_width = p.text_width;
+
 	// Label
-	if( !label.empty() )
+	if( !p.label().empty() )
 	{
-		if (label_width == 0)
+		if (p.label_width == 0)
 		{
-			label_width = font->getWidth(label);
+			label_width = p.font()->getWidth(p.label);
 		}
 		LLRect label_rect( left, top, label_width, bottom );
-		mLabelBox = new LLTextBox( std::string("MultiSliderCtrl Label"), label_rect, label, font );
+		LLTextBox::Params params;
+		params.name("MultiSliderCtrl Label");
+		params.rect(label_rect);
+		params.text(p.label);
+		params.font(p.font);
+		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild(mLabelBox);
 	}
 
 	S32 slider_right = getRect().getWidth();
-	if( show_text )
-	{
-		slider_right = text_left - MULTI_SLIDERCTRL_SPACING;
-	}
 
-	S32 slider_left = label_width ? label_width + MULTI_SLIDERCTRL_SPACING : 0;
-	LLRect slider_rect( slider_left, top, slider_right, bottom );
-	mMultiSlider = new LLMultiSlider( 
-		std::string("multi_slider"),
-		slider_rect, 
-		LLMultiSliderCtrl::onSliderCommit, this, 
-		initial_value, min_value, max_value, increment,
-		max_sliders, allow_overlap, draw_track,
-		use_triangle,
-		control_which );
-	addChild( mMultiSlider );
-	mCurValue = mMultiSlider->getCurSliderValue();
-	
-	if( show_text )
+	if (p.show_text)
 	{
+		if (!p.text_width.isProvided())
+		{
+			text_width = 0;
+			// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
+			if ( p.max_value() )
+				text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10  ( p.max_value ) ) + p.decimal_digits + 1 );
+
+			if ( p.increment < 1.0f )
+				text_width += p.font()->getWidth(std::string("."));	// (mostly) take account of decimal point in value
+
+			if ( p.min_value < 0.0f || p.max_value < 0.0f )
+				text_width += p.font()->getWidth(std::string("-"));	// (mostly) take account of minus sign 
+
+			// padding to make things look nicer
+			text_width += 8;
+		}
+		S32 text_left = getRect().getWidth() - text_width;
+
+		slider_right = text_left - multi_sliderctrl_spacing;
+
 		LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
-		if( can_edit_text )
+		if( p.can_edit_text )
 		{
-			mEditor = new LLLineEditor( std::string("MultiSliderCtrl Editor"), text_rect,
-				LLStringUtil::null, font,
-				MAX_STRING_LENGTH,
-				&LLMultiSliderCtrl::onEditorCommit, NULL, NULL, this,
-				&LLLineEditor::prevalidateFloat );
-			mEditor->setFollowsLeft();
-			mEditor->setFollowsBottom();
+			LLLineEditor::Params params;
+			params.name("MultiSliderCtrl Editor");
+			params.rect(text_rect);
+			params.font(p.font);
+			params.max_length_bytes(MAX_STRING_LENGTH);
+			params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
+			params.prevalidate_callback(&LLLineEditor::prevalidateFloat);
+			params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+			mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
 			mEditor->setFocusReceivedCallback( &LLMultiSliderCtrl::onEditorGainFocus );
-			mEditor->setIgnoreTab(TRUE);
 			// don't do this, as selecting the entire text is single clicking in some cases
 			// and double clicking in others
 			//mEditor->setSelectAllonFocusReceived(TRUE);
@@ -141,13 +151,37 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const std::string& name, const LLRect& rect
 		}
 		else
 		{
-			mTextBox = new LLTextBox( std::string("MultiSliderCtrl Text"), text_rect,	LLStringUtil::null,	font);
-			mTextBox->setFollowsLeft();
-			mTextBox->setFollowsBottom();
+			LLTextBox::Params params;
+			params.name("MultiSliderCtrl Text");
+			params.rect(text_rect);
+			params.font(p.font);
+			params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+			mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
 			addChild(mTextBox);
 		}
 	}
 
+	S32 slider_left = label_width ? label_width + multi_sliderctrl_spacing : 0;
+	LLRect slider_rect( slider_left, top, slider_right, bottom );
+	LLMultiSlider::Params params;
+	params.rect(slider_rect);
+	params.commit_callback.function( LLMultiSliderCtrl::onSliderCommit );
+	params.mouse_down_callback( p.mouse_down_callback );
+	params.mouse_up_callback( p.mouse_up_callback );
+	params.initial_value(p.initial_value());
+	params.min_value(p.min_value);
+	params.max_value(p.max_value);
+	params.increment(p.increment);
+	params.max_sliders(p.max_sliders);
+	params.allow_overlap(p.allow_overlap);
+	params.draw_track(p.draw_track);
+	params.use_triangle(p.use_triangle);
+	params.control_name(p.control_name);
+	mMultiSlider = LLUICtrlFactory::create<LLMultiSlider> (params);
+	addChild( mMultiSlider );
+	mCurValue = mMultiSlider->getCurSliderValue();
+
+
 	updateText();
 }
 
@@ -203,7 +237,8 @@ BOOL LLMultiSliderCtrl::setLabelArg( const std::string& key, const LLStringExpli
 			S32 delta = rect.mRight - prev_right;
 			rect = mMultiSlider->getRect();
 			S32 left = rect.mLeft + delta;
-			left = llclamp(left, 0, rect.mRight-MULTI_SLIDERCTRL_SPACING);
+			static LLUICachedControl<S32> multi_slider_ctrl_spacing ("UIMultiSliderctrlSpacing", 0);
+			left = llclamp(left, 0, rect.mRight - multi_slider_ctrl_spacing);
 			rect.mLeft = left;
 			mMultiSlider->setRect(rect);
 		}
@@ -294,11 +329,12 @@ void LLMultiSliderCtrl::updateText()
 }
 
 // static
-void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
+void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata)
 {
-	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
-	llassert( caller == self->mEditor );
-
+	LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl);
+	if (!ctrl)
+		return;
+	
 	BOOL success = FALSE;
 	F32 val = self->mCurValue;
 	F32 saved_val = self->mCurValue;
@@ -310,17 +346,9 @@ void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
 		val = (F32) atof( text.c_str() );
 		if( self->mMultiSlider->getMinValue() <= val && val <= self->mMultiSlider->getMaxValue() )
 		{
-			if( self->mValidateCallback )
-			{
-				self->setCurSliderValue( val );  // set the value temporarily so that the callback can retrieve it.
-				if( self->mValidateCallback( self, self->mCallbackUserData ) )
-				{
-					success = TRUE;
-				}
-			}
-			else
+			self->setCurSliderValue( val );  // set the value temporarily so that the callback can retrieve it.
+			if( self->mValidateSignal( self, val ) )
 			{
-				self->setCurSliderValue( val );
 				success = TRUE;
 			}
 		}
@@ -342,26 +370,19 @@ void LLMultiSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
 }
 
 // static
-void LLMultiSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata )
+void LLMultiSliderCtrl::onSliderCommit(LLUICtrl* ctrl, const LLSD& userdata)
 {
-	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
-	//llassert( caller == self->mSlider );
-
+	LLMultiSliderCtrl* self = dynamic_cast<LLMultiSliderCtrl*>(ctrl);
+	if (!self)
+		return;
+	
 	BOOL success = FALSE;
 	F32 saved_val = self->mCurValue;
 	F32 new_val = self->mMultiSlider->getCurSliderValue();
 
-	if( self->mValidateCallback )
+	self->mCurValue = new_val;  // set the value temporarily so that the callback can retrieve it.
+	if( self->mValidateSignal( self, new_val ) )
 	{
-		self->mCurValue = new_val;  // set the value temporarily so that the callback can retrieve it.
-		if( self->mValidateCallback( self, self->mCallbackUserData ) )
-		{
-			success = TRUE;
-		}
-	}
-	else
-	{
-		self->mCurValue = new_val;
 		success = TRUE;
 	}
 
@@ -382,11 +403,11 @@ void LLMultiSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata )
 
 void LLMultiSliderCtrl::setEnabled(BOOL b)
 {
-	LLUICtrl::setEnabled( b );
+	LLF32UICtrl::setEnabled( b );
 
 	if( mLabelBox )
 	{
-		mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
+		mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
 	}
 
 	mMultiSlider->setEnabled( b );
@@ -398,7 +419,7 @@ void LLMultiSliderCtrl::setEnabled(BOOL b)
 
 	if( mTextBox )
 	{
-		mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
+		mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
 	}
 }
 
@@ -409,7 +430,7 @@ void LLMultiSliderCtrl::setTentative(BOOL b)
 	{
 		mEditor->setTentative(b);
 	}
-	LLUICtrl::setTentative(b);
+	LLF32UICtrl::setTentative(b);
 }
 
 
@@ -422,7 +443,8 @@ void LLMultiSliderCtrl::onCommit()
 		mEditor->setTentative(FALSE);
 	}
 
-	LLUICtrl::onCommit();
+	setControlValue(getValueF32());
+	LLF32UICtrl::onCommit();
 }
 
 
@@ -438,37 +460,14 @@ void LLMultiSliderCtrl::setPrecision(S32 precision)
 	updateText();
 }
 
-void LLMultiSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) )
-{
-	mSliderMouseDownCallback = slider_mousedown_callback;
-	mMultiSlider->setMouseDownCallback( LLMultiSliderCtrl::onSliderMouseDown );
-}
-
-// static
-void LLMultiSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
+boost::signals::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
 {
-	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
-	if( self->mSliderMouseDownCallback )
-	{
-		self->mSliderMouseDownCallback( self, self->mCallbackUserData );
-	}
+	return mMultiSlider->setMouseDownCallback( cb );
 }
 
-
-void LLMultiSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) )
+boost::signals::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
 {
-	mSliderMouseUpCallback = slider_mouseup_callback;
-	mMultiSlider->setMouseUpCallback( LLMultiSliderCtrl::onSliderMouseUp );
-}
-
-// static
-void LLMultiSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
-{
-	LLMultiSliderCtrl* self = (LLMultiSliderCtrl*) userdata;
-	if( self->mSliderMouseUpCallback )
-	{
-		self->mSliderMouseUpCallback( self, self->mCallbackUserData );
-	}
+	return mMultiSlider->setMouseUpCallback( cb );
 }
 
 void LLMultiSliderCtrl::onTabInto()
@@ -484,154 +483,9 @@ void LLMultiSliderCtrl::reportInvalidData()
 	make_ui_sound("UISndBadKeystroke");
 }
 
-//virtual
-std::string LLMultiSliderCtrl::getControlName() const
-{
-	return mMultiSlider->getControlName();
-}
-
 // virtual
 void LLMultiSliderCtrl::setControlName(const std::string& control_name, LLView* context)
 {
 	mMultiSlider->setControlName(control_name, context);
 }
 
-// virtual
-LLXMLNodePtr LLMultiSliderCtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("show_text", TRUE)->setBoolValue(mShowText);
-
-	node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText);
-
-	node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
-
-	if (mLabelBox)
-	{
-		node->createChild("label", TRUE)->setStringValue(mLabelBox->getText());
-	}
-
-	// TomY TODO: Do we really want to export the transient state of the slider?
-	node->createChild("value", TRUE)->setFloatValue(mCurValue);
-
-	if (mMultiSlider)
-	{
-		node->createChild("initial_val", TRUE)->setFloatValue(mMultiSlider->getInitialValue());
-		node->createChild("min_val", TRUE)->setFloatValue(mMultiSlider->getMinValue());
-		node->createChild("max_val", TRUE)->setFloatValue(mMultiSlider->getMaxValue());
-		node->createChild("increment", TRUE)->setFloatValue(mMultiSlider->getIncrement());
-	}
-	addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
-	addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
-
-	return node;
-}
-
-LLView* LLMultiSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("multi_slider");
-	node->getAttributeString("name", name);
-
-	std::string label;
-	node->getAttributeString("label", label);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	LLFontGL* font = LLView::selectFont(node);
-
-	// HACK: Font might not be specified.
-	if (!font)
-	{
-		font = LLFontGL::getFontSansSerifSmall();
-	}
-
-	S32 label_width = 0;
-	node->getAttributeS32("label_width", label_width);
-
-	BOOL show_text = TRUE;
-	node->getAttributeBOOL("show_text", show_text);
-
-	BOOL can_edit_text = FALSE;
-	node->getAttributeBOOL("can_edit_text", can_edit_text);
-	
-	BOOL allow_overlap = FALSE;
-	node->getAttributeBOOL("allow_overlap", allow_overlap);
-
-	BOOL draw_track = TRUE;
-	node->getAttributeBOOL("draw_track", draw_track);
-
-	BOOL use_triangle = FALSE;
-	node->getAttributeBOOL("use_triangle", use_triangle);
-
-	F32 initial_value = 0.f;
-	node->getAttributeF32("initial_val", initial_value);
-
-	F32 min_value = 0.f;
-	node->getAttributeF32("min_val", min_value);
-
-	F32 max_value = 1.f; 
-	node->getAttributeF32("max_val", max_value);
-
-	F32 increment = 0.1f;
-	node->getAttributeF32("increment", increment);
-
-	U32 precision = 3;
-	node->getAttributeU32("decimal_digits", precision);
-
-	S32 max_sliders = 1;
-	node->getAttributeS32("max_sliders", max_sliders);
-
-
-	S32 text_left = 0;
-	if (show_text)
-	{
-		// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
-		if ( max_value )
-			text_left = font->getWidth(std::string("0")) * ( static_cast < S32 > ( log10  ( max_value ) ) + precision + 1 );
-
-		if ( increment < 1.0f )
-			text_left += font->getWidth(std::string("."));	// (mostly) take account of decimal point in value
-
-		if ( min_value < 0.0f || max_value < 0.0f )
-			text_left += font->getWidth(std::string("-"));	// (mostly) take account of minus sign 
-
-		// padding to make things look nicer
-		text_left += 8;
-	}
-
-	LLUICtrlCallback callback = NULL;
-
-	if (label.empty())
-	{
-		label.assign(node->getTextContents());
-	}
-
-	LLMultiSliderCtrl* slider = new LLMultiSliderCtrl(name,
-							rect,
-							label,
-							font,
-							label_width,
-							rect.getWidth() - text_left,
-							show_text,
-							can_edit_text,
-							callback,
-							NULL,
-							initial_value,
-							min_value, 
-							max_value,
-							increment,
-							max_sliders,
-							allow_overlap,
-							draw_track,
-							use_triangle);
-
-	slider->setPrecision(precision);
-
-	slider->initFromXML(node, parent);
-
-	slider->updateText();
-	
-	return slider;
-}
diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h
index b62b5ec323..85ba77b7df 100644
--- a/indra/llui/llmultisliderctrl.h
+++ b/indra/llui/llmultisliderctrl.h
@@ -33,17 +33,12 @@
 #ifndef LL_MULTI_SLIDERCTRL_H
 #define LL_MULTI_SLIDERCTRL_H
 
-#include "lluictrl.h"
+#include "llf32uictrl.h"
 #include "v4color.h"
 #include "llmultislider.h"
 #include "lltextbox.h"
 #include "llrect.h"
 
-//
-// Constants
-//
-const S32	MULTI_SLIDERCTRL_SPACING	=  4;			// space between label, slider, and text
-const S32	MULTI_SLIDERCTRL_HEIGHT		=  16;
 
 //
 // Classes
@@ -53,27 +48,35 @@ class LLLineEditor;
 class LLSlider;
 
 
-class LLMultiSliderCtrl : public LLUICtrl
+class LLMultiSliderCtrl : public LLF32UICtrl
 {
 public:
-	LLMultiSliderCtrl(const std::string& name, 
-		const LLRect& rect, 
-		const std::string& label, 
-		const LLFontGL* font,
-		S32 slider_left,
-		S32 text_left,
-		BOOL show_text,
-		BOOL can_edit_text,
-		void (*commit_callback)(LLUICtrl*, void*),
-		void* callback_userdata,
-		F32 initial_value, F32 min_value, F32 max_value, F32 increment,
-		S32 max_sliders, BOOL allow_overlap, BOOL draw_track,
-		BOOL use_triangle,
-		const std::string& control_which = LLStringUtil::null );
-
+	struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
+	{
+		Optional<S32>			label_width,
+								text_width;
+		Optional<bool>			show_text,
+								can_edit_text;
+		Optional<S32>			decimal_digits;
+		Optional<S32>			max_sliders;	
+		Optional<bool>			allow_overlap,
+								draw_track,
+								use_triangle;
+
+		Optional<LLUIColor>		text_color,
+								text_disabled_color;
+
+		Optional<CommitCallbackParam>	mouse_down_callback,
+										mouse_up_callback;
+
+		Params();
+	};
+
+protected:
+	LLMultiSliderCtrl(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual ~LLMultiSliderCtrl();
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
 
 	F32				getSliderValue(const std::string& name) const;
 	void			setSliderValue(const std::string& name, F32 v, BOOL from_event = FALSE);
@@ -112,8 +115,8 @@ public:
 	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
 	void			setDisabledLabelColor(const LLColor4& c)	{ mTextDisabledColor = c; }
 
-	void			setSliderMouseDownCallback(	void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) );
-	void			setSliderMouseUpCallback(	void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) );
+	boost::signals::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
+	boost::signals::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
 
 	virtual void	onTabInto();
 
@@ -121,13 +124,10 @@ public:
 	virtual void	onCommit();						// mark not tentative, then commit
 
 	virtual void		setControlName(const std::string& control_name, LLView* context);
-	virtual std::string 	getControlName() const;
 	
-	static void		onSliderCommit(LLUICtrl* caller, void* userdata);
-	static void		onSliderMouseDown(LLUICtrl* caller,void* userdata);
-	static void		onSliderMouseUp(LLUICtrl* caller,void* userdata);
-
-	static void		onEditorCommit(LLUICtrl* caller, void* userdata);
+	static void		onSliderCommit(LLUICtrl* caller, const LLSD& userdata);
+	
+	static void		onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata);
 	static void		onEditorGainFocus(LLFocusableElement* caller, void *userdata);
 	static void		onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
 
@@ -149,11 +149,8 @@ private:
 	LLLineEditor*	mEditor;
 	LLTextBox*		mTextBox;
 
-	LLColor4		mTextEnabledColor;
-	LLColor4		mTextDisabledColor;
-
-	void			(*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
-	void			(*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
+	LLUIColor	mTextEnabledColor;
+	LLUIColor	mTextDisabledColor;
 };
 
 #endif  // LL_MULTI_SLIDERCTRL_H
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 2ae96726af..34ff21268e 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -31,11 +31,14 @@
 */
 
 #include "linden_common.h"
+
+#include "llnotifications.h"
+
+#include "lluictrl.h"
 #include "lluictrlfactory.h"
 #include "lldir.h"
 #include "llsdserialize.h"
-
-#include "llnotifications.h"
+#include "lltrans.h"
 
 #include <algorithm>
 #include <boost/regex.hpp>
@@ -161,7 +164,7 @@ bool filterIgnoredNotifications(LLNotificationPtr notification)
 	// Check to see if the user wants to ignore this alert
 	if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
 	{
-		return LLUI::sConfigGroup->getWarning(notification->getName());
+		return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName());
 	}
 
 	return true;
@@ -182,7 +185,7 @@ bool handleIgnoredNotification(const LLSD& payload)
 			response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
 			break;
 		case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
-			response = LLUI::sIgnoresGroup->getLLSD("Default" + pNotif->getName());
+			response = LLUI::sSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName());
 			break;
 		case LLNotificationForm::IGNORE_SHOW_AGAIN:
 			break;
@@ -240,10 +243,11 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodeP
 			{
 				// remember last option chosen by user and automatically respond with that in the future
 				mIgnore = IGNORE_WITH_LAST_RESPONSE;
-				LLUI::sIgnoresGroup->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
+				LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
 			}
 			child->getAttributeString("text", mIgnoreMsg);
-			LLUI::sIgnoresGroup->addWarning(name);
+			BOOL show_notification = TRUE;
+			LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
 		}
 		else
 		{
@@ -339,13 +343,13 @@ void LLNotificationForm::formatElements(const LLSD& substitutions)
 		if ((*it).has("text"))
 		{
 			std::string text = (*it)["text"].asString();
-			text = LLNotification::format(text, substitutions);
+			LLStringUtil::format(text, substitutions);
 			(*it)["text"] = text;
 		}
 		if ((*it)["type"].asString() == "text" && (*it).has("value"))
 		{
 			std::string value = (*it)["value"].asString();
-			value = LLNotification::format(value, substitutions);
+			LLStringUtil::format(value, substitutions);
 			(*it)["value"] = value;
 		}
 	}
@@ -366,6 +370,7 @@ LLNotificationTemplate::LLNotificationTemplate() :
 	mExpireSeconds(0),
 	mExpireOption(-1),
 	mURLOption(-1),
+    mURLOpenExternally(-1),
 	mUnique(false),
 	mPriority(NOTIFICATION_PRIORITY_NORMAL)
 {
@@ -377,13 +382,24 @@ LLNotification::LLNotification(const LLNotification::Params& p) :
 	mSubstitutions(p.substitutions),
 	mPayload(p.payload),
 	mExpiresAt(0),
-	mResponseFunctorName(p.functor_name),
-	mTemporaryResponder(p.mTemporaryResponder),
+	mTemporaryResponder(false),
 	mRespondedTo(false),
 	mPriority(p.priority),
 	mCancelled(false),
 	mIgnored(false)
 {
+	if (p.functor.name.isChosen())
+	{
+		mResponseFunctorName = p.functor.name;
+	}
+	else if (p.functor.function.isChosen())
+	{
+		mResponseFunctorName = LLUUID::generateNewID().asString();
+		LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function());
+
+		mTemporaryResponder = true;
+	}
+
 	mId.generate();
 	init(p.name, p.form_elements);
 }
@@ -525,7 +541,8 @@ std::string LLNotification::getSelectedOptionName(const LLSD& response)
 void LLNotification::respond(const LLSD& response)
 {
 	mRespondedTo = true;
-	LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName)(asLLSD(), response);
+	LLNotificationResponder func = LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
+	func(asLLSD(), response);
 	if (mTemporaryResponder)
 	{
 		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
@@ -535,10 +552,11 @@ void LLNotification::respond(const LLSD& response)
 
 	if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
 	{
-		LLUI::sIgnoresGroup->setWarning(getName(), !mIgnored);
+		BOOL show_notification = mIgnored ? FALSE : TRUE;
+		LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification);
 		if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
 		{
-			LLUI::sIgnoresGroup->setLLSD("Default" + getName(), response);
+			LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
 		}
 	}
 
@@ -596,8 +614,12 @@ void LLNotification::init(const std::string& template_name, const LLSD& form_ele
 	if (!mTemplatep) return;
 
 	// add default substitutions
-	// TODO: change this to read from the translatable strings file!
-	mSubstitutions["SECOND_LIFE"] = "Second Life";
+	const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs();
+	for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin();
+		 iter != default_args.end(); ++iter)
+	{
+		mSubstitutions[iter->first] = iter->second;
+	}
 	mSubstitutions["_URL"] = getURL();
 	mSubstitutions["_NAME"] = template_name;
 	// TODO: something like this so that a missing alert is sensible:
@@ -631,64 +653,6 @@ std::string LLNotification::summarize() const
 	return s;
 }
 
-//static
-std::string LLNotification::format(const std::string& s, const LLSD& substitutions)
-{
-	if (!substitutions.isMap()) 
-	{
-		return s;
-	}
-
-	std::ostringstream output;
-	// match strings like [NAME]
-	const boost::regex key("\\[([0-9_A-Z]+)]");
-	
-	std::string::const_iterator start = s.begin();
-	std::string::const_iterator end = s.end();
-	boost::smatch match;
-	
-	while (boost::regex_search(start, end, match, key, boost::match_default))
-	{
-		bool found_replacement = false;
-		std::string replacement;
-		
-		// see if we have a replacement for the bracketed string (without the brackets)
-		// test first using has() because if we just look up with operator[] we get back an
-		// empty string even if the value is missing. We want to distinguish between 
-		// missing replacements and deliberately empty replacement strings.
-		if (substitutions.has(std::string(match[1].first, match[1].second)))
-		{
-			replacement = substitutions[std::string(match[1].first, match[1].second)].asString();
-			found_replacement = true;
-		}
-		// if not, see if there's one WITH brackets
-		else if (substitutions.has(std::string(match[0].first, match[0].second)))
-		{
-			replacement = substitutions[std::string(match[0].first, match[0].second)].asString();
-			found_replacement = true;
-		}
-		
-		if (found_replacement)
-		{
-			// found a replacement
-			// "hello world" is output
-			output << std::string(start, match[0].first) << replacement;
-		}
-		else
-		{
-			// we had no replacement, so leave the string we searched for so that it gets noticed by QA
-			// "hello [NAME_NOT_FOUND]" is output
-			output << std::string(start, match[0].second);
-		}
-		
-		// update search position 
-		start = match[0].second; 
-	}
-	// send the remainder of the string (with no further matches for bracketed names)
-	output << std::string(start, end);
-	return output.str();
-}
-
 std::string LLNotification::getMessage() const
 {
 	// all our callers cache this result, so it gives us more flexibility
@@ -696,15 +660,27 @@ std::string LLNotification::getMessage() const
 	// cache it in the notification
 	if (!mTemplatep)
 		return std::string();
-	return format(mTemplatep->mMessage, mSubstitutions);
+
+	std::string message = mTemplatep->mMessage;
+	LLStringUtil::format(message, mSubstitutions);
+	return message;
 }
 
 std::string LLNotification::getLabel() const
 {
-	return (mTemplatep ? format(mTemplatep->mLabel, mSubstitutions) : "");
+	std::string label = mTemplatep->mLabel;
+	LLStringUtil::format(label, mSubstitutions);
+	return (mTemplatep ? label : "");
 }
 
-
+std::string LLNotification::getURL() const
+{
+	if (!mTemplatep)
+		return std::string();
+	std::string url = mTemplatep->mURL;
+	LLStringUtil::format(url, mSubstitutions);
+	return (mTemplatep ? url : "");
+}
 
 // =========================================================
 // LLNotificationChannel implementation
@@ -948,6 +924,7 @@ std::string LLNotificationChannel::summarize()
 LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
 															   LLNotificationComparators::orderByUUID())
 {
+	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
 }
 
 
@@ -1097,9 +1074,6 @@ void LLNotifications::createDefaultChannels()
 		connectFailedFilter(&handleIgnoredNotification);
 }
 
-static std::string sStringSkipNextTime("Skip this dialog next time");
-static std::string sStringAlwaysChoose("Always choose this option");
-
 bool LLNotifications::addTemplate(const std::string &name, 
 								  LLNotificationTemplatePtr theTemplate)
 {
@@ -1320,8 +1294,17 @@ bool LLNotifications::loadTemplates()
 		item->getAttributeString("sound", sound);
 		if (!sound.empty())
 		{
-			// TODO: test for bad sound effect name / missing effect
-			pTemplate->mSoundEffect = LLUUID(LLUI::sConfigGroup->getString(sound.c_str()));
+			// test for bad sound effect name / missing effect
+			if (LLUI::sSettingGroups["config"]->controlExists(sound))
+			{
+				pTemplate->mSoundEffect = 
+					LLUUID(LLUI::sSettingGroups["config"]->getString(sound));
+			}
+			else
+			{
+				llwarns << "Unknown sound effect control name " << sound
+					<< llendl;
+			}
 		}
 
 		for (LLXMLNodePtr child = item->getFirstChild();
@@ -1334,6 +1317,7 @@ bool LLNotifications::loadTemplates()
 			{
 				pTemplate->mURL = child->getTextContents();
 				child->getAttributeU32("option", pTemplate->mURLOption);
+				child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
 			}
 			
             if (child->hasName("unique"))
@@ -1373,12 +1357,20 @@ bool LLNotifications::loadTemplates()
 	return true;
 }
 
+// Add a simple notification (from XUI)
+void LLNotifications::addFromCallback(const LLSD& name)
+{
+	add(LLNotification::Params().name(name.asString()));	
+}
+
 // we provide a couple of simple add notification functions so that it's reasonable to create notifications in one line
 LLNotificationPtr LLNotifications::add(const std::string& name, 
 										const LLSD& substitutions, 
 										const LLSD& payload)
 {
-	return add(LLNotification::Params(name).substitutions(substitutions).payload(payload));	
+	LLNotification::Params::Functor functor_p;
+	functor_p.name = name;
+	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
 }
 
 LLNotificationPtr LLNotifications::add(const std::string& name, 
@@ -1386,7 +1378,9 @@ LLNotificationPtr LLNotifications::add(const std::string& name,
 										const LLSD& payload, 
 										const std::string& functor_name)
 {
-	return add(LLNotification::Params(name).substitutions(substitutions).payload(payload).functor_name(functor_name));	
+	LLNotification::Params::Functor functor_p;
+	functor_p.name = functor_name;
+	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
 }
 
 LLNotificationPtr LLNotifications::add(const std::string& name, 
@@ -1394,7 +1388,9 @@ LLNotificationPtr LLNotifications::add(const std::string& name,
 										const LLSD& payload, 
 										LLNotificationFunctorRegistry::ResponseFunctor functor)
 {
-	return add(LLNotification::Params(name).substitutions(substitutions).payload(payload).functor(functor));	
+	LLNotification::Params::Functor functor_p;
+	functor_p.function = functor;
+	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
 }
 
 // generalized add function that takes a parameter block object for more complex instantiations
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index bb379121cc..de86f5daa2 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -100,6 +100,7 @@
 // and we need this to manage the notification callbacks
 #include "llfunctorregistry.h"
 #include "llui.h"
+#include "llmemory.h"
 
 class LLNotification;
 typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
@@ -280,6 +281,11 @@ struct LLNotificationTemplate
     // that URL. Obsolete this and eliminate the buttons for affected
     // messages when we allow clickable URLs in the UI
     U32 mURLOption;
+	
+	U32 mURLOpenExternally;
+	//This is a flag that tells if the url needs to open externally dispite 
+	//what the user setting is.
+	
 	// does this notification persist across sessions? if so, it will be
 	// serialized to disk on first receipt and read on startup
 	bool mPersist;
@@ -322,42 +328,49 @@ friend class LLNotifications;
 
 public:
 	// parameter object used to instantiate a new notification
-	class Params : public LLParamBlock<Params>
+	struct Params : public LLInitParam::Block<Params>
 	{
 		friend class LLNotification;
-	public:
-		Params(const std::string& _name) 
-			:	name(_name),
-				mTemporaryResponder(false),
-				functor_name(_name),
-				priority(NOTIFICATION_PRIORITY_UNSPECIFIED),
-				timestamp(LLDate::now())
+	
+		Mandatory<std::string>					name;
+
+		// optional
+		Optional<LLSD>							substitutions;
+		Optional<LLSD>							payload;
+		Optional<ENotificationPriority>			priority;
+		Optional<LLSD>							form_elements;
+		Optional<LLDate>						timestamp;
+		Optional<LLNotificationContext*>		context;
+
+		struct Functor : public LLInitParam::Choice<Functor>
 		{
+			Option<std::string>										name;
+			Option<LLNotificationFunctorRegistry::ResponseFunctor>	function;
+
+			Functor()
+			:	name("functor_name"),
+				function("functor")
+			{}
+		};
+		Optional<Functor>						functor;
+
+		Params()
+		:	name("name"),
+			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+			timestamp("time_stamp")
+		{
+			timestamp = LLDate::now();
 		}
 
-		// pseudo-param
-		Params& functor(LLNotificationFunctorRegistry::ResponseFunctor f) 
-		{ 	
-			functor_name = LLUUID::generateNewID().asString();
-			LLNotificationFunctorRegistry::instance().registerFunctor(functor_name, f);
-
-			mTemporaryResponder = true;
-			return *this;
+		Params(const std::string& _name) 
+			:	name("name"),
+				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+				timestamp("time_stamp")
+		{
+			functor.name = _name;
+			name = _name;
+			timestamp = LLDate::now();
 		}
-
-		LLMandatoryParam<std::string>					name;
-
-		// optional
-		LLOptionalParam<LLSD>							substitutions;
-		LLOptionalParam<LLSD>							payload;
-		LLOptionalParam<ENotificationPriority>			priority;
-		LLOptionalParam<LLSD>							form_elements;
-		LLOptionalParam<LLDate>							timestamp;
-		LLOptionalParam<LLNotificationContext*>			context;
-		LLOptionalParam<std::string>					functor_name;
-
-	private:
-		bool					mTemporaryResponder;
 	};
 
 private:
@@ -410,10 +423,6 @@ public:
 	// constructor from a saved notification
 	LLNotification(const LLSD& sd);
 
-	// This is a string formatter for substituting into the message directly 
-	// from LLSD without going through the hopefully-to-be-obsoleted LLString
-	static std::string format(const std::string& text, const LLSD& substitutions);
-
 	void setResponseFunctor(std::string const &responseFunctorName);
 
 	typedef enum e_response_template_type
@@ -505,16 +514,21 @@ public:
 	std::string getMessage() const;
 	std::string getLabel() const;
 
-	std::string getURL() const
-	{
-		return (mTemplatep ? mTemplatep->mURL : "");
-	}
+	std::string getURL() const;
+//	{
+//		return (mTemplatep ? mTemplatep->mURL : "");
+//	}
 
 	S32 getURLOption() const
 	{
 		return (mTemplatep ? mTemplatep->mURLOption : -1);
 	}
-
+    
+	S32 getURLOpenExternally() const
+	{
+		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
+	}
+	
 	const LLNotificationFormPtr getForm();
 
 	const LLDate getExpiration() const
@@ -813,7 +827,10 @@ public:
 	// OK to call more than once because it will reload
 	bool loadTemplates();  
 	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
-
+	
+	// Add a simple notification (from XUI)
+	void addFromCallback(const LLSD& name);
+	
 	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
 	LLNotificationPtr add(const std::string& name, 
 						const LLSD& substitutions = LLSD(), 
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 92d045d114..35871dc078 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -54,74 +54,47 @@
 #include "lluictrlfactory.h"
 #include "llviewborder.h"
 #include "llbutton.h"
+#include "lltabcontainer.h"
 
-// LLLayoutStack
-#include "llresizebar.h"
-#include "llcriticaldamp.h"
+static LLRegisterWidget<LLPanel> r1("panel", &LLPanel::fromXML);
 
-const S32 RESIZE_BAR_OVERLAP = 1;
-const S32 RESIZE_BAR_HEIGHT = 3;
-
-static LLRegisterWidget<LLPanel> r1("panel");
-
-void LLPanel::init()
+LLPanel::Params::Params()
+:	has_border("border", false),
+	bg_opaque_color("bg_opaque_color"),
+	bg_alpha_color("bg_alpha_color"),
+	background_visible("background_visible", false),
+	background_opaque("background_opaque", false),
+	min_width("min_width", 100),
+	min_height("min_height", 100),
+	strings("string"),
+	filename("filename")
 {
-	// mRectControl
-	mBgColorAlpha        = LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" );
-	mBgColorOpaque       = LLUI::sColorsGroup->getColor( "FocusBackgroundColor" );
-	mDefaultBtnHighlight = LLUI::sColorsGroup->getColor( "DefaultHighlightLight" );
-	mBgVisible = FALSE;
-	mBgOpaque = FALSE;
-	mBorder = NULL;
-	mDefaultBtn = NULL;
-	setIsChrome(FALSE); //is this a decorator to a live window or a form?
-	mLastTabGroup = 0;
-
-	mPanelHandle.bind(this);
-	setTabStop(FALSE);
+	name = "panel";
+	addSynonym(background_visible, "bg_visible");
+	addSynonym(has_border, "border_visible");
+	addSynonym(label, "title");
 }
 
-LLPanel::LLPanel()
-: mRectControl()
-{
-	init();
-	setName(std::string("panel"));
-}
 
-LLPanel::LLPanel(const std::string& name)
-:	LLUICtrl(name, LLRect(0, 0, 0, 0), TRUE, NULL, NULL),
-	mRectControl()
+LLPanel::LLPanel(const LLPanel::Params& p)
+:	LLUICtrl(p),
+	mBgColorAlpha(p.bg_alpha_color().get()),
+	mBgColorOpaque(p.bg_opaque_color().get()),
+	mBgVisible(p.background_visible),
+	mBgOpaque(p.background_opaque),
+	mDefaultBtn(NULL),
+	mBorder(NULL),
+	mLabel(p.label),
+	mCommitCallbackRegistrar(false)
 {
-	init();
-}
-
-
-LLPanel::LLPanel(const std::string& name, const LLRect& rect, BOOL bordered)
-:	LLUICtrl(name, rect, TRUE, NULL, NULL),
-	mRectControl()
-{
-	init();
-	if (bordered)
-	{
-		addBorder();
-	}
-}
+	setIsChrome(FALSE);
 
-
-LLPanel::LLPanel(const std::string& name, const std::string& rect_control, BOOL bordered)
-:	LLUICtrl(name, LLUI::sConfigGroup->getRect(rect_control), TRUE, NULL, NULL),
-	mRectControl( rect_control )
-{
-	init();
-	if (bordered)
+	if (p.has_border)
 	{
-		addBorder();
+		addBorder(p.border);
 	}
-}
-
-LLPanel::~LLPanel()
-{
-	storeRectControl();
+	
+	mPanelHandle.bind(this);
 }
 
 // virtual
@@ -130,27 +103,23 @@ BOOL LLPanel::isPanel() const
 	return TRUE;
 }
 
-// virtual
-BOOL LLPanel::postBuild()
-{
-	return TRUE;
-}
-
-void LLPanel::addBorder(LLViewBorder::EBevel border_bevel,
-						LLViewBorder::EStyle border_style, S32 border_thickness)
+void LLPanel::addBorder(LLViewBorder::Params p)
 {
 	removeBorder();
-	mBorder = new LLViewBorder( std::string("panel border"), 
-								LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), 
-								border_bevel, border_style, border_thickness );
-	mBorder->setSaveToXML(false);
+	p.rect = getLocalRect();
+
+	mBorder = LLUICtrlFactory::create<LLViewBorder>(p);
 	addChild( mBorder );
 }
 
 void LLPanel::removeBorder()
 {
-	delete mBorder;
-	mBorder = NULL;
+	if (mBorder)
+	{
+		removeChild(mBorder);
+		delete mBorder;
+		mBorder = NULL;
+	}
 }
 
 
@@ -258,20 +227,6 @@ void LLPanel::setDefaultBtn(const std::string& id)
 	}
 }
 
-void LLPanel::addCtrl( LLUICtrl* ctrl, S32 tab_group)
-{
-	mLastTabGroup = tab_group;
-
-	LLView::addCtrl(ctrl, tab_group);
-}
-
-void LLPanel::addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group)
-{
-	mLastTabGroup = tab_group;
-
-	LLView::addCtrlAtEnd(ctrl, tab_group);
-}
-
 BOOL LLPanel::handleKeyHere( KEY key, MASK mask )
 {
 	BOOL handled = FALSE;
@@ -364,12 +319,10 @@ void LLPanel::setFocus(BOOL b)
 	{
 		if (!gFocusMgr.childHasKeyboardFocus(this))
 		{
-			//refresh();
-			if (!focusFirstItem())
-			{
-				LLUICtrl::setFocus(TRUE);
-			}
-			onFocusReceived();
+			// give ourselves focus preemptively, to avoid infinite loop
+			LLUICtrl::setFocus(TRUE);
+			// then try to pass to first valid child
+			focusFirstItem();
 		}
 	}
 	else
@@ -399,191 +352,135 @@ void LLPanel::setBorderVisible(BOOL b)
 	}
 }
 
-// virtual
-LLXMLNodePtr LLPanel::getXML(bool save_children) const
+LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_node)
 {
-	LLXMLNodePtr node = LLView::getXML();
+	std::string name("panel");
+	node->getAttributeString("name", name);
 
-	if (mBorder && mBorder->getVisible())
-	{
-		node->createChild("border", TRUE)->setBoolValue(TRUE);
-	}
+	LLPanel* panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name); 
 
-	if (!mRectControl.empty())
+	// factory panels may have registered their own factory maps
+	if (!panelp->getFactoryMap().empty())
 	{
-		node->createChild("rect_control", TRUE)->setStringValue(mRectControl);
+		LLUICtrlFactory::instance().pushFactoryFunctions(&panelp->getFactoryMap());
 	}
+	panelp->mCommitCallbackRegistrar.pushScope(); // for local registry callbacks; define in constructor, referenced in XUI or postBuild
 
-	if (!mLabel.empty())
-	{
-		node->createChild("label", TRUE)->setStringValue(mLabel);
-	}
+	panelp->initPanelXML(node, parent, output_node);
+	
+	panelp->mCommitCallbackRegistrar.popScope();
 
-	if (save_children)
+	if (panelp && !panelp->getFactoryMap().empty())
 	{
-		LLView::child_list_const_reverse_iter_t rit;
-		for (rit = getChildList()->rbegin(); rit != getChildList()->rend(); ++rit)
-		{
-			LLView* childp = *rit;
-
-			if (childp->getSaveToXML())
-			{
-				LLXMLNodePtr xml_node = childp->getXML();
-
-				node->addChild(xml_node);
-			}
-		}
+		LLUICtrlFactory::instance().popFactoryFunctions();
 	}
 
-	return node;
+	return panelp;
 }
 
-LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *factory)
+void LLPanel::initFromParams(const LLPanel::Params& p)
 {
-	std::string name("panel");
-	node->getAttributeString("name", name);
+	 // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
+	LLUICtrl::initFromParams(p);
 
-	LLPanel* panelp = factory->createFactoryPanel(name);
-	// Fall back on a default panel, if there was no special factory.
-	if (!panelp)
-	{
-		LLRect rect;
-		createRect(node, rect, parent, LLRect());
-		// create a new panel without a border, by default
-		panelp = new LLPanel(name, rect, FALSE);
-		panelp->initPanelXML(node, parent, factory);
-		// preserve panel's width and height, but override the location
-		const LLRect& panelrect = panelp->getRect();
-		S32 w = panelrect.getWidth();
-		S32 h = panelrect.getHeight();
-		rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
-		panelp->setRect(rect);
-	}
-	else
+	for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings().begin();
+		it != p.strings().end();
+		++it)
 	{
-		panelp->initPanelXML(node, parent, factory);
+		mUIStrings[it->name] = it->text;
 	}
 
-	return panelp;
-}
-
-BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name = getName();
-	node->getAttributeString("name", name);
-	setName(name);
-
-	setPanelParameters(node, parent);
+	setName(p.name());
+	setLabel(p.label());
 
-	initChildrenXML(node, factory);
+	setShape(p.rect);
+	parseFollowsFlags(p);
 
-	std::string xml_filename;
-	node->getAttributeString("filename", xml_filename);
-
-	BOOL didPost;
-
-	if (!xml_filename.empty())
+	setEnabled(p.enabled);
+	setVisible(p.visible);
+	setToolTip(p.tool_tip());
+	setSaveToXML(p.serializable);
+	
+	mHoverCursor = getCursorFromString(p.hover_cursor);
+	
+	if (p.has_border)
 	{
-		didPost = factory->buildPanel(this, xml_filename, NULL);
-
-		LLRect new_rect = getRect();
-		// override rectangle with embedding parameters as provided
-		createRect(node, new_rect, parent);
-		setOrigin(new_rect.mLeft, new_rect.mBottom);
-		reshape(new_rect.getWidth(), new_rect.getHeight());
-		// optionally override follows flags from including nodes
-		parseFollowsFlags(node);
+		addBorder(p.border);
 	}
-	else
+	// let constructors set this value if not provided
+	if (p.use_bounding_rect.isProvided())
 	{
-		didPost = FALSE;
+		setUseBoundingRect(p.use_bounding_rect);
 	}
+	setDefaultTabGroup(p.default_tab_group);
+	setMouseOpaque(p.mouse_opaque);
+	
+	setBackgroundVisible(p.background_visible);
+	setBackgroundOpaque(p.background_opaque);
+	setBackgroundColor(p.bg_opaque_color().get());
+	setTransparentColor(p.bg_alpha_color().get());
 	
-	if (!didPost)
-	{
-		postBuild();
-		didPost = TRUE;
-	}
-
-	return didPost;
 }
 
-void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory)
+BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
 {
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+	const LLPanel::Params& default_params(LLUICtrlFactory::getDefaultParams<LLPanel::Params>());
+	Params params(default_params);
+
+	LLXMLNodePtr referenced_xml;
+	std::string xml_filename;
+	node->getAttributeString("filename", xml_filename);
+
+	if (!xml_filename.empty())
 	{
-		// look for string declarations for programmatic text
-		if (child->hasName("string"))
+		if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
 		{
-			std::string string_name;
-			child->getAttributeString("name", string_name);
-			if (!string_name.empty())
-			{
-				mUIStrings[string_name] = child->getTextContents();
-			}
-		}
-		else
-		{
-			factory->createWidget(this, child);
+			llwarns << "Couldn't parse panel from: " << xml_filename << llendl;
+
+			return FALSE;
 		}
-	}
-}
 
-void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
-{
-	/////// Rect, follows, tool_tip, enabled, visible attributes ///////
-	initFromXML(node, parent);
+		LLXUIParser::instance().readXUI(referenced_xml, params);
 
-	/////// Border attributes ///////
-	BOOL border = mBorder != NULL;
-	node->getAttributeBOOL("border", border);
-	if (border)
-	{
-		LLViewBorder::EBevel bevel_style = LLViewBorder::BEVEL_OUT;
-		LLViewBorder::getBevelFromAttribute(node, bevel_style);
+		// add children using dimensions from referenced xml for consistent layout
+		setShape(params.rect);
+		addChildren(referenced_xml);
+	}
 
-		LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE;
-		std::string border_string;
-		node->getAttributeString("border_style", border_string);
-		LLStringUtil::toLower(border_string);
+	LLXUIParser::instance().readXUI(node, params);
 
-		if (border_string == "texture")
-		{
-			border_style = LLViewBorder::STYLE_TEXTURE;
-		}
+	if (output_node)
+	{
+		Params output_params(params);
+		setupParamsForExport(output_params, parent);
+		output_node->setName(node->getName()->mString);
+		LLXUIParser::instance().writeXUI(
+			output_node, output_params, &default_params);
+	}
+	
+	setupParams(params, parent);
+	initFromParams(params);
 
-		S32 border_thickness = LLPANEL_BORDER_WIDTH;
-		node->getAttributeS32("border_thickness", border_thickness);
+	// add children
+	addChildren(node, output_node);
 
-		addBorder(bevel_style, border_style, border_thickness);
-	}
-	else
+	// Connect to parent after children are built, because tab containers
+	// do a reshape() on their child panels, which requires that the children
+	// be built/added. JC
+	if (parent)
 	{
-		removeBorder();
+		S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
+		parent->addChild(this, tab_group);
 	}
 
-	/////// Background attributes ///////
-	BOOL background_visible = mBgVisible;
-	node->getAttributeBOOL("background_visible", background_visible);
-	setBackgroundVisible(background_visible);
-	
-	BOOL background_opaque = mBgOpaque;
-	node->getAttributeBOOL("background_opaque", background_opaque);
-	setBackgroundOpaque(background_opaque);
-
-	LLColor4 color;
-	color = mBgColorOpaque;
-	LLUICtrlFactory::getAttributeColor(node,"bg_opaque_color", color);
-	setBackgroundColor(color);
-
-	color = mBgColorAlpha;
-	LLUICtrlFactory::getAttributeColor(node,"bg_alpha_color", color);
-	setTransparentColor(color);
-
-	std::string label = getLabel();
-	node->getAttributeString("label", label);
-	setLabel(label);
+	postBuild();
+
+	return TRUE;
+}
+
+bool LLPanel::hasString(const std::string& name)
+{
+	return mUIStrings.find(name) != mUIStrings.end();
 }
 
 std::string LLPanel::getString(const std::string& name, const LLStringUtil::format_map_t& args) const
@@ -597,9 +494,7 @@ std::string LLPanel::getString(const std::string& name, const LLStringUtil::form
 		return formatted_string.getString();
 	}
 	std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate
-	// *TODO: once the QAR-369 ui-cleanup work on settings is in we need to change the following line to be
-	//if(LLUI::sConfigGroup->getBOOL("QAMode"))
-	if(LLUI::sQAMode)
+	if(LLUI::sSettingGroups["config"]->getBOOL("QAMode"))
 	{
 		llerrs << err_str << llendl;
 	}
@@ -618,7 +513,7 @@ std::string LLPanel::getString(const std::string& name) const
 		return found_it->second;
 	}
 	std::string err_str("Failed to find string " + name + " in panel " + getName()); //*TODO: Translate
-	if(LLUI::sQAMode)
+	if(LLUI::sSettingGroups["config"]->getBOOL("QAMode"))
 	{
 		llerrs << err_str << llendl;
 	}
@@ -632,7 +527,7 @@ std::string LLPanel::getString(const std::string& name) const
 
 void LLPanel::childSetVisible(const std::string& id, bool visible)
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		child->setVisible(visible);
@@ -641,7 +536,7 @@ void LLPanel::childSetVisible(const std::string& id, bool visible)
 
 bool LLPanel::childIsVisible(const std::string& id) const
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		return (bool)child->getVisible();
@@ -651,7 +546,7 @@ bool LLPanel::childIsVisible(const std::string& id) const
 
 void LLPanel::childSetEnabled(const std::string& id, bool enabled)
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		child->setEnabled(enabled);
@@ -660,7 +555,7 @@ void LLPanel::childSetEnabled(const std::string& id, bool enabled)
 
 void LLPanel::childSetTentative(const std::string& id, bool tentative)
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		child->setTentative(tentative);
@@ -669,7 +564,7 @@ void LLPanel::childSetTentative(const std::string& id, bool tentative)
 
 bool LLPanel::childIsEnabled(const std::string& id) const
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		return (bool)child->getEnabled();
@@ -680,7 +575,7 @@ bool LLPanel::childIsEnabled(const std::string& id) const
 
 void LLPanel::childSetToolTip(const std::string& id, const std::string& msg)
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		child->setToolTip(msg);
@@ -689,7 +584,7 @@ void LLPanel::childSetToolTip(const std::string& id, const std::string& msg)
 
 void LLPanel::childSetRect(const std::string& id, const LLRect& rect)
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		child->setRect(rect);
@@ -698,7 +593,7 @@ void LLPanel::childSetRect(const std::string& id, const LLRect& rect)
 
 bool LLPanel::childGetRect(const std::string& id, LLRect& rect) const
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		rect = child->getRect();
@@ -709,7 +604,7 @@ bool LLPanel::childGetRect(const std::string& id, LLRect& rect) const
 
 void LLPanel::childSetFocus(const std::string& id, BOOL focus)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		child->setFocus(focus);
@@ -718,7 +613,7 @@ void LLPanel::childSetFocus(const std::string& id, BOOL focus)
 
 BOOL LLPanel::childHasFocus(const std::string& id)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		return child->hasFocus();
@@ -730,60 +625,28 @@ BOOL LLPanel::childHasFocus(const std::string& id)
 	}
 }
 
-
-void LLPanel::childSetFocusChangedCallback(const std::string& id, void (*cb)(LLFocusableElement*, void*), void* user_data)
-{
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
-	if (child)
-	{
-		child->setFocusChangedCallback(cb, user_data);
-	}
-}
-
-void LLPanel::childSetCommitCallback(const std::string& id, void (*cb)(LLUICtrl*, void*), void *userdata )
-{
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
-	if (child)
-	{
-		child->setCommitCallback(cb);
-		child->setCallbackUserData(userdata);
-	}
-}
-
-void LLPanel::childSetDoubleClickCallback(const std::string& id, void (*cb)(void*), void *userdata )
+// *TODO: Deprecate; for backwards compatability only:
+void LLPanel::childSetCommitCallback(const std::string& id, boost::function<void (LLUICtrl*,void*)> cb, void* data)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
-		child->setDoubleClickCallback(cb);
-		if (userdata)
-		{
-			child->setCallbackUserData(userdata);
-		}
+		child->setCommitCallback(boost::bind(cb, child, data));
 	}
 }
 
-void LLPanel::childSetValidate(const std::string& id, BOOL (*cb)(LLUICtrl*, void*))
+void LLPanel::childSetValidate(const std::string& id, boost::function<bool (const LLSD& data)> cb)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		child->setValidateBeforeCommit(cb);
 	}
 }
 
-void LLPanel::childSetUserData(const std::string& id, void* userdata)
-{
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
-	if (child)
-	{
-		child->setCallbackUserData(userdata);
-	}
-}
-
 void LLPanel::childSetColor(const std::string& id, const LLColor4& color)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		child->setColor(color);
@@ -792,7 +655,7 @@ void LLPanel::childSetColor(const std::string& id, const LLColor4& color)
 
 LLCtrlSelectionInterface* LLPanel::childGetSelectionInterface(const std::string& id) const
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		return child->getSelectionInterface();
@@ -802,7 +665,7 @@ LLCtrlSelectionInterface* LLPanel::childGetSelectionInterface(const std::string&
 
 LLCtrlListInterface* LLPanel::childGetListInterface(const std::string& id) const
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		return child->getListInterface();
@@ -812,7 +675,7 @@ LLCtrlListInterface* LLPanel::childGetListInterface(const std::string& id) const
 
 LLCtrlScrollInterface* LLPanel::childGetScrollInterface(const std::string& id) const
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		return child->getScrollInterface();
@@ -822,7 +685,7 @@ LLCtrlScrollInterface* LLPanel::childGetScrollInterface(const std::string& id) c
 
 void LLPanel::childSetValue(const std::string& id, LLSD value)
 {
-	LLView* child = getChild<LLView>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		child->setValue(value);
@@ -831,7 +694,7 @@ void LLPanel::childSetValue(const std::string& id, LLSD value)
 
 LLSD LLPanel::childGetValue(const std::string& id) const
 {
-	LLView* child = getChild<LLView>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		return child->getValue();
@@ -842,7 +705,7 @@ LLSD LLPanel::childGetValue(const std::string& id) const
 
 BOOL LLPanel::childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		return child->setTextArg(key, text);
@@ -852,7 +715,7 @@ BOOL LLPanel::childSetTextArg(const std::string& id, const std::string& key, con
 
 BOOL LLPanel::childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text)
 {
-	LLView* child = getChild<LLView>(id);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		return child->setLabelArg(key, text);
@@ -862,7 +725,7 @@ BOOL LLPanel::childSetLabelArg(const std::string& id, const std::string& key, co
 
 BOOL LLPanel::childSetToolTipArg(const std::string& id, const std::string& key, const LLStringExplicit& text)
 {
-	LLView* child = getChildView(id, true, FALSE);
+	LLView* child = findChild<LLView>(id);
 	if (child)
 	{
 		return child->setToolTipArg(key, text);
@@ -872,7 +735,7 @@ BOOL LLPanel::childSetToolTipArg(const std::string& id, const std::string& key,
 
 void LLPanel::childSetMinValue(const std::string& id, LLSD min_value)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		child->setMinValue(min_value);
@@ -881,7 +744,7 @@ void LLPanel::childSetMinValue(const std::string& id, LLSD min_value)
 
 void LLPanel::childSetMaxValue(const std::string& id, LLSD max_value)
 {
-	LLUICtrl* child = getChild<LLUICtrl>(id, true);
+	LLUICtrl* child = findChild<LLUICtrl>(id);
 	if (child)
 	{
 		child->setMaxValue(max_value);
@@ -890,7 +753,7 @@ void LLPanel::childSetMaxValue(const std::string& id, LLSD max_value)
 
 void LLPanel::childShowTab(const std::string& id, const std::string& tabname, bool visible)
 {
-	LLTabContainer* child = getChild<LLTabContainer>(id);
+	LLTabContainer* child = findChild<LLTabContainer>(id);
 	if (child)
 	{
 		child->selectTabByName(tabname);
@@ -899,7 +762,7 @@ void LLPanel::childShowTab(const std::string& id, const std::string& tabname, bo
 
 LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const
 {
-	LLTabContainer* child = getChild<LLTabContainer>(id);
+	LLTabContainer* child = findChild<LLTabContainer>(id);
 	if (child)
 	{
 		return child->getCurrentPanel();
@@ -907,40 +770,9 @@ LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const
 	return NULL;
 }
 
-void LLPanel::childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool))
-{
-	LLTabContainer* child = getChild<LLTabContainer>(id);
-	if (child)
-	{
-		LLPanel *panel = child->getPanelByName(tabname);
-		if (panel)
-		{
-			child->setTabChangeCallback(panel, on_tab_clicked);
-			child->setTabUserData(panel, userdata);
-			if (on_precommit)
-			{
-				child->setTabPrecommitChangeCallback(panel, on_precommit);
-			}
-		}
-	}
-}
-
-void LLPanel::childSetKeystrokeCallback(const std::string& id, void (*keystroke_callback)(LLLineEditor* caller, void* user_data), void *user_data)
-{
-	LLLineEditor* child = getChild<LLLineEditor>(id);
-	if (child)
-	{
-		child->setKeystrokeCallback(keystroke_callback);
-		if (user_data)
-		{
-			child->setCallbackUserData(user_data);
-		}
-	}
-}
-
 void LLPanel::childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWString &) )
 {
-	LLLineEditor* child = getChild<LLLineEditor>(id);
+	LLLineEditor* child = findChild<LLLineEditor>(id);
 	if (child)
 	{
 		child->setPrevalidate(func);
@@ -949,7 +781,7 @@ void LLPanel::childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWS
 
 void LLPanel::childSetWrappedText(const std::string& id, const std::string& text, bool visible)
 {
-	LLTextBox* child = getChild<LLTextBox>(id);
+	LLTextBox* child = findChild<LLTextBox>(id);
 	if (child)
 	{
 		child->setVisible(visible);
@@ -957,18 +789,18 @@ void LLPanel::childSetWrappedText(const std::string& id, const std::string& text
 	}
 }
 
-void LLPanel::childSetAction(const std::string& id, void(*function)(void*), void* value)
+void LLPanel::childSetAction(const std::string& id, boost::function<void(void*)> function, void* value)
 {
-	LLButton* button = getChild<LLButton>(id);
+	LLButton* button = findChild<LLButton>(id);
 	if (button)
 	{
-		button->setClickedCallback(function, value);
+		button->setClickedCallback(boost::bind(function, value));
 	}
 }
 
 void LLPanel::childSetActionTextbox(const std::string& id, void(*function)(void*), void* value)
 {
-	LLTextBox* textbox = getChild<LLTextBox>(id);
+	LLTextBox* textbox = findChild<LLTextBox>(id);
 	if (textbox)
 	{
 		textbox->setClickedCallback(function, value);
@@ -977,7 +809,7 @@ void LLPanel::childSetActionTextbox(const std::string& id, void(*function)(void*
 
 void LLPanel::childSetControlName(const std::string& id, const std::string& control_name)
 {
-	LLView* view = getChild<LLView>(id);
+	LLUICtrl* view = findChild<LLUICtrl>(id);
 	if (view)
 	{
 		view->setControlName(control_name, NULL);
@@ -995,7 +827,11 @@ LLView* LLPanel::getChildView(const std::string& name, BOOL recurse, BOOL create
 	}
 	if (!view && create_if_missing)
 	{
-		view = createDummyWidget<LLView>(name);
+		view = getDummyWidget<LLView>(name);
+		if (!view)
+		{
+			view = LLUICtrlFactory::createDummyWidget<LLView>(name);
+		}
 	}
 	return view;
 }
@@ -1028,617 +864,8 @@ void LLPanel::childDisplayNotFound()
 	LLNotifications::instance().add("FloaterNotFound", args);
 }
 
-void LLPanel::storeRectControl()
+void LLPanel::requires(const std::string& name)
 {
-	if( !mRectControl.empty() )
-	{
-		LLUI::sConfigGroup->setRect( mRectControl, getRect() );
-	}
+	requires<LLView>(name);
 }
 
-
-//
-// LLLayoutStack
-//
-struct LLLayoutStack::LLEmbeddedPanel
-{
-	LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : 
-			mPanel(panelp), 
-			mMinWidth(min_width), 
-			mMinHeight(min_height),
-			mAutoResize(auto_resize),
-			mUserResize(user_resize),
-			mOrientation(orientation),
-			mCollapsed(FALSE),
-			mCollapseAmt(0.f),
-			mVisibleAmt(1.f) // default to fully visible
-	{
-		LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
-		LLRect resize_bar_rect = panelp->getRect();
-
-		S32 min_dim;
-		if (orientation == HORIZONTAL)
-		{
-			min_dim = mMinHeight;
-		}
-		else
-		{
-			min_dim = mMinWidth;
-		}
-		mResizeBar = new LLResizeBar(std::string("resizer"), mPanel, LLRect(), min_dim, S32_MAX, side);
-		mResizeBar->setEnableSnapping(FALSE);
-		// panels initialized as hidden should not start out partially visible
-		if (!mPanel->getVisible())
-		{
-			mVisibleAmt = 0.f;
-		}
-	}
-
-	~LLEmbeddedPanel()
-	{
-		// probably not necessary, but...
-		delete mResizeBar;
-		mResizeBar = NULL;
-	}
-
-	F32 getCollapseFactor()
-	{
-		if (mOrientation == HORIZONTAL)
-		{
-			return mVisibleAmt * clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)mPanel->getRect().getWidth());
-		}
-		else
-		{
-			return mVisibleAmt * clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinHeight / (F32)mPanel->getRect().getHeight());
-		}
-	}
-
-	LLPanel* mPanel;
-	S32 mMinWidth;
-	S32 mMinHeight;
-	BOOL mAutoResize;
-	BOOL mUserResize;
-	BOOL mCollapsed;
-	LLResizeBar* mResizeBar;
-	eLayoutOrientation mOrientation;
-	F32 mVisibleAmt;
-	F32 mCollapseAmt;
-};
-
-static LLRegisterWidget<LLLayoutStack> r2("layout_stack");
-
-LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) : 
-		mOrientation(orientation),
-		mMinWidth(0),
-		mMinHeight(0),
-		mPanelSpacing(RESIZE_BAR_HEIGHT)
-{
-}
-
-LLLayoutStack::~LLLayoutStack()
-{
-	std::for_each(mPanels.begin(), mPanels.end(), DeletePointer());
-}
-
-void LLLayoutStack::draw()
-{
-	updateLayout();
-
-	e_panel_list_t::iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		// clip to layout rectangle, not bounding rectangle
-		LLRect clip_rect = (*panel_it)->mPanel->getRect();
-		// scale clipping rectangle by visible amount
-		if (mOrientation == HORIZONTAL)
-		{
-			clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor());
-		}
-		else
-		{
-			clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor());
-		}
-
-		LLPanel* panelp = (*panel_it)->mPanel;
-
-		LLLocalClipRect clip(clip_rect);
-		// only force drawing invisible children if visible amount is non-zero
-		drawChild(panelp, 0, 0, !clip_rect.isNull());
-	}
-}
-
-void LLLayoutStack::removeCtrl(LLUICtrl* ctrl)
-{
-	LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel((LLPanel*)ctrl);
-
-	if (embedded_panelp)
-	{
-		mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
-		delete embedded_panelp;
-	}
-
-	// need to update resizebars
-
-	calcMinExtents();
-
-	LLView::removeCtrl(ctrl);
-}
-
-LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLView::getXML();
-	return node;
-}
-
-//static 
-LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string orientation_string("vertical");
-	node->getAttributeString("orientation", orientation_string);
-
-	eLayoutOrientation orientation = VERTICAL;
-
-	if (orientation_string == "horizontal")
-	{
-		orientation = HORIZONTAL;
-	}
-	else if (orientation_string == "vertical")
-	{
-		orientation = VERTICAL;
-	}
-	else
-	{
-		llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl;
-	}
-
-	LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
-
-	node->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
-	// don't allow negative spacing values
-	layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
-
-	std::string name("stack");
-	node->getAttributeString("name", name);
-
-	layout_stackp->setName(name);
-	layout_stackp->initFromXML(node, parent);
-
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		S32 min_width = 0;
-		S32 min_height = 0;
-		BOOL auto_resize = TRUE;
-
-		child->getAttributeS32("min_width", min_width);
-		child->getAttributeS32("min_height", min_height);
-		child->getAttributeBOOL("auto_resize", auto_resize);
-
-		if (child->hasName("layout_panel"))
-		{
-			BOOL user_resize = TRUE;
-			child->getAttributeBOOL("user_resize", user_resize);
-			LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
-			if (panelp)
-			{
-				panelp->setFollowsNone();
-				layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
-			}
-		}
-		else
-		{
-			BOOL user_resize = FALSE;
-			child->getAttributeBOOL("user_resize", user_resize);
-
-			LLPanel* panelp = new LLPanel(std::string("auto_panel"));
-			LLView* new_child = factory->createWidget(panelp, child);
-			if (new_child)
-			{
-				// put child in new embedded panel
-				layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
-				// resize panel to contain widget and move widget to be contained in panel
-				panelp->setRect(new_child->getRect());
-				new_child->setOrigin(0, 0);
-			}
-			else
-			{
-				panelp->die();
-			}
-		}
-	}
-	layout_stackp->updateLayout();
-
-	return layout_stackp;
-}
-
-S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
-{
-	// if we are spanning our children (crude upward propagation of size)
-	// then don't enforce our size on our children
-	if (mOrientation == HORIZONTAL)
-	{
-		cur_height = llmax(mMinHeight, getRect().getHeight());
-	}
-
-	return cur_height;
-}
-
-S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
-{
-	// if we are spanning our children (crude upward propagation of size)
-	// then don't enforce our size on our children
-	if (mOrientation == VERTICAL)
-	{
-		cur_width = llmax(mMinWidth, getRect().getWidth());
-	}
-
-	return cur_width;
-}
-
-void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate, S32 index)
-{
-	// panel starts off invisible (collapsed)
-	if (animate == ANIMATE)
-	{
-		panel->setVisible(FALSE);
-	}
-	LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
-	
-	mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
-	
-	addChild(panel);
-	addChild(embedded_panel->mResizeBar);
-
-	// bring all resize bars to the front so that they are clickable even over the panels
-	// with a bit of overlap
-	for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
-		sendChildToFront(resize_barp);
-	}
-
-	// start expanding panel animation
-	if (animate == ANIMATE)
-	{
-		panel->setVisible(TRUE);
-	}
-}
-
-void LLLayoutStack::removePanel(LLPanel* panel)
-{
-	removeChild(panel);
-}
-
-void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed)
-{
-	LLEmbeddedPanel* panel_container = findEmbeddedPanel(panel);
-	if (!panel_container) return;
-
-	panel_container->mCollapsed = collapsed;
-}
-
-void LLLayoutStack::updateLayout(BOOL force_resize)
-{
-	calcMinExtents();
-
-	// calculate current extents
-	S32 total_width = 0;
-	S32 total_height = 0;
-
-	const F32 ANIM_OPEN_TIME = 0.02f;
-	const F32 ANIM_CLOSE_TIME = 0.03f;
-
-	e_panel_list_t::iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end();	++panel_it)
-	{
-		LLPanel* panelp = (*panel_it)->mPanel;
-		if (panelp->getVisible()) 
-		{
-			(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
-			if ((*panel_it)->mVisibleAmt > 0.99f)
-			{
-				(*panel_it)->mVisibleAmt = 1.f;
-			}
-		}
-		else // not visible
-		{
-			(*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
-			if ((*panel_it)->mVisibleAmt < 0.001f)
-			{
-				(*panel_it)->mVisibleAmt = 0.f;
-			}
-		}
-
-		if ((*panel_it)->mCollapsed)
-		{
-			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
-		}
-		else
-		{
-			(*panel_it)->mCollapseAmt = lerp((*panel_it)->mCollapseAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
-		}
-
-		if (mOrientation == HORIZONTAL)
-		{
-			// enforce minimize size constraint by default
-			if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
-			{
-				panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
-			}
-        	total_width += llround(panelp->getRect().getWidth() * (*panel_it)->getCollapseFactor());
-        	// want n-1 panel gaps for n panels
-			if (panel_it != mPanels.begin())
-			{
-				total_width += mPanelSpacing;
-			}
-		}
-		else //VERTICAL
-		{
-			// enforce minimize size constraint by default
-			if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
-			{
-				panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
-			}
-			total_height += llround(panelp->getRect().getHeight() * (*panel_it)->getCollapseFactor());
-			if (panel_it != mPanels.begin())
-			{
-				total_height += mPanelSpacing;
-			}
-		}
-	}
-
-	S32 num_resizable_panels = 0;
-	S32 shrink_headroom_available = 0;
-	S32 shrink_headroom_total = 0;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		// panels that are not fully visible do not count towards shrink headroom
-		if ((*panel_it)->getCollapseFactor() < 1.f) 
-		{
-			continue;
-		}
-
-		// if currently resizing a panel or the panel is flagged as not automatically resizing
-		// only track total available headroom, but don't use it for automatic resize logic
-		if ((*panel_it)->mResizeBar->hasMouseCapture() 
-			|| (!(*panel_it)->mAutoResize 
-				&& !force_resize))
-		{
-			if (mOrientation == HORIZONTAL)
-			{
-				shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
-			}
-			else //VERTICAL
-			{
-				shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
-			}
-		}
-		else
-		{
-			num_resizable_panels++;
-			if (mOrientation == HORIZONTAL)
-			{
-				shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
-				shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
-			}
-			else //VERTICAL
-			{
-				shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
-				shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
-			}
-		}
-	}
-
-	// calculate how many pixels need to be distributed among layout panels
-	// positive means panels need to grow, negative means shrink
-	S32 pixels_to_distribute;
-	if (mOrientation == HORIZONTAL)
-	{
-		pixels_to_distribute = getRect().getWidth() - total_width;
-	}
-	else //VERTICAL
-	{
-		pixels_to_distribute = getRect().getHeight() - total_height;
-	}
-
-	// now we distribute the pixels...
-	S32 cur_x = 0;
-	S32 cur_y = getRect().getHeight();
-
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		LLPanel* panelp = (*panel_it)->mPanel;
-
-		S32 cur_width = panelp->getRect().getWidth();
-		S32 cur_height = panelp->getRect().getHeight();
-		S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
-		S32 new_height = llmax((*panel_it)->mMinHeight, cur_height); 
-
-		S32 delta_size = 0;
-
-		// if panel can automatically resize (not animating, and resize flag set)...
-		if ((*panel_it)->getCollapseFactor() == 1.f 
-			&& (force_resize || (*panel_it)->mAutoResize) 
-			&& !(*panel_it)->mResizeBar->hasMouseCapture()) 
-		{
-			if (mOrientation == HORIZONTAL)
-			{
-				// if we're shrinking
-				if (pixels_to_distribute < 0)
-				{
-					// shrink proportionally to amount over minimum
-					// so we can do this in one pass
-					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
-					shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
-				}
-				else
-				{
-					// grow all elements equally
-					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
-					num_resizable_panels--;
-				}
-				pixels_to_distribute -= delta_size;
-				new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
-			}
-			else
-			{
-				new_width = getDefaultWidth(new_width);
-			}
-
-			if (mOrientation == VERTICAL)
-			{
-				if (pixels_to_distribute < 0)
-				{
-					// shrink proportionally to amount over minimum
-					// so we can do this in one pass
-					delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
-					shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
-				}
-				else
-				{
-					delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
-					num_resizable_panels--;
-				}
-				pixels_to_distribute -= delta_size;
-				new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
-			}
-			else
-			{
-				new_height = getDefaultHeight(new_height);
-			}
-		}
-		else
-		{
-			if (mOrientation == HORIZONTAL)
-			{
-				new_height = getDefaultHeight(new_height);
-			}
-			else // VERTICAL
-			{
-				new_width = getDefaultWidth(new_width);
-			}
-		}
-
-		// adjust running headroom count based on new sizes
-		shrink_headroom_total += delta_size;
-
-		panelp->reshape(new_width, new_height);
-		panelp->setOrigin(cur_x, cur_y - new_height);
-
-		LLRect panel_rect = panelp->getRect();
-		LLRect resize_bar_rect = panel_rect;
-		if (mOrientation == HORIZONTAL)
-		{
-			resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
-			resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + RESIZE_BAR_OVERLAP;
-		}
-		else
-		{
-			resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
-			resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - RESIZE_BAR_OVERLAP;
-		}
-		(*panel_it)->mResizeBar->setRect(resize_bar_rect);
-
-		if (mOrientation == HORIZONTAL)
-		{
-			cur_x += llround(new_width * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
-		}
-		else //VERTICAL
-		{
-			cur_y -= llround(new_height * (*panel_it)->getCollapseFactor()) + mPanelSpacing;
-		}
-	}
-
-	// update resize bars with new limits
-	LLResizeBar* last_resize_bar = NULL;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		LLPanel* panelp = (*panel_it)->mPanel;
-
-		if (mOrientation == HORIZONTAL)
-		{
-			(*panel_it)->mResizeBar->setResizeLimits(
-				(*panel_it)->mMinWidth, 
-				(*panel_it)->mMinWidth + shrink_headroom_total);
-		}
-		else //VERTICAL
-		{
-			(*panel_it)->mResizeBar->setResizeLimits(
-				(*panel_it)->mMinHeight, 
-				(*panel_it)->mMinHeight + shrink_headroom_total);
-		}
-
-		// toggle resize bars based on panel visibility, resizability, etc
-		BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
-		(*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
-
-		if (resize_bar_enabled)
-		{
-			last_resize_bar = (*panel_it)->mResizeBar;
-		}
-	}
-
-	// hide last resize bar as there is nothing past it
-	// resize bars need to be in between two resizable panels
-	if (last_resize_bar)
-	{
-		last_resize_bar->setVisible(FALSE);
-	}
-
-	// not enough room to fit existing contents
-	if (force_resize == FALSE
-		// layout did not complete by reaching target position
-		&& ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
-			|| (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
-	{
-		// do another layout pass with all stacked elements contributing
-		// even those that don't usually resize
-		llassert_always(force_resize == FALSE);
-		updateLayout(TRUE);
-	}
-} // end LLLayoutStack::updateLayout
-
-
-LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
-{
-	e_panel_list_t::const_iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		if ((*panel_it)->mPanel == panelp)
-		{
-			return *panel_it;
-		}
-	}
-	return NULL;
-}
-
-void LLLayoutStack::calcMinExtents()
-{
-	mMinWidth = 0;
-	mMinHeight = 0;
-
-	e_panel_list_t::iterator panel_it;
-	for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
-	{
-		if (mOrientation == HORIZONTAL)
-		{
-			mMinHeight = llmax(	mMinHeight, 
-								(*panel_it)->mMinHeight);
-            mMinWidth += (*panel_it)->mMinWidth;
-			if (panel_it != mPanels.begin())
-			{
-				mMinWidth += mPanelSpacing;
-			}
-		}
-		else //VERTICAL
-		{
-	        mMinWidth = llmax(	mMinWidth, 
-								(*panel_it)->mMinWidth);
-			mMinHeight += (*panel_it)->mMinHeight;
-			if (panel_it != mPanels.begin())
-			{
-				mMinHeight += mPanelSpacing;
-			}
-		}
-	}
-}
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 756d02ef7d..5f4f8d16e7 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -56,42 +56,70 @@ const BOOL BORDER_NO = FALSE;
  * With or without border,
  * Can contain LLUICtrls.
  */
-class LLPanel : public LLUICtrl, public boost::signals::trackable
+class LLPanel : public LLUICtrl
 {
 public:
+	struct LocalizedString : public LLInitParam::Block<LocalizedString>
+	{
+		Mandatory<std::string>	name;
+		Mandatory<std::string>	text;
+		
+		LocalizedString()
+		:	name("name"),
+			text("value")
+		{}
+	};
+
+	struct Params 
+	:	public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<bool>			has_border;
+		Optional<LLViewBorder::Params>	border;
+
+		Optional<LLUIColor>		bg_opaque_color,
+								bg_alpha_color;
+
+		Optional<bool>			background_visible,
+								background_opaque;
+
+		Optional<S32>			min_width,
+								min_height;
+
+		Optional<std::string>	filename;
 
-	// minimal constructor for data-driven initialization
-	LLPanel();
-	LLPanel(const std::string& name);
+		Multiple<LocalizedString>	strings;
 
-	// Position and size not saved
-	LLPanel(const std::string& name, const LLRect& rect, BOOL bordered = TRUE);
+		Params();
+	};
 
-	// Position and size are saved to rect_control
-	LLPanel(const std::string& name, const std::string& rect_control, BOOL bordered = TRUE);	
+	// RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8
+	static const Params& defaultParams() { return LLUICtrlFactory::getDefaultParams<LLPanel::Params>(); }
+
+	// Panels can get constructed directly
+	LLPanel(const Params& params = defaultParams());
 	
-	/*virtual*/ ~LLPanel();
+public:
+// 	LLPanel(const std::string& name, const LLRect& rect = LLRect(), BOOL bordered = TRUE);
+	/*virtual*/ ~LLPanel() {}
 
 	// LLView interface
 	/*virtual*/ BOOL 	isPanel() const;
 	/*virtual*/ void	draw();	
 	/*virtual*/ BOOL	handleKeyHere( KEY key, MASK mask );
-	/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
+
 	// Override to set not found list:
-	virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
+	/*virtual*/ LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
 
 	// From LLFocusableElement
 	/*virtual*/ void	setFocus( BOOL b );
 	
 	// New virtuals
 	virtual 	void	refresh();	// called in setFocus()
-	virtual 	BOOL	postBuild();
 	virtual 	void	clearCtrls(); // overridden in LLPanelObject and LLPanelVolume
 
 	// Border controls
-	void addBorder( LLViewBorder::EBevel border_bevel = LLViewBorder::BEVEL_OUT,
-					LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE,
-					S32 border_thickness = LLPANEL_BORDER_WIDTH );
+	void addBorder( LLViewBorder::Params p);
+	void addBorder() {  LLViewBorder::Params p; p.border_thickness(LLPANEL_BORDER_WIDTH); addBorder(p); }
 	void			removeBorder();
 	BOOL			hasBorder() const { return mBorder != NULL; }
 	void			setBorderVisible( BOOL b );
@@ -106,10 +134,7 @@ public:
 	}
 	
 	// requires LLView by default
-	void requires(const std::string& name)
-	{
-		requires<LLView>(name);
-	}
+	void requires(const std::string& name);
 	BOOL			checkRequirements();
 
 	void			setBackgroundColor( const LLColor4& color ) { mBgColorOpaque = color; }
@@ -126,22 +151,18 @@ public:
 	void			setLabel(const LLStringExplicit& label) { mLabel = label; }
 	std::string		getLabel() const { return mLabel; }
 	
-	void            setRectControl(const std::string& rect_control) { mRectControl.assign(rect_control); }
-	const std::string&	getRectControl() const { return mRectControl; }
-	void			storeRectControl();
-
 	void			setCtrlsEnabled(BOOL b);
 
 	LLHandle<LLPanel>	getHandle() const { return mPanelHandle; }
 
-	S32				getLastTabGroup() const { return mLastTabGroup; }
-
 	const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; }
-
-	BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-	void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory);
-	void setPanelParameters(LLXMLNodePtr node, LLView *parentp);
-
+	
+	CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; }
+	
+	void initFromParams(const Params& p);
+	BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
+	
+	bool hasString(const std::string& name);
 	std::string getString(const std::string& name, const LLStringUtil::format_map_t& args) const;
 	std::string getString(const std::string& name) const;
 
@@ -166,12 +187,10 @@ public:
 	// LLUICtrl
 	void childSetFocus(const std::string& id, BOOL focus = TRUE);
 	BOOL childHasFocus(const std::string& id);
-	void childSetFocusChangedCallback(const std::string& id, void (*cb)(LLFocusableElement*, void*), void* user_data = NULL);
 	
-	void childSetCommitCallback(const std::string& id, void (*cb)(LLUICtrl*, void*), void* userdata = NULL );
-	void childSetDoubleClickCallback(const std::string& id, void (*cb)(void*), void* userdata = NULL );
-	void childSetValidate(const std::string& id, BOOL (*cb)(LLUICtrl*, void*) );
-	void childSetUserData(const std::string& id, void* userdata);
+	// *TODO: Deprecate; for backwards compatability only:
+	void childSetCommitCallback(const std::string& id, boost::function<void (LLUICtrl*,void*)> cb, void* data);	
+	void childSetValidate(const std::string& id, boost::function<bool (const LLSD& data)> cb );
 
 	void childSetColor(const std::string& id, const LLColor4& color);
 
@@ -196,21 +215,21 @@ public:
 	// LLTabContainer
 	void childShowTab(const std::string& id, const std::string& tabname, bool visible = true);
 	LLPanel *childGetVisibleTab(const std::string& id) const;
-	void childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool) = NULL);
 
 	// LLTextBox
 	void childSetWrappedText(const std::string& id, const std::string& text, bool visible = true);
 
 	// LLTextBox/LLTextEditor/LLLineEditor
 	void childSetText(const std::string& id, const LLStringExplicit& text) { childSetValue(id, LLSD(text)); }
+
+	// *NOTE: Does not return text from <string> tags, use getString()
 	std::string childGetText(const std::string& id) const { return childGetValue(id).asString(); }
 
 	// LLLineEditor
-	void childSetKeystrokeCallback(const std::string& id, void (*keystroke_callback)(LLLineEditor* caller, void* user_data), void *user_data);
 	void childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWString &) );
 
 	// LLButton
-	void childSetAction(const std::string& id, void(*function)(void*), void* value);
+	void childSetAction(const std::string& id, boost::function<void(void*)> function, void* value = NULL);
 	void childSetActionTextbox(const std::string& id, void(*function)(void*), void* value = NULL);
 	void childSetControlName(const std::string& id, const std::string& control_name);
 
@@ -218,36 +237,27 @@ public:
 	void childNotFound(const std::string& id) const;
 	void childDisplayNotFound();
 
-	static LLView*	fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	static LLView*	fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
 	
 protected:
 	// Override to set not found list
 	LLButton*		getDefaultButton() { return mDefaultBtn; }
 	LLCallbackMap::map_t mFactoryMap;
-
+	CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar;
+	
 private:
-	// common construction logic
-	void init();
-
-	// From LLView
-	virtual void	addCtrl( LLUICtrl* ctrl, S32 tab_group );
-	virtual void	addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group);
-
 	// Unified error reporting for the child* functions
 	typedef std::set<std::string> expected_members_list_t;
 	mutable expected_members_list_t mExpectedMembers;
 	mutable expected_members_list_t mNewExpectedMembers;
 
-	std::string		mRectControl;
 	LLColor4		mBgColorAlpha;
 	LLColor4		mBgColorOpaque;
-	LLColor4		mDefaultBtnHighlight;
 	BOOL			mBgVisible;
 	BOOL			mBgOpaque;
 	LLViewBorder*	mBorder;
 	LLButton*		mDefaultBtn;
-	std::string		mLabel;
-	S32				mLastTabGroup;
+	LLUIString		mLabel;
 	LLRootHandle<LLPanel> mPanelHandle;
 
 	typedef std::map<std::string, std::string> ui_string_map_t;
@@ -257,56 +267,4 @@ private:
 
 }; // end class LLPanel
 
-
-class LLLayoutStack : public LLView
-{
-public:
-	typedef enum e_layout_orientation
-	{
-		HORIZONTAL,
-		VERTICAL
-	} eLayoutOrientation;
-
-	LLLayoutStack(eLayoutOrientation orientation);
-	virtual ~LLLayoutStack();
-
-	/*virtual*/ void draw();
-	/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
-	/*virtual*/ void removeCtrl(LLUICtrl* ctrl);
-
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-
-	S32 getMinWidth() const { return mMinWidth; }
-	S32 getMinHeight() const { return mMinHeight; }
-	
-	typedef enum e_animate
-	{
-		NO_ANIMATE,
-		ANIMATE
-	} EAnimate;
-
-	void addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, EAnimate animate = NO_ANIMATE, S32 index = S32_MAX);
-	void removePanel(LLPanel* panel);
-	void collapsePanel(LLPanel* panel, BOOL collapsed = TRUE);
-	S32 getNumPanels() { return mPanels.size(); }
-
-private:
-	struct LLEmbeddedPanel;
-
-	void updateLayout(BOOL force_resize = FALSE);
-	void calcMinExtents();
-	S32 getDefaultHeight(S32 cur_height);
-	S32 getDefaultWidth(S32 cur_width);
-
-	const eLayoutOrientation mOrientation;
-
-	typedef std::vector<LLEmbeddedPanel*> e_panel_list_t;
-	e_panel_list_t mPanels;
-	LLEmbeddedPanel* findEmbeddedPanel(LLPanel* panelp) const;
-
-	S32 mMinWidth;
-	S32 mMinHeight;
-	S32 mPanelSpacing;
-}; // end class LLLayoutStack
-
 #endif
diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp
index 8833494af8..693c331797 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -44,26 +44,32 @@
 #include "llglheaders.h"
 
 #include "llfocusmgr.h"
+#include "lluictrlfactory.h"
 
 static LLRegisterWidget<LLProgressBar> r("progress_bar");
 
-LLProgressBar::LLProgressBar(const std::string& name, const LLRect &rect) 
-	: LLView(name, rect, FALSE),
-	  mImageBar( NULL ),
-	  mImageShadow( NULL )
-{
-	mPercentDone = 0.f;
-
-	// Defaults:
-
-	setImageBar("rounded_square.tga");	
-	setImageShadow("rounded_square_soft.tga");
-
-	mColorBackground = LLColor4(0.3254f, 0.4000f, 0.5058f, 1.0f);
-	mColorBar        = LLColor4(0.5764f, 0.6627f, 0.8352f, 1.0f);
-	mColorBar2       = LLColor4(0.5764f, 0.6627f, 0.8352f, 1.0f);
-	mColorShadow     = LLColor4(0.2000f, 0.2000f, 0.4000f, 1.0f);
-}
+LLProgressBar::Params::Params()
+:	image_bar("image_bar"),
+	image_fill("image_fill"),
+	image_shadow("image_shadow"),
+	color_bar("color_bar"),
+	color_bar2("color_bar2"),
+	color_shadow("color_shadow"),
+	color_bg("color_bg")
+{}
+
+
+LLProgressBar::LLProgressBar(const LLProgressBar::Params& p) 
+:	LLView(p),
+	mImageBar(p.image_bar),
+	mImageShadow(p.image_shadow),
+	mImageFill(p.image_fill),
+	mColorBackground(p.color_bg()),
+	mColorBar(p.color_bar()),
+	mColorBar2(p.color_bar2()),
+	mColorShadow(p.color_shadow()),
+	mPercentDone(0.f)
+{}
 
 LLProgressBar::~LLProgressBar()
 {
@@ -74,108 +80,19 @@ void LLProgressBar::draw()
 {
 	static LLTimer timer;
 
-	LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga");
 	LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("progressbar_fill.tga");
-	LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("progressbar_track.tga");
-	LLUIImagePtr bar_imagep = LLUI::getUIImage("rounded_square.tga");
-	LLColor4 background_color = LLUI::sColorsGroup->getColor("LoginProgressBarBgColor");
 	
-	bar_bg_imagep->draw(getLocalRect(),
-		background_color);
+	mImageBar->draw(getLocalRect(), mColorBackground.get());
 
 	F32 alpha = 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
-	LLColor4 bar_color = LLUI::sColorsGroup->getColor("LoginProgressBarFgColor");
+	LLColor4 bar_color = mColorBar.get();
 	bar_color.mV[3] = alpha;
 	LLRect progress_rect = getLocalRect();
 	progress_rect.mRight = llround(getRect().getWidth() * (mPercentDone / 100.f));
-	bar_fg_imagep->draw(progress_rect);
+	mImageFill->draw(progress_rect);
 }
 
 void LLProgressBar::setPercent(const F32 percent)
 {
 	mPercentDone = llclamp(percent, 0.f, 100.f);
 }
-
-void LLProgressBar::setImageBar( const std::string &bar_name )
-{
-	mImageBar = LLUI::sImageProvider->getUIImage(bar_name)->getImage();
-}
-
-void LLProgressBar::setImageShadow(const std::string &shadow_name)
-{
-	mImageShadow = LLUI::sImageProvider->getUIImage(shadow_name)->getImage();
-}
-
-void LLProgressBar::setColorBar(const LLColor4 &c)
-{
-	mColorBar = c;
-}
-void LLProgressBar::setColorBar2(const LLColor4 &c)
-{
-	mColorBar2 = c;
-}
-void LLProgressBar::setColorShadow(const LLColor4 &c)
-{
-	mColorShadow = c;
-}
-void LLProgressBar::setColorBackground(const LLColor4 &c)
-{
-	mColorBackground = c;
-}
-
-
-// static
-LLView* LLProgressBar::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("progress_bar");
-	node->getAttributeString("name", name);
-
-	LLProgressBar *progress = new LLProgressBar(name, LLRect());
-
-
-	std::string image_bar;
-	if (node->hasAttribute("image_bar")) node->getAttributeString("image_bar",image_bar);
-	if (image_bar != LLStringUtil::null) progress->setImageBar(image_bar);
-
-
-	std::string image_shadow;
-	if (node->hasAttribute("image_shadow")) node->getAttributeString("image_shadow",image_shadow);
-	if (image_shadow != LLStringUtil::null) progress->setImageShadow(image_shadow);
-
-
-	LLColor4 color_bar;
-	if (node->hasAttribute("color_bar"))
-	{
-		node->getAttributeColor4("color_bar",color_bar);
-		progress->setColorBar(color_bar);
-	}
-
-
-	LLColor4 color_bar2;
-	if (node->hasAttribute("color_bar2"))
-	{
-		node->getAttributeColor4("color_bar2",color_bar2);
-		progress->setColorBar2(color_bar2);
-	}
-
-
-	LLColor4 color_shadow;
-	if (node->hasAttribute("color_shadow"))
-	{
-		node->getAttributeColor4("color_shadow",color_shadow);
-		progress->setColorShadow(color_shadow);
-	}
-
-
-	LLColor4 color_bg;
-	if (node->hasAttribute("color_bg"))
-	{
-		node->getAttributeColor4("color_bg",color_bg);
-		progress->setColorBackground(color_bg);
-	}
-
-	
-	progress->initFromXML(node, parent);
-	
-	return progress;
-}
diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h
index 00ad61d540..5c2f73ef9e 100644
--- a/indra/llui/llprogressbar.h
+++ b/indra/llui/llprogressbar.h
@@ -40,37 +40,38 @@ class LLProgressBar
 	: public LLView
 {
 public:
-	LLProgressBar(const std::string& name, const LLRect &rect);
-	virtual ~LLProgressBar();
-
-	void setPercent(const F32 percent);
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<LLUIImage*>	image_bar,
+								image_fill,
+								image_shadow;
 
-	void setImageBar(const std::string &bar_name);
-	void setImageShadow(const std::string &shadow_name);
+		Optional<LLUIColor>		color_bar,
+								color_bar2,
+								color_shadow,
+								color_bg;
 
-	void setColorBar(const LLColor4 &c);
-	void setColorBar2(const LLColor4 &c);
-	void setColorShadow(const LLColor4 &c);
-	void setColorBackground(const LLColor4 &c);
+		Params();
+	};
+	LLProgressBar(const Params&);
+	virtual ~LLProgressBar();
 
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	void setPercent(const F32 percent);
 
 	/*virtual*/ void draw();
 
-protected:
+private:
 	F32 mPercentDone;
 
-	LLPointer<LLImageGL>  mImageBar;
-	//LLUUID                mImageBarID;
-	//LLString              mImageBarName;
-	LLColor4              mColorBar;
-	LLColor4              mColorBar2;
+	LLPointer<LLUIImage>	mImageBar;
+	LLUIColor	mColorBar;
+	LLUIColor	mColorBar2;
 
-	LLPointer<LLImageGL>  mImageShadow;
-	//LLUUID                mImageShadowID;
-	//LLString              mImageShadowName;
-	LLColor4              mColorShadow;
-	LLColor4              mColorBackground;
+	LLPointer<LLUIImage>	mImageShadow;
+	LLUIColor    mColorShadow;
+	LLUIColor    mColorBackground;
+	
+	LLPointer<LLUIImage>	mImageFill;
 };
 
 #endif // LL_LLPROGRESSBAR_H
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 33b93985d7..7d34841431 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -42,52 +42,49 @@
 #include "llcontrol.h"
 #include "llui.h"
 #include "llfocusmgr.h"
+#include "lluictrlfactory.h"
 
-static LLRegisterWidget<LLRadioGroup> r("radio_group");
+static LLRegisterWidget<LLRadioGroup> r1("radio_group");
+static LLRegisterWidget<LLRadioCtrl> r2("radio_item");
 
-LLRadioGroup::LLRadioGroup(const std::string& name, const LLRect& rect,
-						   const std::string& control_name,
-						   LLUICtrlCallback callback,
-						   void* userdata,
-						   BOOL border)
-:	LLUICtrl(name, rect, TRUE, callback, userdata, FOLLOWS_LEFT | FOLLOWS_TOP),
-	mSelectedIndex(0)
+LLRadioGroup::Params::Params()
+:	has_border("draw_border")
 {
-	setControlName(control_name, NULL);
-	init(border);
+	name = "radio_group";
+	mouse_opaque = true;
+	follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP;
 }
 
-LLRadioGroup::LLRadioGroup(const std::string& name, const LLRect& rect,
-						   S32 initial_index,
-						   LLUICtrlCallback callback,
-						   void* userdata,
-						   BOOL border) :
-	LLUICtrl(name, rect, TRUE, callback, userdata, FOLLOWS_LEFT | FOLLOWS_TOP),
-	mSelectedIndex(initial_index)
-{
-	init(border);
-}
-
-void LLRadioGroup::init(BOOL border)
-{
-	if (border)
+LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
+:	LLUICtrl(p),
+	mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
+	mSelectedIndex(-1),
+	mHasBorder(p.has_border)
+{	
+	if (mHasBorder)
 	{
-		addChild( new LLViewBorder( std::string("radio group border"), 
-									LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), 
-									LLViewBorder::BEVEL_NONE, 
-									LLViewBorder::STYLE_LINE, 
-									1 ) );
+		LLViewBorder::Params params;
+		params.name("radio group border");
+		params.rect(LLRect(0, getRect().getHeight(), getRect().getWidth(), 0));
+		params.bevel_type(LLViewBorder::BEVEL_NONE);
+		LLViewBorder * vb = LLUICtrlFactory::create<LLViewBorder> (params);
+		addChild (vb);
 	}
-	mHasBorder = border;
 }
 
-
-
-
 LLRadioGroup::~LLRadioGroup()
 {
 }
 
+// virtual
+BOOL LLRadioGroup::postBuild()
+{
+	if (mControlVariable)
+	{
+		setSelectedIndex(mControlVariable->getValue().asInteger());
+	}
+	return TRUE;
+}
 
 // virtual
 void LLRadioGroup::setEnabled(BOOL enabled)
@@ -250,48 +247,52 @@ void LLRadioGroup::draw()
 	LLView::draw();
 }
 
-
-// When adding a button, we need to ensure that the radio
+// When adding a child button, we need to ensure that the radio
 // group gets a message when the button is clicked.
-LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font )
+
+/*virtual*/
+bool LLRadioGroup::addChild(LLView* view, S32 tab_group)
 {
-	// Highlight will get fixed in draw method above
-	LLRadioCtrl* radio = new LLRadioCtrl(name, rect, label, font,
-		onClickButton, this);
-	addChild(radio);
-	mRadioButtons.push_back(radio);
-	return radio;
+	bool res = LLView::addChild(view, tab_group);
+	if (res)
+	{
+		LLRadioCtrl* radio_ctrl = dynamic_cast<LLRadioCtrl*>(view);
+		if (radio_ctrl)
+		{
+			radio_ctrl->setFont(mFont);
+			radio_ctrl->setCommitCallback(boost::bind(&LLRadioGroup::onClickButton, this, _1));
+			mRadioButtons.push_back(radio_ctrl);
+		}
+	}
+	return res;
 }
 
 // Handle one button being clicked.  All child buttons must have this
 // function as their callback function.
 
-// static
-void LLRadioGroup::onClickButton(LLUICtrl* ui_ctrl, void* userdata)
+void LLRadioGroup::onClickButton(LLUICtrl* ctrl)
 {
 	// llinfos << "LLRadioGroup::onClickButton" << llendl;
-
-	LLRadioCtrl* clickedRadio = (LLRadioCtrl*) ui_ctrl;
-	LLRadioGroup* self = (LLRadioGroup*) userdata;
-
-	S32 counter = 0;
-	for (button_list_t::iterator iter = self->mRadioButtons.begin();
-		 iter != self->mRadioButtons.end(); ++iter)
+	LLRadioCtrl* clicked_radio = dynamic_cast<LLRadioCtrl*>(ctrl);
+	if (!clicked_radio)
+	    return;
+	S32 index = 0;
+	for (button_list_t::iterator iter = mRadioButtons.begin();
+		 iter != mRadioButtons.end(); ++iter)
 	{
 		LLRadioCtrl* radio = *iter;
-		if (radio == clickedRadio)
+		if (radio == clicked_radio)
 		{
-			// llinfos << "clicked button " << counter << llendl;
-			self->setSelectedIndex(counter);
-			self->setControlValue(counter);
+			// llinfos << "clicked button " << index << llendl;
+			setSelectedIndex(index);
 			
 			// BUG: Calls click callback even if button didn't actually change
-			self->onCommit();
+			onCommit();
 
 			return;
 		}
 
-		counter++;
+		index++;
 	}
 
 	llwarns << "LLRadioGroup::onClickButton - clicked button that isn't a child" << llendl;
@@ -340,107 +341,6 @@ LLSD LLRadioGroup::getValue() const
 	return LLSD();
 }
 
-// virtual
-LLXMLNodePtr LLRadioGroup::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	// Attributes
-
-	node->createChild("draw_border", TRUE)->setBoolValue(mHasBorder);
-
-	// Contents
-
-	for (button_list_t::const_iterator iter = mRadioButtons.begin();
-		 iter != mRadioButtons.end(); ++iter)
-	{
-		LLRadioCtrl* radio = *iter;
-
-		LLXMLNodePtr child_node = radio->LLView::getXML();
-		child_node->setStringValue(radio->getLabel());
-		child_node->setName(std::string("radio_item"));
-
-		node->addChild(child_node);
-	}
-
-	return node;
-}
-
-// static
-LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("radio_group");
-	node->getAttributeString("name", name);
-
-	U32 initial_value = 0;
-	node->getAttributeU32("initial_value", initial_value);
-
-	BOOL draw_border = TRUE;
-	node->getAttributeBOOL("draw_border", draw_border);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	LLRadioGroup* radio_group = new LLRadioGroup(name, 
-		rect,
-		initial_value,
-		NULL,
-		NULL,
-		draw_border);
-
-	const std::string& contents = node->getValue();
-
-	LLRect group_rect = radio_group->getRect();
-
-	LLFontGL *font = LLView::selectFont(node);
-
-	if (contents.find_first_not_of(" \n\t") != contents.npos)
-	{
-		// ...old school default vertical layout
-		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-		boost::char_separator<char> sep("\t\n");
-		tokenizer tokens(contents, sep);
-		tokenizer::iterator token_iter = tokens.begin();
-	
-		const S32 HPAD = 4, VPAD = 4;
-		S32 cur_y = group_rect.getHeight() - VPAD;
-	
-		while(token_iter != tokens.end())
-		{
-			const std::string& line = *token_iter;
-			LLRect rect(HPAD, cur_y, group_rect.getWidth() - (2 * HPAD), cur_y - 15);
-			cur_y -= VPAD + 15;
-			radio_group->addRadioButton(std::string("radio"), line, rect, font);
-			++token_iter;
-		}
-		llwarns << "Legacy radio group format used! Please convert to use <radio_item> tags!" << llendl;
-	}
-	else
-	{
-		// ...per pixel layout
-		LLXMLNodePtr child;
-		for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-		{
-			if (child->hasName("radio_item"))
-			{
-				LLRect item_rect;
-				createRect(child, item_rect, radio_group, rect);
-
-				std::string radioname("radio");
-				child->getAttributeString("name", radioname);
-				std::string item_label = child->getTextContents();
-				LLRadioCtrl* radio = radio_group->addRadioButton(radioname, item_label, item_rect, font);
-
-				radio->initFromXML(child, radio_group);
-			}
-		}
-	}
-
-	radio_group->initFromXML(node, parent);
-
-	return radio_group;
-}
-
 // LLCtrlSelectionInterface functions
 BOOL	LLRadioGroup::setCurrentByID( const LLUUID& id )
 {
@@ -504,6 +404,22 @@ BOOL	LLRadioGroup::operateOnAll(EOperation op)
 	return FALSE;
 }
 
+LLRadioCtrl::LLRadioCtrl(const LLRadioCtrl::Params& p)
+	: LLCheckBoxCtrl(p)
+{
+}
+
+BOOL LLRadioCtrl::postBuild()
+{
+	// Old-style radio_item used the text contents to indicate the label,
+	// but new-style radio_item uses label attribute.
+	std::string value = getValue().asString();
+	if (!value.empty())
+	{
+		setLabel(value);
+	}
+	return TRUE;
+}
 
 LLRadioCtrl::~LLRadioCtrl()
 {
@@ -515,3 +431,19 @@ void LLRadioCtrl::setValue(const LLSD& value)
 	mButton->setTabStop(value.asBoolean());
 }
 
+// *TODO: Remove this function after the initial XUI XML re-export pass.
+// static
+void LLRadioCtrl::setupParamsForExport(Params& p, LLView* parent)
+{
+	std::string label = p.label;
+	if (label.empty())
+	{
+		// We don't have a label attribute, so move the text contents
+		// stored in "value" into the label
+		std::string initial_value = p.LLUICtrl::Params::initial_value();
+		p.label = initial_value;
+		p.LLUICtrl::Params::initial_value = LLSD();
+	}
+
+	LLCheckBoxCtrl::setupParamsForExport(p, parent);
+}
diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h
index 3410b74104..3dfab9b2b3 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -39,20 +39,35 @@
 
 
 /*
- * A checkbox control with use_radio_style == true.
+ * An invisible view containing multiple mutually exclusive toggling 
+ * buttons (usually radio buttons).  Automatically handles the mutex
+ * condition by highlighting only one button at a time.
  */
 class LLRadioCtrl : public LLCheckBoxCtrl 
 {
 public:
-	LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const LLFontGL* font = NULL,
-		void (*commit_callback)(LLUICtrl*, void*) = NULL, void* callback_userdata = NULL) :
-				LLCheckBoxCtrl(name, rect, label, font, commit_callback, callback_userdata, FALSE, RADIO_STYLE)
+	struct Params : public LLInitParam::Block<Params, LLCheckBoxCtrl::Params>
 	{
-		setTabStop(FALSE);
-	}
-	/*virtual*/ ~LLRadioCtrl();
+		Deprecated length;
+		Deprecated type;
+
+		Params() 
+		:	length("length"),
+			type("type")
+		{}
+	};
 
+	/*virtual*/ ~LLRadioCtrl();
 	/*virtual*/ void setValue(const LLSD& value);
+
+	/*virtual*/ BOOL postBuild();
+
+	// Ensure label is in an attribute, not the contents
+	static void setupParamsForExport(Params& p, LLView* parent);
+
+protected:
+	LLRadioCtrl(const Params& p);
+	friend class LLUICtrlFactory;
 };
 
 
@@ -65,30 +80,26 @@ class LLRadioGroup
 :	public LLUICtrl, public LLCtrlSelectionInterface
 {
 public:
-	// Build a radio group.  The number (0...n-1) of the currently selected
-	// element will be stored in the named control.  After the control is
-	// changed the callback will be called.
-	LLRadioGroup(const std::string& name, const LLRect& rect, 
-		const std::string& control_name, 
-		LLUICtrlCallback callback = NULL,
-		void* userdata = NULL,
-		BOOL border = TRUE);
-
-	// Another radio group constructor, but this one doesn't rely on
-	// needing a control
-	LLRadioGroup(const std::string& name, const LLRect& rect,
-				 S32 initial_index,
-				 LLUICtrlCallback callback = NULL,
-				 void* userdata = NULL,
-				 BOOL border = TRUE);
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<bool> has_border;
+		Params();
+	};
 
-	virtual ~LLRadioGroup();
+protected:
+	LLRadioGroup(const Params&);
+	friend class LLUICtrlFactory;
 
+public:
+	virtual ~LLRadioGroup();
+	
+	virtual BOOL postBuild();
+	
+	virtual bool addChild(LLView* view, S32 tab_group = 0);
+	
 	virtual BOOL handleKeyHere(KEY key, MASK mask);
 
 	virtual void setEnabled(BOOL enabled);
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
 	void setIndexEnabled(S32 index, BOOL enabled);
 	
 	// return the index value of the selected item
@@ -104,13 +115,8 @@ public:
 	// Draw the group, but also fix the highlighting based on the control.
 	void draw();
 
-	// You must use this method to add buttons to a radio group.
-	// Don't use addChild -- it won't set the callback function
-	// correctly.
-	LLRadioCtrl* addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font);
-	LLRadioCtrl* getRadioButton(const S32& index) { return mRadioButtons[index]; }
 	// Update the control as needed.  Userdata must be a pointer to the button.
-	static void onClickButton(LLUICtrl* radio, void* userdata);
+	void onClickButton(LLUICtrl* clicked_radio);
 	
 	//========================================================================
 	LLCtrlSelectionInterface* getSelectionInterface()	{ return (LLCtrlSelectionInterface*)this; };
@@ -131,9 +137,7 @@ public:
 	/*virtual*/ BOOL	operateOnAll(EOperation op);
 
 private:
-	// protected function shared by the two constructors.
-	void init(BOOL border);
-
+	const LLFontGL* mFont;
 	S32 mSelectedIndex;
 	typedef std::vector<LLRadioCtrl*> button_list_t;
 	button_list_t mRadioButtons;
diff --git a/indra/llui/llresizebar.cpp b/indra/llui/llresizebar.cpp
index 5b9fe72e99..304ac64f31 100644
--- a/indra/llui/llresizebar.cpp
+++ b/indra/llui/llresizebar.cpp
@@ -40,22 +40,22 @@
 #include "llfocusmgr.h"
 #include "llwindow.h"
 
-LLResizeBar::LLResizeBar( const std::string& name, LLView* resizing_view, const LLRect& rect, S32 min_size, S32 max_size, Side side )
-	:
-	LLView( name, rect, TRUE ),
+LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)
+:	LLView(p),
 	mDragLastScreenX( 0 ),
 	mDragLastScreenY( 0 ),
 	mLastMouseScreenX( 0 ),
 	mLastMouseScreenY( 0 ),
-	mMinSize( min_size ),
-	mMaxSize( max_size ),
-	mSide( side ),
-	mSnappingEnabled(TRUE),
-	mAllowDoubleClickSnapping(TRUE),
-	mResizingView(resizing_view)
+	mMinSize( p.min_size ),
+	mMaxSize( p.max_size ),
+	mSide( p.side ),
+	mSnappingEnabled(p.snapping_enabled),
+	mAllowDoubleClickSnapping(p.allow_double_click_snapping),
+	mResizingView(p.resizing_view)
 {
+	setFollowsNone();
 	// set up some generically good follow code.
-	switch( side )
+	switch( mSide )
 	{
 	case LEFT:
 		setFollowsLeft();
@@ -80,8 +80,6 @@ LLResizeBar::LLResizeBar( const std::string& name, LLView* resizing_view, const
 	default:
 		break;
 	}
-	// this is just a decorator
-	setSaveToXML(FALSE);
 }
 
 
@@ -185,30 +183,31 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
 
 			if (mSnappingEnabled)
 			{
+				static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
 				switch( mSide )
 				{
 				case LEFT:
-					snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+					snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 					break;
 				case TOP:
-					snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+					snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 					break;
 				case RIGHT:
-					snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+					snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 					break;
 				case BOTTOM:
-					snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+					snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 					break;
 				}
 			}
 
 			// register "snap" behavior with snapped view
-			mResizingView->snappedTo(snap_view);
+			mResizingView->setSnappedTo(snap_view);
 
 			// restore original rectangle so the appropriate changes are detected
 			mResizingView->setRect(orig_rect);
 			// change view shape as user operation
-			mResizingView->userSetShape(scaled_rect);
+			mResizingView->setShape(scaled_rect, true);
 
 			// update last valid mouse cursor position based on resized view's actual size
 			LLRect new_rect = mResizingView->getRect();
@@ -284,7 +283,7 @@ BOOL LLResizeBar::handleDoubleClick(S32 x, S32 y, MASK mask)
 			break;
 		}
 
-		mResizingView->userSetShape(scaled_rect);
+		mResizingView->setShape(scaled_rect, true);
 	}
 
 	return TRUE;
diff --git a/indra/llui/llresizebar.h b/indra/llui/llresizebar.h
index b9fc40593d..4ad3d5035a 100644
--- a/indra/llui/llresizebar.h
+++ b/indra/llui/llresizebar.h
@@ -41,7 +41,31 @@ class LLResizeBar : public LLView
 public:
 	enum Side { LEFT, TOP, RIGHT, BOTTOM };
 
-	LLResizeBar(const std::string& name, LLView* resizing_view, const LLRect& rect, S32 min_size, S32 max_size, Side side );
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Mandatory<LLView*> resizing_view;
+		Mandatory<Side>	side;
+
+		Optional<S32>	min_size;
+		Optional<S32>	max_size;
+		Optional<bool>	snapping_enabled;
+		Optional<bool>	allow_double_click_snapping;
+
+		Params()
+		:	max_size("", S32_MAX),
+			snapping_enabled("", true),
+			resizing_view("resizing_view"),
+			side("side"),
+			allow_double_click_snapping("", true)
+		{
+			name = "resize_bar";
+		}
+	};
+
+protected:
+	LLResizeBar(const LLResizeBar::Params& p);
+	friend class LLUICtrlFactory;
+public:
 
 //	virtual void	draw();  No appearance
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llresizehandle.cpp b/indra/llui/llresizehandle.cpp
index c5d57d8d6c..943e2f55f1 100644
--- a/indra/llui/llresizehandle.cpp
+++ b/indra/llui/llresizehandle.cpp
@@ -44,37 +44,37 @@
 
 const S32 RESIZE_BORDER_WIDTH = 3;
 
-LLResizeHandle::LLResizeHandle( const std::string& name, const LLRect& rect, S32 min_width, S32 min_height, ECorner corner )
-	:
-	LLView( name, rect, TRUE ),
+LLResizeHandle::Params::Params()
+:	corner("corner")
+{
+	name = "resize_handle";
+}
+
+LLResizeHandle::LLResizeHandle(const LLResizeHandle::Params& p)
+:	LLView(p),
 	mDragLastScreenX( 0 ),
 	mDragLastScreenY( 0 ),
 	mLastMouseScreenX( 0 ),
 	mLastMouseScreenY( 0 ),
 	mImage( NULL ),
-	mMinWidth( min_width ),
-	mMinHeight( min_height ),
-	mCorner( corner )
+	mMinWidth( p.min_width ),
+	mMinHeight( p.min_height ),
+	mCorner( p.corner )
 {
-	setSaveToXML(false);
-
 	if( RIGHT_BOTTOM == mCorner)
 	{
-		mImage = LLUI::sImageProvider->getUIImage("UIImgResizeBottomRightUUID");
+		mImage = LLUI::getUIImage("resize_handle_bottom_right_blue.tga");
 	}
-
-	switch( mCorner )
+	switch( p.corner )
 	{
-	case LEFT_TOP:		setFollows( FOLLOWS_LEFT | FOLLOWS_TOP );		break;
-	case LEFT_BOTTOM:	setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM );	break;
-	case RIGHT_TOP:		setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP );		break;
-	case RIGHT_BOTTOM:	setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM );	break;
+		case LEFT_TOP:		setFollows( FOLLOWS_LEFT | FOLLOWS_TOP );		break;
+		case LEFT_BOTTOM:	setFollows( FOLLOWS_LEFT | FOLLOWS_BOTTOM );	break;
+		case RIGHT_TOP:		setFollows( FOLLOWS_RIGHT | FOLLOWS_TOP );		break;
+		case RIGHT_BOTTOM:	setFollows( FOLLOWS_RIGHT | FOLLOWS_BOTTOM );	break;
 	}
-
-	// decorator object, don't serialize
-	setSaveToXML(FALSE);
 }
 
+
 BOOL LLResizeHandle::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = FALSE;
@@ -205,36 +205,37 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
 			LLView* snap_view = NULL;
 			LLView* test_view = NULL;
 
+			static LLUICachedControl<S32> snap_margin ("SnapMargin", 0);
 			// now do snapping
 			switch(mCorner)
 			{
 			case LEFT_TOP:		
-				snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
-				test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+				snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
+				test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 				if (!snap_view)
 				{
 					snap_view = test_view;
 				}
 				break;
 			case LEFT_BOTTOM:	
-				snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
-				test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+				snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
+				test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 				if (!snap_view)
 				{
 					snap_view = test_view;
 				}
 				break;
 			case RIGHT_TOP:		
-				snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
-				test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+				snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
+				test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 				if (!snap_view)
 				{
 					snap_view = test_view;
 				}
 				break;
 			case RIGHT_BOTTOM:	
-				snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
-				test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
+				snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
+				test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
 				if (!snap_view)
 				{
 					snap_view = test_view;
@@ -243,13 +244,13 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
 			}
 
 			// register "snap" behavior with snapped view
-			resizing_view->snappedTo(snap_view);
+			resizing_view->setSnappedTo(snap_view);
 
 			// reset parent rect
 			resizing_view->setRect(orig_rect);
 
 			// translate and scale to new shape
-			resizing_view->userSetShape(scaled_rect);
+			resizing_view->setShape(scaled_rect, true);
 			
 			// update last valid mouse cursor position based on resized view's actual size
 			LLRect new_rect = resizing_view->getRect();
diff --git a/indra/llui/llresizehandle.h b/indra/llui/llresizehandle.h
index 0e23d526fa..e4e3c81cec 100644
--- a/indra/llui/llresizehandle.h
+++ b/indra/llui/llresizehandle.h
@@ -44,9 +44,18 @@ class LLResizeHandle : public LLView
 public:
 	enum ECorner { LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM };
 
-	
-	LLResizeHandle(const std::string& name, const LLRect& rect, S32 min_width, S32 min_height, ECorner corner = RIGHT_BOTTOM );
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Mandatory<ECorner>	corner;
+		Optional<S32>		min_width;
+		Optional<S32>		min_height;
+		Params();
+	};
 
+protected:
+	LLResizeHandle(const LLResizeHandle::Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual void	draw();
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp
index 141b08c39d..a4e23a605b 100644
--- a/indra/llui/llresmgr.cpp
+++ b/indra/llui/llresmgr.cpp
@@ -43,106 +43,8 @@
 
 LLResMgr::LLResMgr()
 {
-	U32 i;
-
-	// Init values for each locale.
-	// Note: This is only the most bare-bones version.  In the future, load these dynamically, on demand.
-
-	//////////////////////////////////////////////////////////////////////////////
-	// USA
-	// USA Fonts
-	for( i=0; i<LLFONT_COUNT; i++ )
-	{
-		mUSAFonts[i] = NULL;
-	}
-	mUSAFonts[ LLFONT_OCRA ]			= LLFontGL::getFontMonospace();
-	mUSAFonts[ LLFONT_SANSSERIF ]		= LLFontGL::getFontSansSerif();
-	mUSAFonts[ LLFONT_SANSSERIF_SMALL ]	= LLFontGL::getFontSansSerifSmall();
-	mUSAFonts[ LLFONT_SANSSERIF_BIG ]	= LLFontGL::getFontSansSerifBig();
-	mUSAFonts[ LLFONT_SMALL ]			= LLFontGL::getFontMonospace();
-/*
-	// USA Strings
-	for( i=0; i<LLSTR_COUNT; i++ )
-	{
-		mUSAStrings[i] = "";
-	}
-	mUSAStrings[ LLSTR_HELLO ]			= "hello";
-	mUSAStrings[ LLSTR_GOODBYE ]		= "goodbye";
-	mUSAStrings[ LLSTR_CHAT_LABEL ]		= "Chat";
-	mUSAStrings[ LLSTR_STATUS_LABEL ]	= "Properties";
-	mUSAStrings[ LLSTR_X ]				= "X";
-	mUSAStrings[ LLSTR_Y ]				= "Y";
-	mUSAStrings[ LLSTR_Z ]				= "Z";
-	mUSAStrings[ LLSTR_POSITION ]		= "Position (meters)";
-	mUSAStrings[ LLSTR_SCALE ]			= "Size (meters)";
-	mUSAStrings[ LLSTR_ROTATION ]		= "Rotation (degrees)";
-	mUSAStrings[ LLSTR_HAS_PHYSICS ]	= "Has Physics";
-	mUSAStrings[ LLSTR_SCRIPT ]			= "Script";
-	mUSAStrings[ LLSTR_HELP ]			= "Help";
-	mUSAStrings[ LLSTR_REMOVE ]			= "Remove";
-	mUSAStrings[ LLSTR_CLEAR ]			= "Clear";
-	mUSAStrings[ LLSTR_APPLY ]			= "Apply";
-	mUSAStrings[ LLSTR_CANCEL ]			= "Cancel";
-	mUSAStrings[ LLSTR_MATERIAL ]		= "Material";
-	mUSAStrings[ LLSTR_FACE ]			= "Face";
-	mUSAStrings[ LLSTR_TEXTURE ]		= "Texture";
-	mUSAStrings[ LLSTR_TEXTURE_SIZE ]	= "Repeats per Face";
-	mUSAStrings[ LLSTR_TEXTURE_OFFSET ]	= "Offset";
-	mUSAStrings[ LLSTR_TEXTURE_ROTATION ]	= "Rotation (degrees)";
-	mUSAStrings[ LLSTR_U ]				= "U";
-	mUSAStrings[ LLSTR_V ]				= "V";
-	mUSAStrings[ LLSTR_OWNERSHIP ]		= "Ownership";
-	mUSAStrings[ LLSTR_PUBLIC ]			= "Public";
-	mUSAStrings[ LLSTR_PRIVATE ]		= "Private";
-	mUSAStrings[ LLSTR_REVERT ]			= "Revert";
-	mUSAStrings[ LLSTR_INSERT_SAMPLE ]	= "Insert Sample";
-	mUSAStrings[ LLSTR_SET_TEXTURE ]	= "Set Texture";
-	mUSAStrings[ LLSTR_EDIT_SCRIPT ]	= "Edit Script...";
-	mUSAStrings[ LLSTR_MOUSELOOK_INSTRUCTIONS ] = "Press ESC to leave Mouselook.";
-	mUSAStrings[ LLSTR_EDIT_FACE_INSTRUCTIONS ] = "Click on face to select part.  Click and hold on a picture to look more like that.  Press ESC to leave Face Edit Mode.";
-	mUSAStrings[ LLSTR_CLOSE ]			= "Close";
-	mUSAStrings[ LLSTR_MOVE ]			= "Move";
-	mUSAStrings[ LLSTR_ROTATE ]			= "Rotate";
-	mUSAStrings[ LLSTR_RESIZE ]			= "Resize";
-	mUSAStrings[ LLSTR_PLACE_BOX ]		= "Place Box";
-	mUSAStrings[ LLSTR_PLACE_PRISM ]	= "Place Prism";
-	mUSAStrings[ LLSTR_PLACE_PYRAMID ]	= "Place Pyramid";
-	mUSAStrings[ LLSTR_PLACE_TETRAHEDRON ]	= "Place Tetrahedron";
-	mUSAStrings[ LLSTR_PLACE_CYLINDER ]	= "Place Cylinder";
-	mUSAStrings[ LLSTR_PLACE_HALF_CYLINDER ] = "Place Half-Cylinder";
-	mUSAStrings[ LLSTR_PLACE_CONE ]		= "Place Cone";
-	mUSAStrings[ LLSTR_PLACE_HALF_CONE ] = "Place Half-Cone";
-	mUSAStrings[ LLSTR_PLACE_SPHERE ]	= "Place Sphere";
-	mUSAStrings[ LLSTR_PLACE_HALF_SPHERE ] = "Place Half-Sphere";
-	mUSAStrings[ LLSTR_PLACE_BIRD ]		= "Place Bird";
-	mUSAStrings[ LLSTR_PLACE_SNAKE ]	= "Place Silly Snake";
-	mUSAStrings[ LLSTR_PLACE_ROCK ]		= "Place Rock";
-	mUSAStrings[ LLSTR_PLACE_TREE ]		= "Place Tree";
-	mUSAStrings[ LLSTR_PLACE_GRASS ]	= "Place Grass";
-	mUSAStrings[ LLSTR_MODIFY_LAND ]	= "Modify Land";
-*/
-	//////////////////////////////////////////////////////////////////////////////
-	// UK
-	// The Brits are a lot like us Americans, so initially assume we're the same and only code the exceptions.
-
-	// UK Fonts
-	for( i=0; i<LLFONT_COUNT; i++ )
-	{
-		mUKFonts[i] = mUSAFonts[i];
-	}
-/*
-	// UK Strings
-	for( i=0; i<LLSTR_COUNT; i++ )
-	{
-		mUKStrings[i] = mUSAStrings[i];
-	}
-	mUKStrings[ LLSTR_HELLO ]			= "hullo";
-	mUKStrings[ LLSTR_GOODBYE ]			= "cheerio";
-*/
-	//////////////////////////////////////////////////////////////////////////////
 	// Set default
 	setLocale( LLLOCALE_USA );
-
 }
 
 
@@ -151,9 +53,9 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id )
 	mLocale = locale_id;
 
 	//RN: for now, use normal 'C' locale for everything but specific UI input/output routines
-	switch( locale_id )
-	{
-	case LLLOCALE_USA: 
+//	switch( locale_id )
+//	{
+//	case LLLOCALE_USA: 
 //#if LL_WINDOWS
 //		// Windows doesn't use ISO country codes.
 //		llinfos << "Setting locale to " << setlocale( LC_ALL, "english-usa" ) << llendl;
@@ -161,11 +63,8 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id )
 //		// posix version should work everywhere else.
 //		llinfos << "Setting locale to " << setlocale( LC_ALL, "en_US" ) << llendl;
 //#endif
-
-//		mStrings	= mUSAStrings;
-		mFonts		= mUSAFonts;
-		break;
-	case LLLOCALE_UK:
+//		break;
+//	case LLLOCALE_UK:
 //#if LL_WINDOWS
 //		// Windows doesn't use ISO country codes.
 //		llinfos << "Setting locale to " << setlocale( LC_ALL, "english-uk" ) << llendl;
@@ -173,15 +72,12 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id )
 //		// posix version should work everywhere else.
 //		llinfos << "Setting locale to " << setlocale( LC_ALL, "en_GB" ) << llendl;
 //#endif
-
-//		mStrings	= mUKStrings;
-		mFonts		= mUKFonts;
-		break;
-	default:
-		llassert(0);
-		setLocale(LLLOCALE_USA);
-		break;
-	}
+//		break;
+//	default:
+//		llassert(0);
+//		setLocale(LLLOCALE_USA);
+//		break;
+//	}
 }
 
 char LLResMgr::getDecimalPoint() const					
@@ -418,27 +314,6 @@ void LLResMgr::getIntegerString( std::string& output, S32 input ) const
 	}
 }
 
-const std::string LLFONT_ID_NAMES[] =
-{
-	std::string("OCRA"),
-	std::string("SANSSERIF"),
-	std::string("SANSSERIF_SMALL"),
-	std::string("SANSSERIF_BIG"),
-	std::string("SMALL"),
-};
-
-const LLFontGL* LLResMgr::getRes( std::string font_id ) const
-{
-	for (S32 i=0; i<LLFONT_COUNT; ++i)
-	{
-		if (LLFONT_ID_NAMES[i] == font_id)
-		{
-			return getRes((LLFONT_ID)i);
-		}
-	}
-	return NULL;
-}
-
 #if LL_WINDOWS
 const std::string LLLocale::USER_LOCALE("English_United States.1252");// = LLStringUtil::null;
 const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252");
diff --git a/indra/llui/llresmgr.h b/indra/llui/llresmgr.h
index d54505c503..c8fa340990 100644
--- a/indra/llui/llresmgr.h
+++ b/indra/llui/llresmgr.h
@@ -37,7 +37,7 @@
 #include "locale.h"
 #include "stdtypes.h"
 #include "llstring.h"
-#include "llmemory.h"
+#include "llsingleton.h"
 
 enum LLLOCALE_ID
 {
@@ -46,18 +46,6 @@ enum LLLOCALE_ID
 	LLLOCALE_COUNT	// Number of values in this enum.  Keep at end.
 };
 
-enum LLFONT_ID
-{
-	LLFONT_OCRA,
-	LLFONT_SANSSERIF,
-	LLFONT_SANSSERIF_SMALL,
-	LLFONT_SANSSERIF_BIG,
-	LLFONT_SMALL,
-	LLFONT_COUNT	// Number of values in this enum.  Keep at end.
-};
-
-class LLFontGL;
-
 class LLResMgr : public LLSingleton<LLResMgr>
 {
 public:
@@ -74,20 +62,9 @@ public:
 	std::string			getMonetaryString( S32 input ) const;
 	void				getIntegerString( std::string& output, S32 input ) const;
 
-//	const char*			getRes( LLSTR_ID string_id ) const		{ return mStrings[ string_id ]; }
-	const LLFontGL*		getRes( LLFONT_ID font_id ) const		{ return mFonts[ font_id ]; }
-	const LLFontGL*		getRes( std::string font_id ) const;
 
 private:
 	LLLOCALE_ID			mLocale;
-//	const char**		mStrings;
-	const LLFontGL**	mFonts;
-
-//	const char*			mUSAStrings[LLSTR_COUNT];
-	const LLFontGL*		mUSAFonts[LLFONT_COUNT];
-
-//	const char*			mUKStrings[LLSTR_COUNT];
-	const LLFontGL*		mUKFonts[LLFONT_COUNT];
 };
 
 class LLLocale
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index 65086d833d..1a2603420b 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -46,101 +46,84 @@
 #include "llwindow.h"
 #include "llcontrol.h"
 #include "llrender.h"
+#include "lluictrlfactory.h"
+
+static LLRegisterWidget<LLScrollbar> register_scrollbar("scroll_bar");
+
+LLScrollbar::Params::Params()
+:	orientation ("orientation", HORIZONTAL),
+	doc_size ("doc_size", 0),
+	doc_pos ("doc_pos", 0),
+	page_size ("page_size", 0),
+	step_size ("step_size", 1),
+	thumb_image("thumb_image"),
+	track_image("track_image"),
+	track_color("track_color"),
+	thumb_color("thumb_color"),
+	thickness("thickness"),
+	up_button("up_button"),
+	down_button("down_button")
+{
+	tab_stop = false;
+}
 
-LLScrollbar::LLScrollbar(
-		const std::string& name, LLRect rect,
-		LLScrollbar::ORIENTATION orientation,
-		S32 doc_size, S32 doc_pos, S32 page_size,
-		void (*change_callback)( S32 new_pos, LLScrollbar* self, void* userdata ),
-		void* callback_user_data,
-		S32 step_size)
-:		LLUICtrl( name, rect, TRUE, NULL, NULL ),
-
-		mChangeCallback( change_callback ),
-		mCallbackUserData( callback_user_data ),
-		mOrientation( orientation ),
-		mDocSize( doc_size ),
-		mDocPos( doc_pos ),
-		mPageSize( page_size ),
-		mStepSize( step_size ),
+LLScrollbar::LLScrollbar(const Params & p)
+:		LLUICtrl(p),
+		mChangeCallback( p.change_callback() ),
+		mOrientation( p.orientation ),
+		mDocSize( p.doc_size ),
+		mDocPos( p.doc_pos ),
+		mPageSize( p.page_size ),
+		mStepSize( p.step_size ),
 		mDocChanged(FALSE),
 		mDragStartX( 0 ),
 		mDragStartY( 0 ),
 		mHoverGlowStrength(0.15f),
 		mCurGlowStrength(0.f),
-		mTrackColor( LLUI::sColorsGroup->getColor("ScrollbarTrackColor") ),
-		mThumbColor ( LLUI::sColorsGroup->getColor("ScrollbarThumbColor") ),
-		mHighlightColor ( LLUI::sColorsGroup->getColor("DefaultHighlightLight") ),
-		mShadowColor ( LLUI::sColorsGroup->getColor("DefaultShadowLight") ),
+		mTrackColor( p.track_color() ),
+		mThumbColor ( p.thumb_color() ),
 		mOnScrollEndCallback( NULL ),
-		mOnScrollEndData( NULL )
+		mOnScrollEndData( NULL ),
+		mThumbImage(p.thumb_image),
+		mTrackImage(p.track_image),
+		mThickness(p.thickness.isProvided() ? p.thickness : LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize"))
 {
-	//llassert( 0 <= mDocSize );
-	//llassert( 0 <= mDocPos && mDocPos <= mDocSize );
-	
-	setTabStop(FALSE);
 	updateThumbRect();
 	
 	// Page up and page down buttons
 	LLRect line_up_rect;
-	std::string line_up_img;
-	std::string line_up_selected_img;
-	std::string line_down_img;
-	std::string line_down_selected_img;
-
 	LLRect line_down_rect;
 
-	if( LLScrollbar::VERTICAL == mOrientation )
+	if( VERTICAL == mOrientation )
 	{
-		line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), SCROLLBAR_SIZE, SCROLLBAR_SIZE );
-		line_up_img="UIImgBtnScrollUpOutUUID";
-		line_up_selected_img="UIImgBtnScrollUpInUUID";
-
-		line_down_rect.setOriginAndSize( 0, 0, SCROLLBAR_SIZE, SCROLLBAR_SIZE );
-		line_down_img="UIImgBtnScrollDownOutUUID";
-		line_down_selected_img="UIImgBtnScrollDownInUUID";
+		line_up_rect.setLeftTopAndSize( 0, getRect().getHeight(), mThickness, mThickness );
+		line_down_rect.setOriginAndSize( 0, 0, mThickness, mThickness );
 	}
-	else
+	else // HORIZONTAL
 	{
-		// Horizontal
-		line_up_rect.setOriginAndSize( 0, 0, SCROLLBAR_SIZE, SCROLLBAR_SIZE );
-		line_up_img="UIImgBtnScrollLeftOutUUID";
-		line_up_selected_img="UIImgBtnScrollLeftInUUID";
-
-		line_down_rect.setOriginAndSize( getRect().getWidth() - SCROLLBAR_SIZE, 0, SCROLLBAR_SIZE, SCROLLBAR_SIZE );
-		line_down_img="UIImgBtnScrollRightOutUUID";
-		line_down_selected_img="UIImgBtnScrollRightInUUID";
+		line_up_rect.setOriginAndSize( 0, 0, mThickness, mThickness );
+		line_down_rect.setOriginAndSize( getRect().getWidth() - mThickness, 0, mThickness, mThickness );
 	}
 
-	LLButton* line_up_btn = new LLButton(std::string("Line Up"), line_up_rect,
-										 line_up_img, line_up_selected_img, LLStringUtil::null,
-										 &LLScrollbar::onLineUpBtnPressed, this, LLFontGL::getFontSansSerif() );
-	if( LLScrollbar::VERTICAL == mOrientation )
-	{
-		line_up_btn->setFollowsRight();
-		line_up_btn->setFollowsTop();
-	}
-	else
-	{
-		// horizontal
-		line_up_btn->setFollowsLeft();
-		line_up_btn->setFollowsBottom();
-	}
-	line_up_btn->setHeldDownCallback( &LLScrollbar::onLineUpBtnPressed );
-	line_up_btn->setTabStop(FALSE);
-	line_up_btn->setScaleImage(TRUE);
-
-	addChild(line_up_btn);
-
-	LLButton* line_down_btn = new LLButton(std::string("Line Down"), line_down_rect,
-										   line_down_img, line_down_selected_img, LLStringUtil::null,
-										   &LLScrollbar::onLineDownBtnPressed, this, LLFontGL::getFontSansSerif() );
-	line_down_btn->setFollowsRight();
-	line_down_btn->setFollowsBottom();
-	line_down_btn->setHeldDownCallback( &LLScrollbar::onLineDownBtnPressed );
-	line_down_btn->setTabStop(FALSE);
-	line_down_btn->setScaleImage(TRUE);
-	addChild(line_down_btn);
+	LLButton::Params up_btn(mOrientation == VERTICAL ? p.up_button : p.left_button);
+	up_btn.name(std::string("Line Up"));
+	up_btn.rect(line_up_rect);
+	up_btn.click_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2));
+	up_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineUpBtnPressed, this, _2));
+	up_btn.tab_stop(false);
+	up_btn.follows.flags = (mOrientation == VERTICAL ? (FOLLOWS_RIGHT | FOLLOWS_TOP) : (FOLLOWS_LEFT | FOLLOWS_BOTTOM));
+
+	addChild(LLUICtrlFactory::create<LLButton>(up_btn));
+
+	LLButton::Params down_btn(mOrientation == VERTICAL ? p.down_button : p.right_button);
+	down_btn.name(std::string("Line Down"));
+	down_btn.rect(line_down_rect);
+	down_btn.follows.flags(FOLLOWS_RIGHT|FOLLOWS_BOTTOM);
+	down_btn.click_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2));
+	down_btn.mouse_held_callback.function(boost::bind(&LLScrollbar::onLineDownBtnPressed, this, _2));
+	down_btn.tab_stop(false);
+
+	addChild(LLUICtrlFactory::create<LLButton>(down_btn));
 }
 
 
@@ -168,7 +151,7 @@ void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
 
 		if( mChangeCallback )
 		{
-			mChangeCallback( mDocPos, this, mCallbackUserData );
+			mChangeCallback( mDocPos, this );
 		}
 
 		if( update_thumb )
@@ -221,7 +204,7 @@ void LLScrollbar::updateThumbRect()
 	const S32 THUMB_MIN_LENGTH = 16;
 
 	S32 window_length = (mOrientation == LLScrollbar::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight();
-	S32 thumb_bg_length = llmax(0, window_length - 2 * SCROLLBAR_SIZE);
+	S32 thumb_bg_length = llmax(0, window_length - 2 * mThickness);
 	S32 visible_lines = llmin( mDocSize, mPageSize );
 	S32 thumb_length = mDocSize ? llmin(llmax( visible_lines * thumb_bg_length / mDocSize, THUMB_MIN_LENGTH), thumb_bg_length) : thumb_bg_length;
 
@@ -229,24 +212,24 @@ void LLScrollbar::updateThumbRect()
 
 	if( mOrientation == LLScrollbar::VERTICAL )
 	{ 
-		S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE;
-		S32 thumb_start_min = SCROLLBAR_SIZE + THUMB_MIN_LENGTH;
+		S32 thumb_start_max = thumb_bg_length + mThickness;
+		S32 thumb_start_min = mThickness + THUMB_MIN_LENGTH;
 		S32 thumb_start = variable_lines ? llmin( llmax(thumb_start_max - (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_max;
 
 		mThumbRect.mLeft =  0;
 		mThumbRect.mTop = thumb_start;
-		mThumbRect.mRight = SCROLLBAR_SIZE;
+		mThumbRect.mRight = mThickness;
 		mThumbRect.mBottom = thumb_start - thumb_length;
 	}
 	else
 	{
 		// Horizontal
-		S32 thumb_start_max = thumb_bg_length + SCROLLBAR_SIZE - thumb_length;
-		S32 thumb_start_min = SCROLLBAR_SIZE;
+		S32 thumb_start_max = thumb_bg_length + mThickness - thumb_length;
+		S32 thumb_start_min = mThickness;
 		S32 thumb_start = variable_lines ? llmin(llmax( thumb_start_min + (mDocPos * (thumb_bg_length - thumb_length)) / variable_lines, thumb_start_min), thumb_start_max ) : thumb_start_min;
 	
 		mThumbRect.mLeft = thumb_start;
-		mThumbRect.mTop = SCROLLBAR_SIZE;
+		mThumbRect.mTop = mThickness;
 		mThumbRect.mRight = thumb_start + thumb_length;
 		mThumbRect.mBottom = 0;
 	}
@@ -318,21 +301,21 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
 //			S32 old_pos = mThumbRect.mTop;
 
 			S32 delta_pixels = y - mDragStartY;
-			if( mOrigRect.mBottom + delta_pixels < SCROLLBAR_SIZE )
+			if( mOrigRect.mBottom + delta_pixels < mThickness )
 			{
-				delta_pixels = SCROLLBAR_SIZE - mOrigRect.mBottom - 1;
+				delta_pixels = mThickness - mOrigRect.mBottom - 1;
 			}
 			else
-			if( mOrigRect.mTop + delta_pixels > height - SCROLLBAR_SIZE )
+			if( mOrigRect.mTop + delta_pixels > height - mThickness )
 			{
-				delta_pixels = height - SCROLLBAR_SIZE - mOrigRect.mTop + 1;
+				delta_pixels = height - mThickness - mOrigRect.mTop + 1;
 			}
 
 			mThumbRect.mTop = mOrigRect.mTop + delta_pixels;
 			mThumbRect.mBottom = mOrigRect.mBottom + delta_pixels;
 
 			S32 thumb_length = mThumbRect.getHeight();
-			S32 thumb_track_length = height - 2 * SCROLLBAR_SIZE;
+			S32 thumb_track_length = height - 2 * mThickness;
 
 
 			if( delta_pixels != mLastDelta || mDocChanged)
@@ -343,7 +326,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
 				{
 					S32 variable_lines = getDocPosMax();
 					S32 pos = mThumbRect.mTop;
-					F32 ratio = F32(pos - SCROLLBAR_SIZE - thumb_length) / usable_track_length;	
+					F32 ratio = F32(pos - mThickness - thumb_length) / usable_track_length;	
 	
 					S32 new_pos = llclamp( S32(variable_lines - ratio * variable_lines + 0.5f), 0, variable_lines );
 					// Note: we do not call updateThumbRect() here.  Instead we let the thumb and the document go slightly
@@ -362,21 +345,21 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
 
 			S32 delta_pixels = x - mDragStartX;
 
-			if( mOrigRect.mLeft + delta_pixels < SCROLLBAR_SIZE )
+			if( mOrigRect.mLeft + delta_pixels < mThickness )
 			{
-				delta_pixels = SCROLLBAR_SIZE - mOrigRect.mLeft - 1;
+				delta_pixels = mThickness - mOrigRect.mLeft - 1;
 			}
 			else
-			if( mOrigRect.mRight + delta_pixels > width - SCROLLBAR_SIZE )
+			if( mOrigRect.mRight + delta_pixels > width - mThickness )
 			{
-				delta_pixels = width - SCROLLBAR_SIZE - mOrigRect.mRight + 1;
+				delta_pixels = width - mThickness - mOrigRect.mRight + 1;
 			}
 
 			mThumbRect.mLeft = mOrigRect.mLeft + delta_pixels;
 			mThumbRect.mRight = mOrigRect.mRight + delta_pixels;
 			
 			S32 thumb_length = mThumbRect.getWidth();
-			S32 thumb_track_length = width - 2 * SCROLLBAR_SIZE;
+			S32 thumb_track_length = width - 2 * mThickness;
 
 			if( delta_pixels != mLastDelta || mDocChanged)
 			{	
@@ -386,7 +369,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
 				{
 					S32 variable_lines = getDocPosMax();
 					S32 pos = mThumbRect.mLeft;
-					F32 ratio = F32(pos - SCROLLBAR_SIZE) / usable_track_length;	
+					F32 ratio = F32(pos - mThickness) / usable_track_length;	
 	
 					S32 new_pos = llclamp( S32(ratio * variable_lines + 0.5f), 0, variable_lines);
 	
@@ -475,14 +458,14 @@ void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent)
 
 	if (mOrientation == VERTICAL)
 	{
-		up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE));
-		down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, SCROLLBAR_SIZE));
+		up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness));
+		down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness));
 		up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight());
 	}
 	else
 	{
-		up_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), up_button->getRect().getHeight());
-		down_button->reshape(llmin(getRect().getWidth() / 2, SCROLLBAR_SIZE), down_button->getRect().getHeight());
+		up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight());
+		down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight());
 		down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom);
 	}
 	updateThumbRect();
@@ -507,28 +490,25 @@ void LLScrollbar::draw()
 		mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f));
 	}
 
-
 	// Draw background and thumb.
-	LLUIImage* rounded_rect_imagep = LLUI::sImageProvider->getUIImage("rounded_square.tga");
-
-	if (!rounded_rect_imagep)
+	if (mTrackImage.isNull() || mThumbImage.isNull())
 	{
-		gl_rect_2d(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, 
-		mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(),
-		mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * SCROLLBAR_SIZE : getRect().getWidth(), 
-		mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0, mTrackColor, TRUE);
+		gl_rect_2d(mOrientation == HORIZONTAL ? mThickness : 0, 
+		mOrientation == VERTICAL ? getRect().getHeight() - 2 * mThickness : getRect().getHeight(),
+		mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * mThickness : getRect().getWidth(), 
+		mOrientation == VERTICAL ? mThickness : 0, mTrackColor.get(), TRUE);
 
-		gl_rect_2d(mThumbRect, mThumbColor, TRUE);
+		gl_rect_2d(mThumbRect, mThumbColor.get(), TRUE);
 
 	}
 	else
 	{
 		// Background
-		rounded_rect_imagep->drawSolid(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, 
-			mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0,
-			mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * SCROLLBAR_SIZE : getRect().getWidth(), 
-			mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(),
-			mTrackColor);
+		mTrackImage->drawSolid(mOrientation == HORIZONTAL ? mThickness : 0, 
+			mOrientation == VERTICAL ? mThickness : 0,
+			mOrientation == HORIZONTAL ? getRect().getWidth() - 2 * mThickness : getRect().getWidth(), 
+			mOrientation == VERTICAL ? getRect().getHeight() - 2 * mThickness : getRect().getHeight(),
+			mTrackColor.get());
 
 		// Thumb
 		LLRect outline_rect = mThumbRect;
@@ -536,14 +516,14 @@ void LLScrollbar::draw()
 
 		if (gFocusMgr.getKeyboardFocus() == this)
 		{
-			rounded_rect_imagep->draw(outline_rect, gFocusMgr.getFocusColor());
+			mTrackImage->draw(outline_rect, gFocusMgr.getFocusColor());
 		}
 
-		rounded_rect_imagep->draw(mThumbRect, mThumbColor);
+		mThumbImage->draw(mThumbRect, mThumbColor.get());
 		if (mCurGlowStrength > 0.01f)
 		{
 			gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-			rounded_rect_imagep->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
+			mThumbImage->drawSolid(mThumbRect, LLColor4(1.f, 1.f, 1.f, mCurGlowStrength));
 			gGL.setSceneBlendType(LLRender::BT_ALPHA);
 		}
 
@@ -625,19 +605,24 @@ void LLScrollbar::pageDown(S32 overlap)
 	}
 }
 
-// static
-void LLScrollbar::onLineUpBtnPressed( void* userdata )
+void LLScrollbar::onLineUpBtnPressed( const LLSD& data )
 {
-	LLScrollbar* self = (LLScrollbar*) userdata;
-
-	self->changeLine( - self->mStepSize, TRUE );
+	changeLine( -mStepSize, TRUE );
 }
 
-// static
-void LLScrollbar::onLineDownBtnPressed( void* userdata )
+void LLScrollbar::onLineDownBtnPressed( const LLSD& data )
 {
-	LLScrollbar* self = (LLScrollbar*) userdata;
-	self->changeLine( self->mStepSize, TRUE );
+	changeLine( mStepSize, TRUE );
 }
 
 
+namespace LLInitParam
+{
+    template<>
+	bool ParamCompare<boost::function<void (S32, LLScrollbar*)> >::equals(
+		const boost::function<void (S32, LLScrollbar*)> &a,
+		const boost::function<void (S32, LLScrollbar*)> &b) 
+	{
+		return false;
+	}
+}
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index 0bbf8662aa..43604d37b7 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -36,12 +36,7 @@
 #include "stdtypes.h"
 #include "lluictrl.h"
 #include "v4color.h"
-
-//
-// Constants
-//
-const S32 SCROLLBAR_SIZE = 16;
-
+#include "llbutton.h"
 
 //
 // Classes
@@ -50,15 +45,41 @@ class LLScrollbar
 : public LLUICtrl
 {
 public:
+
 	enum ORIENTATION { HORIZONTAL, VERTICAL };
+	
+	typedef boost::function<void (S32, LLScrollbar*)> callback_t;
+	struct Params 
+	:	public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Mandatory<ORIENTATION>			orientation;
+		Mandatory<S32>					doc_size;
+		Mandatory<S32>					doc_pos;
+		Mandatory<S32>					page_size;
+
+		Optional<callback_t> 			change_callback;
+		Optional<S32>					step_size;
+		Optional<S32>					thickness;
+
+		Optional<LLUIImage*>			thumb_image,
+										track_image;
 
-	LLScrollbar(const std::string& name, LLRect rect,
-		ORIENTATION orientation,
-		S32 doc_size, S32 doc_pos, S32 page_size,
-		void(*change_callback)( S32 new_pos, LLScrollbar* self, void* userdata ),
-		void* callback_user_data = NULL,
-		S32 step_size = 1);
+		Optional<LLUIColor>				track_color,
+										thumb_color;
 
+		Optional<LLButton::Params>		up_button;
+		Optional<LLButton::Params>		down_button;
+		Optional<LLButton::Params>		left_button;
+		Optional<LLButton::Params>		right_button;
+
+		Params();
+	};
+
+protected:
+	LLScrollbar (const Params & p);
+	friend class LLUICtrlFactory;
+
+public:
 	virtual ~LLScrollbar();
 
 	virtual void setValue(const LLSD& value);
@@ -101,13 +122,11 @@ public:
 	void				pageUp(S32 overlap);
 	void				pageDown(S32 overlap);
 
-	static void			onLineUpBtnPressed(void* userdata);
-	static void			onLineDownBtnPressed(void* userdata);
+	void				onLineUpBtnPressed(const LLSD& data);
+	void				onLineDownBtnPressed(const LLSD& data);
 
 	void setTrackColor( const LLColor4& color ) { mTrackColor = color; }
 	void setThumbColor( const LLColor4& color ) { mThumbColor = color; }
-	void setHighlightColor( const LLColor4& color ) { mHighlightColor = color; }
-	void setShadowColor( const LLColor4& color ) { mShadowColor = color; }
 
 	void setOnScrollEndCallback(void (*callback)(void*), void* userdata) { mOnScrollEndCallback = callback; mOnScrollEndData = userdata;}
 
@@ -115,8 +134,7 @@ private:
 	void				updateThumbRect();
 	void				changeLine(S32 delta, BOOL update_thumb );
 
-	void				(*mChangeCallback)( S32 new_pos, LLScrollbar* self, void* userdata );
-	void*				mCallbackUserData;
+	callback_t			mChangeCallback;
 
 	const ORIENTATION	mOrientation;	
 	S32					mDocSize;		// Size of the document that the scrollbar is modeling.  Units depend on the user.  0 <= mDocSize.
@@ -134,16 +152,24 @@ private:
 	LLRect				mOrigRect;
 	S32					mLastDelta;
 
-	LLColor4			mTrackColor;
-	LLColor4			mThumbColor;
-	LLColor4			mFocusColor;
-	LLColor4			mHighlightColor;
-	LLColor4			mShadowColor;
+	LLUIColor			mTrackColor;
+	LLUIColor			mThumbColor;
+
+	LLUIImagePtr		mThumbImage;
+	LLUIImagePtr		mTrackImage;
+
+	S32					mThickness;
 
 	void			(*mOnScrollEndCallback)(void*);
 	void			*mOnScrollEndData;
 };
 
 
+namespace LLInitParam
+{
+    template<>
+	bool ParamCompare<boost::function<void (S32, LLScrollbar*)> >::equals(
+		const boost::function<void (S32, LLScrollbar*)> &a, const boost::function<void (S32, LLScrollbar*)> &b); 
+}
 
 #endif  // LL_SCROLLBAR_H
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index cf03259879..dfe3ef29fc 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -1,6 +1,6 @@
 /** 
  * @file llscrollcontainer.cpp
- * @brief LLScrollableContainerView base class
+ * @brief LLScrollContainer base class
  *
  * $LicenseInfo:firstyear=2001&license=viewergpl$
  * 
@@ -33,8 +33,12 @@
 
 #include "linden_common.h"
 
-#include "llrender.h"
 #include "llscrollcontainer.h"
+
+#include "llrender.h"
+#include "llcontainerview.h"
+// #include "llfolderview.h"
+#include "llscrollingpanellist.h"
 #include "llscrollbar.h"
 #include "llui.h"
 #include "llkeyboard.h"
@@ -42,6 +46,7 @@
 #include "llfocusmgr.h"
 #include "llframetimer.h"
 #include "lluictrlfactory.h"
+#include "llpanel.h"
 #include "llfontgl.h"
 
 ///----------------------------------------------------------------------------
@@ -55,98 +60,79 @@ static const F32 MAX_AUTO_SCROLL_RATE = 500.f;
 static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f;
 
 ///----------------------------------------------------------------------------
-/// Class LLScrollableContainerView
+/// Class LLScrollContainer
 ///----------------------------------------------------------------------------
 
-static LLRegisterWidget<LLScrollableContainerView> r("scroll_container");
+static LLRegisterWidget<LLScrollContainer> r("scroll_container");
 
-// Default constructor
-LLScrollableContainerView::LLScrollableContainerView( const std::string& name,
-													  const LLRect& rect,
-													  LLView* scrolled_view,
-													  BOOL is_opaque,
-													  const LLColor4& bg_color ) :
-	LLUICtrl( name, rect, FALSE, NULL, NULL ),
-	mScrolledView( scrolled_view ),
-	mIsOpaque( is_opaque ),
-	mBackgroundColor( bg_color ),
-	mReserveScrollCorner( FALSE ),
-	mAutoScrolling( FALSE ),
-	mAutoScrollRate( 0.f )
+LLScrollContainer::Params::Params()
+:	is_opaque("opaque"),
+	bg_color("color"),
+	reserve_scroll_corner("reserve_scroll_corner", false)
 {
-	if( mScrolledView )
-	{
-		addChild( mScrolledView );
-	}
-
-	init();
+	name = "scroll_container";
+	mouse_opaque(true);
+	tab_stop(false);
 }
 
-// LLUICtrl constructor
-LLScrollableContainerView::LLScrollableContainerView( const std::string& name, const LLRect& rect,
-							   LLUICtrl* scrolled_ctrl, BOOL is_opaque,
-							   const LLColor4& bg_color) :
-	LLUICtrl( name, rect, FALSE, NULL, NULL ),
-	mScrolledView( scrolled_ctrl ),
-	mIsOpaque( is_opaque ),
-	mBackgroundColor( bg_color ),
-	mReserveScrollCorner( FALSE ),
-	mAutoScrolling( FALSE ),
-	mAutoScrollRate( 0.f )
-{
-	if( scrolled_ctrl )
-	{
-		addChild( scrolled_ctrl );
-	}
 
-	init();
-}
-
-void LLScrollableContainerView::init()
+// Default constructor
+LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
+:	LLUICtrl(p),
+	mAutoScrolling( FALSE ),
+	mAutoScrollRate( 0.f ),
+	mBackgroundColor(p.bg_color()),
+	mIsOpaque(p.is_opaque),
+	mReserveScrollCorner(p.reserve_scroll_corner),
+	mScrolledView(NULL)
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
-	mBorder = new LLViewBorder( std::string("scroll border"), border_rect, LLViewBorder::BEVEL_IN );
-	addChild( mBorder );
+	LLViewBorder::Params params;
+	params.name("scroll border");
+	params.rect(border_rect);
+	params.bevel_type(LLViewBorder::BEVEL_IN);
+	mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
+	LLView::addChild( mBorder );
 
 	mInnerRect.set( 0, getRect().getHeight(), getRect().getWidth(), 0 );
 	mInnerRect.stretch( -mBorder->getBorderWidth()  );
 
 	LLRect vertical_scroll_rect = mInnerRect;
-	vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - SCROLLBAR_SIZE;
-	mScrollbar[VERTICAL] = new LLScrollbar( std::string("scrollable vertical"),
-											vertical_scroll_rect,
-											LLScrollbar::VERTICAL,
-											mInnerRect.getHeight(), 
-											0,
-											mInnerRect.getHeight(),
-											NULL, this,
-											VERTICAL_MULTIPLE);
-	addChild( mScrollbar[VERTICAL] );
+	vertical_scroll_rect.mLeft = vertical_scroll_rect.mRight - scrollbar_size;
+	LLScrollbar::Params sbparams;
+	sbparams.name("scrollable vertical");
+	sbparams.rect(vertical_scroll_rect);
+	sbparams.orientation(LLScrollbar::VERTICAL);
+	sbparams.doc_size(mInnerRect.getHeight());
+	sbparams.doc_pos(0);
+	sbparams.page_size(mInnerRect.getHeight());
+	sbparams.step_size(VERTICAL_MULTIPLE);
+	mScrollbar[VERTICAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
+	LLView::addChild( mScrollbar[VERTICAL] );
 	mScrollbar[VERTICAL]->setVisible( FALSE );
 	mScrollbar[VERTICAL]->setFollowsRight();
 	mScrollbar[VERTICAL]->setFollowsTop();
 	mScrollbar[VERTICAL]->setFollowsBottom();
 	
 	LLRect horizontal_scroll_rect = mInnerRect;
-	horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + SCROLLBAR_SIZE;
-	mScrollbar[HORIZONTAL] = new LLScrollbar( std::string("scrollable horizontal"),
-											  horizontal_scroll_rect,
-											  LLScrollbar::HORIZONTAL,
-											  mInnerRect.getWidth(),
-											  0,
-											  mInnerRect.getWidth(),
-											  NULL, this,
-											  HORIZONTAL_MULTIPLE);
-	addChild( mScrollbar[HORIZONTAL] );
+	horizontal_scroll_rect.mTop = horizontal_scroll_rect.mBottom + scrollbar_size;
+	sbparams.name("scrollable horizontal");
+	sbparams.rect(horizontal_scroll_rect);
+	sbparams.orientation(LLScrollbar::HORIZONTAL);
+	sbparams.doc_size(mInnerRect.getWidth());
+	sbparams.doc_pos(0);
+	sbparams.page_size(mInnerRect.getWidth());
+	sbparams.step_size(VERTICAL_MULTIPLE);
+	mScrollbar[HORIZONTAL] = LLUICtrlFactory::create<LLScrollbar> (sbparams);
+	LLView::addChild( mScrollbar[HORIZONTAL] );
 	mScrollbar[HORIZONTAL]->setVisible( FALSE );
 	mScrollbar[HORIZONTAL]->setFollowsLeft();
 	mScrollbar[HORIZONTAL]->setFollowsRight();
-
-	setTabStop(FALSE);
 }
 
 // Destroys the object
-LLScrollableContainerView::~LLScrollableContainerView( void )
+LLScrollContainer::~LLScrollContainer( void )
 {
 	// mScrolledView and mScrollbar are child views, so the LLView
 	// destructor takes care of memory deallocation.
@@ -159,9 +145,9 @@ LLScrollableContainerView::~LLScrollableContainerView( void )
 
 // internal scrollbar handlers
 // virtual
-void LLScrollableContainerView::scrollHorizontal( S32 new_pos )
+void LLScrollContainer::scrollHorizontal( S32 new_pos )
 {
-	//llinfos << "LLScrollableContainerView::scrollHorizontal()" << llendl;
+	//llinfos << "LLScrollContainer::scrollHorizontal()" << llendl;
 	if( mScrolledView )
 	{
 		LLRect doc_rect = mScrolledView->getRect();
@@ -171,9 +157,9 @@ void LLScrollableContainerView::scrollHorizontal( S32 new_pos )
 }
 
 // virtual
-void LLScrollableContainerView::scrollVertical( S32 new_pos )
+void LLScrollContainer::scrollVertical( S32 new_pos )
 {
-	// llinfos << "LLScrollableContainerView::scrollVertical() " << new_pos << llendl;
+	// llinfos << "LLScrollContainer::scrollVertical() " << new_pos << llendl;
 	if( mScrolledView )
 	{
 		LLRect doc_rect = mScrolledView->getRect();
@@ -183,7 +169,7 @@ void LLScrollableContainerView::scrollVertical( S32 new_pos )
 }
 
 // LLView functionality
-void LLScrollableContainerView::reshape(S32 width, S32 height,
+void LLScrollContainer::reshape(S32 width, S32 height,
 										BOOL called_from_parent)
 {
 	LLUICtrl::reshape( width, height, called_from_parent );
@@ -209,7 +195,7 @@ void LLScrollableContainerView::reshape(S32 width, S32 height,
 	}
 }
 
-BOOL LLScrollableContainerView::handleKeyHere(KEY key, MASK mask)
+BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
 {
 	for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
 	{
@@ -222,7 +208,7 @@ BOOL LLScrollableContainerView::handleKeyHere(KEY key, MASK mask)
 	return FALSE;
 }
 
-BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks )
+BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
 {
 	for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
 	{
@@ -239,7 +225,7 @@ BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks )
 	return TRUE;
 }
 
-BOOL LLScrollableContainerView::needsToScroll(S32 x, S32 y, LLScrollableContainerView::SCROLL_ORIENTATION axis) const
+BOOL LLScrollContainer::needsToScroll(S32 x, S32 y, LLScrollContainer::SCROLL_ORIENTATION axis) const
 {
 	if(mScrollbar[axis]->getVisible())
 	{
@@ -247,7 +233,8 @@ BOOL LLScrollableContainerView::needsToScroll(S32 x, S32 y, LLScrollableContaine
 		const S32 AUTOSCROLL_SIZE = 10;
 		if(mScrollbar[axis]->getVisible())
 		{
-			inner_rect_local.mRight -= SCROLLBAR_SIZE;
+			static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+			inner_rect_local.mRight -= scrollbar_size;
 			inner_rect_local.mTop += AUTOSCROLL_SIZE;
 			inner_rect_local.mBottom = inner_rect_local.mTop - AUTOSCROLL_SIZE;
 		}
@@ -260,13 +247,14 @@ BOOL LLScrollableContainerView::needsToScroll(S32 x, S32 y, LLScrollableContaine
 	return FALSE;
 }
 
-BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
+BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,
 												  BOOL drop,
 												  EDragAndDropType cargo_type,
 												  void* cargo_data,
 												  EAcceptance* accept,
 												  std::string& tooltip_msg)
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	// Scroll folder view if needed.  Never accepts a drag or drop.
 	*accept = ACCEPT_NO;
 	BOOL handled = FALSE;
@@ -278,11 +266,11 @@ BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
 		LLRect inner_rect_local( 0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0 );
 		if(	mScrollbar[HORIZONTAL]->getVisible() )
 		{
-			inner_rect_local.mBottom += SCROLLBAR_SIZE;
+			inner_rect_local.mBottom += scrollbar_size;
 		}
 		if(	mScrollbar[VERTICAL]->getVisible() )
 		{
-			inner_rect_local.mRight -= SCROLLBAR_SIZE;
+			inner_rect_local.mRight -= scrollbar_size;
 		}
 
 		if(	mScrollbar[HORIZONTAL]->getVisible() )
@@ -337,7 +325,7 @@ BOOL LLScrollableContainerView::handleDragAndDrop(S32 x, S32 y, MASK mask,
 }
 
 
-BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect)
+BOOL LLScrollContainer::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect)
 {
 	S32 local_x, local_y;
 	for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
@@ -364,14 +352,15 @@ BOOL LLScrollableContainerView::handleToolTip(S32 x, S32 y, std::string& msg, LL
 	return TRUE;
 }
 
-void LLScrollableContainerView::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
+void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
 {
 	const LLRect& rect = mScrolledView->getRect();
 	calcVisibleSize(rect, visible_width, visible_height, show_h_scrollbar, show_v_scrollbar);
 }
 
-void LLScrollableContainerView::calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
+void LLScrollContainer::calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	S32 doc_width = doc_rect.getWidth();
 	S32 doc_height = doc_rect.getHeight();
 
@@ -382,26 +371,28 @@ void LLScrollableContainerView::calcVisibleSize( const LLRect& doc_rect, S32 *vi
 	if( *visible_height < doc_height )
 	{
 		*show_v_scrollbar = TRUE;
-		*visible_width -= SCROLLBAR_SIZE;
+		*visible_width -= scrollbar_size;
 	}
 
 	*show_h_scrollbar = FALSE;
 	if( *visible_width < doc_width )
 	{
 		*show_h_scrollbar = TRUE;
-		*visible_height -= SCROLLBAR_SIZE;
+		*visible_height -= scrollbar_size;
 
 		// Must retest now that visible_height has changed
 		if( !*show_v_scrollbar && (*visible_height < doc_height) )
 		{
 			*show_v_scrollbar = TRUE;
-			*visible_width -= SCROLLBAR_SIZE;
+			*visible_width -= scrollbar_size;
 		}
 	}
 }
+	
 
-void LLScrollableContainerView::draw()
+void LLScrollContainer::draw()
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	if (mAutoScrolling)
 	{
 		// add acceleration to autoscroll
@@ -427,7 +418,7 @@ void LLScrollableContainerView::draw()
 	if( mIsOpaque )
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.color4fv( mBackgroundColor.mV );
+		gGL.color4fv( mBackgroundColor.get().mV );
 		gl_rect_2d( mInnerRect );
 	}
 	
@@ -448,9 +439,9 @@ void LLScrollableContainerView::draw()
 			calcVisibleSize( mScrolledView->getRect(), &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
 
 			LLLocalClipRect clip(LLRect(mInnerRect.mLeft, 
-					mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0) + visible_height,
+					mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0) + visible_height,
 					visible_width,
-					mInnerRect.mBottom + (show_h_scrollbar ? SCROLLBAR_SIZE : 0)
+					mInnerRect.mBottom + (show_h_scrollbar ? scrollbar_size : 0)
 					));
 			drawChild(mScrolledView);
 		}
@@ -487,10 +478,44 @@ void LLScrollableContainerView::draw()
 		drawDebugRect();
 	}
 
+	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
+	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
+	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
+	//{
+	//	drawDebugRect();
+	//}
+
 } // end draw
 
-void LLScrollableContainerView::updateScroll()
+bool LLScrollContainer::addChild(LLView* view, S32 tab_group)
 {
+	if (!mScrolledView)
+	{
+		//*TODO: Move LLFolderView to llui and enable this check
+// 		if (dynamic_cast<LLPanel*>(view) || dynamic_cast<LLContainerView*>(view) || dynamic_cast<LLScrollingPanelList*>(view) || dynamic_cast<LLFolderView*>(view))
+		{
+			// Use the first panel or container as the scrollable view (bit of a hack)
+			mScrolledView = view;
+		}
+	}
+
+	bool ret_val = LLView::addChild(view, tab_group);
+
+	//bring the scrollbars to the front
+	sendChildToFront( mScrollbar[HORIZONTAL] );
+	sendChildToFront( mScrollbar[VERTICAL] );
+
+	return ret_val;
+}
+
+
+void LLScrollContainer::updateScroll()
+{
+	if (!mScrolledView)
+	{
+		return;
+	}
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	LLRect doc_rect = mScrolledView->getRect();
 	S32 doc_width = doc_rect.getWidth();
 	S32 doc_height = doc_rect.getHeight();
@@ -514,15 +539,15 @@ void LLScrollableContainerView::updateScroll()
 		S32 v_scrollbar_height = visible_height;
 		if( !show_h_scrollbar && mReserveScrollCorner )
 		{
-			v_scrollbar_height -= SCROLLBAR_SIZE;
+			v_scrollbar_height -= scrollbar_size;
 		}
-		mScrollbar[VERTICAL]->reshape( SCROLLBAR_SIZE, v_scrollbar_height, TRUE );
+		mScrollbar[VERTICAL]->reshape( scrollbar_size, v_scrollbar_height, TRUE );
 
 		// Make room for the horizontal scrollbar (or not)
 		S32 v_scrollbar_offset = 0;
 		if( show_h_scrollbar || mReserveScrollCorner )
 		{
-			v_scrollbar_offset = SCROLLBAR_SIZE;
+			v_scrollbar_offset = scrollbar_size;
 		}
 		LLRect r = mScrollbar[VERTICAL]->getRect();
 		r.translate( 0, mInnerRect.mBottom - r.mBottom + v_scrollbar_offset );
@@ -552,9 +577,9 @@ void LLScrollableContainerView::updateScroll()
 		S32 h_scrollbar_width = visible_width;
 		if( !show_v_scrollbar && mReserveScrollCorner )
 		{
-			h_scrollbar_width -= SCROLLBAR_SIZE;
+			h_scrollbar_width -= scrollbar_size;
 		}
-		mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, SCROLLBAR_SIZE, TRUE );
+		mScrollbar[HORIZONTAL]->reshape( h_scrollbar_width, scrollbar_size, TRUE );
 	}
 	else
 	{
@@ -571,17 +596,17 @@ void LLScrollableContainerView::updateScroll()
 	mScrollbar[VERTICAL]->setPageSize( visible_height );
 } // end updateScroll
 
-void LLScrollableContainerView::setBorderVisible(BOOL b)
+void LLScrollContainer::setBorderVisible(BOOL b)
 {
 	mBorder->setVisible( b );
 }
 
 // Scroll so that as much of rect as possible is showing (where rect is defined in the space of scroller view, not scrolled)
-void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset)
+void LLScrollContainer::scrollToShowRect(const LLRect& rect, const LLCoordGL& desired_offset)
 {
 	if (!mScrolledView)
 	{
-		llwarns << "LLScrollableContainerView::scrollToShowRect with no view!" << llendl;
+		llwarns << "LLScrollContainer::scrollToShowRect with no view!" << llendl;
 		return;
 	}
 
@@ -646,27 +671,27 @@ void LLScrollableContainerView::scrollToShowRect(const LLRect& rect, const LLCoo
 	updateScroll();
 }
 
-void LLScrollableContainerView::pageUp(S32 overlap)
+void LLScrollContainer::pageUp(S32 overlap)
 {
 	mScrollbar[VERTICAL]->pageUp(overlap);
 }
 
-void LLScrollableContainerView::pageDown(S32 overlap)
+void LLScrollContainer::pageDown(S32 overlap)
 {
 	mScrollbar[VERTICAL]->pageDown(overlap);
 }
 
-void LLScrollableContainerView::goToTop()
+void LLScrollContainer::goToTop()
 {
 	mScrollbar[VERTICAL]->setDocPos(0);
 }
 
-void LLScrollableContainerView::goToBottom()
+void LLScrollContainer::goToBottom()
 {
 	mScrollbar[VERTICAL]->setDocPos(mScrollbar[VERTICAL]->getDocSize());
 }
 
-S32 LLScrollableContainerView::getBorderWidth() const
+S32 LLScrollContainer::getBorderWidth() const
 {
 	if (mBorder)
 	{
@@ -676,73 +701,3 @@ S32 LLScrollableContainerView::getBorderWidth() const
 	return 0;
 }
 
-// virtual
-LLXMLNodePtr LLScrollableContainerView::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLView::getXML();
-
-	// Attributes
-
-	node->createChild("opaque", TRUE)->setBoolValue(mIsOpaque);
-
-	if (mIsOpaque)
-	{
-		node->createChild("color", TRUE)->setFloatValue(4, mBackgroundColor.mV);
-	}
-
-	// Contents
-
-	LLXMLNodePtr child_node = mScrolledView->getXML();
-
-	node->addChild(child_node);
-
-	return node;
-}
-
-LLView* LLScrollableContainerView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("scroll_container");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-	
-	BOOL opaque = FALSE;
-	node->getAttributeBOOL("opaque", opaque);
-
-	LLColor4 color(0,0,0,0);
-	LLUICtrlFactory::getAttributeColor(node,"color", color);
-
-	// Create the scroll view
-	LLScrollableContainerView *ret = new LLScrollableContainerView(name, rect, (LLPanel*)NULL, opaque, color);
-
-	LLPanel* panelp = NULL;
-
-	// Find a child panel to add
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		LLView *control = factory->createCtrlWidget(panelp, child);
-		if (control && control->isPanel())
-		{
-			if (panelp)
-			{
-				llinfos << "Warning! Attempting to put multiple panels into a scrollable container view!" << llendl;
-				delete control;
-			}
-			else
-			{
-				panelp = (LLPanel*)control;
-			}
-		}
-	}
-
-	if (panelp == NULL)
-	{
-		panelp = new LLPanel(std::string("dummy"), LLRect::null, FALSE);
-	}
-
-	ret->mScrolledView = panelp;
-
-	return ret;
-}
diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h
index 70fc9087d7..7e207645ff 100644
--- a/indra/llui/llscrollcontainer.h
+++ b/indra/llui/llscrollcontainer.h
@@ -1,6 +1,6 @@
 /** 
  * @file llscrollcontainer.h
- * @brief LLScrollableContainerView class header file.
+ * @brief LLScrollContainer class header file.
  *
  * $LicenseInfo:firstyear=2001&license=viewergpl$
  * 
@@ -53,24 +53,28 @@ class LLUICtrlFactory;
  * the width and height of the view you're scrolling.
  *
  *****************************************************************************/
-class LLScrollableContainerView : public LLUICtrl
+class LLScrollContainer : public LLUICtrl
 {
 public:
 	// Note: vertical comes before horizontal because vertical
 	// scrollbars have priority for mouse and keyboard events.
 	enum SCROLL_ORIENTATION { VERTICAL, HORIZONTAL, SCROLLBAR_COUNT };
 
-	LLScrollableContainerView( const std::string& name, const LLRect& rect,
-							   LLView* scrolled_view, BOOL is_opaque = FALSE,
-							   const LLColor4& bg_color = LLColor4(0,0,0,0) );
-	LLScrollableContainerView( const std::string& name, const LLRect& rect,
-							   LLUICtrl* scrolled_ctrl, BOOL is_opaque = FALSE,
-							   const LLColor4& bg_color = LLColor4(0,0,0,0) );
-	virtual ~LLScrollableContainerView( void );
-
-	void setScrolledView(LLView* view) { mScrolledView = view; }
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<bool>		is_opaque;
+		Optional<LLUIColor>	bg_color;
+		Optional<bool>		reserve_scroll_corner;
+		
+		Params();
+	};
+protected:
+	LLScrollContainer(const Params&);
+	friend class LLUICtrlFactory;
+public:
+	virtual ~LLScrollContainer( void );
 
-	virtual void setValue(const LLSD& value) { mInnerRect.setValue(value); }
+	virtual void 	setValue(const LLSD& value) { mInnerRect.setValue(value); }
 
 	void			calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const;
 	void			calcVisibleSize( const LLRect& doc_rect, S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const;
@@ -99,13 +103,9 @@ public:
 
 	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect);
 	virtual void	draw();
-
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	virtual bool	addChild(LLView* view, S32 tab_group = 0);
 
 private:
-	void init();
-
 	// internal scrollbar handlers
 	virtual void scrollHorizontal( S32 new_pos );
 	virtual void scrollVertical( S32 new_pos );
@@ -115,7 +115,7 @@ private:
 	LLView*		mScrolledView;
 	S32			mSize;
 	BOOL		mIsOpaque;
-	LLColor4	mBackgroundColor;
+	LLUIColor	mBackgroundColor;
 	LLRect		mInnerRect;
 	LLViewBorder* mBorder;
 	BOOL		mReserveScrollCorner;
diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp
index 05d0c6f753..bfeb35704a 100644
--- a/indra/llui/llscrollingpanellist.cpp
+++ b/indra/llui/llscrollingpanellist.cpp
@@ -52,9 +52,9 @@ void LLScrollingPanelList::clearPanels()
 
 void LLScrollingPanelList::addPanel( LLScrollingPanel* panel )
 {
-	addChildAtEnd( panel );
+	addChildInBack( panel );
 	mPanelList.push_front( panel );
-	
+
 	const S32 GAP_BETWEEN_PANELS = 6;
 
 	// Resize this view
@@ -82,7 +82,48 @@ void LLScrollingPanelList::addPanel( LLScrollingPanel* panel )
 		cur_y -= GAP_BETWEEN_PANELS;
 	}
 }
-	
+
+void LLScrollingPanelList::removePanel( U32 panel_index )
+{
+	if ( mPanelList.empty() || panel_index >= mPanelList.size() )
+	{
+		llwarns << "Panel index " << panel_index << " is out of range!" << llendl;
+		return;
+	}
+	else
+	{
+		removeChild( mPanelList.at(panel_index) );
+		mPanelList.erase( mPanelList.begin() + panel_index );
+	}
+
+	const S32 GAP_BETWEEN_PANELS = 6;
+
+	// Resize this view
+	S32 total_height = 0;
+	S32 max_width = 0;
+	S32 cur_gap = 0;
+	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
+		 iter != mPanelList.end(); ++iter)
+	{
+		LLScrollingPanel *childp = *iter;
+		total_height += childp->getRect().getHeight() + cur_gap;
+		max_width = llmax( max_width, childp->getRect().getWidth() );
+		cur_gap = GAP_BETWEEN_PANELS;
+	}
+	reshape( max_width, total_height, FALSE );
+
+	// Reposition each of the child views
+	S32 cur_y = total_height;
+	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
+		 iter != mPanelList.end(); ++iter)
+	{
+		LLScrollingPanel *childp = *iter;
+		cur_y -= childp->getRect().getHeight();
+		childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom);
+		cur_y -= GAP_BETWEEN_PANELS;
+	}
+}
+
 void LLScrollingPanelList::updatePanels(BOOL allow_modify)
 {
     for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
@@ -138,18 +179,3 @@ void LLScrollingPanelList::draw()
 	LLUICtrl::draw();
 }
 
-
-// static
-LLView* LLScrollingPanelList::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-    std::string name("scrolling_panel_list");
-    node->getAttributeString("name", name);
-
-    LLRect rect;
-    createRect(node, rect, parent, LLRect());
-
-    LLScrollingPanelList* scrolling_panel_list = new LLScrollingPanelList(name, rect);
-    scrolling_panel_list->initFromXML(node, parent);
-    return scrolling_panel_list;
-}
-
diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h
index b9d730978f..5dc23facda 100644
--- a/indra/llui/llscrollingpanellist.h
+++ b/indra/llui/llscrollingpanellist.h
@@ -29,6 +29,9 @@
  * $/LicenseInfo$
  */
 
+#ifndef LL_LLSCROLLINGPANELLIST_H
+#define LL_LLSCROLLINGPANELLIST_H
+
 #include <vector>
 
 #include "llui.h"
@@ -42,7 +45,7 @@
 class LLScrollingPanel : public LLPanel
 {
 public:
-	LLScrollingPanel(const std::string& name, const LLRect& rect) : LLPanel(name, rect) { }
+	LLScrollingPanel(const LLPanel::Params& params) : LLPanel(params) {}
 	virtual void updatePanel(BOOL allow_modify) = 0;
 };
 
@@ -53,23 +56,34 @@ public:
 class LLScrollingPanelList : public LLUICtrl
 {
 public:
-	LLScrollingPanelList(const std::string& name, const LLRect& rect)
-		:	LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_BOTTOM ) {}
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Params()
+		{
+			name = "scrolling_panel_list";
+			follows.flags = FOLLOWS_LEFT | FOLLOWS_BOTTOM;
+		}
+	};
+	LLScrollingPanelList(const Params& p)
+	:	LLUICtrl(p) 
+	{}
+	
+	typedef std::deque<LLScrollingPanel*>	panel_list_t;
 
 	virtual void setValue(const LLSD& value) {};
 
-	virtual LLXMLNodePtr getXML(bool save_children) const { return LLUICtrl::getXML(); }
-	
 	virtual void		draw();
 
 	void				clearPanels();
 	void				addPanel( LLScrollingPanel* panel );
+	void				removePanel( U32 panel_index );
 	void				updatePanels(BOOL allow_modify);
+	const panel_list_t&	getPanelList() { return mPanelList; }
 
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-	
 private:
 	void				updatePanelVisiblilty();
 
-	std::deque<LLScrollingPanel*> mPanelList;
+	panel_list_t		mPanelList;
 };
+
+#endif //LL_LLSCROLLINGPANELLIST_H
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
new file mode 100644
index 0000000000..4e6de24160
--- /dev/null
+++ b/indra/llui/llscrolllistcell.cpp
@@ -0,0 +1,413 @@
+/** 
+ * @file llscrolllistcell.cpp
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llscrolllistcell.h"
+
+#include "llcheckboxctrl.h"
+#include "llui.h"	// LLUIImage
+#include "lluictrlfactory.h"
+
+//static 
+LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_p)
+{
+	LLScrollListCell* cell = NULL;
+
+	if (cell_p.type() == "icon")
+	{
+		cell = new LLScrollListIcon(cell_p);
+	}
+	else if (cell_p.type() == "checkbox")
+	{
+		cell = new LLScrollListCheck(cell_p);
+	}
+	else if (cell_p.type() == "date")
+	{
+		cell = new LLScrollListDate(cell_p);
+	}
+	else	// default is "text"
+	{
+		cell = new LLScrollListText(cell_p);
+	}
+
+	if (cell_p.value.isProvided())
+	{
+		cell->setValue(cell_p.value);
+	}
+
+	return cell;
+}
+
+
+LLScrollListCell::LLScrollListCell(const LLScrollListCell::Params& p)
+:	mWidth(p.width)
+{}
+
+// virtual
+const LLSD LLScrollListCell::getValue() const
+{
+	return LLStringUtil::null;
+}
+
+//
+// LLScrollListIcon
+//
+LLScrollListIcon::LLScrollListIcon(const LLScrollListCell::Params& p)
+:	LLScrollListCell(p),
+	mIcon(LLUI::getUIImage(p.value().asString())),
+	mColor(p.color),
+	mAlignment(p.font_halign)
+{}
+
+LLScrollListIcon::~LLScrollListIcon()
+{
+}
+
+/*virtual*/
+S32		LLScrollListIcon::getHeight() const
+{ return mIcon ? mIcon->getHeight() : 0; }
+
+/*virtual*/
+const LLSD		LLScrollListIcon::getValue() const
+{ return mIcon.isNull() ? LLStringUtil::null : mIcon->getName(); }
+
+void LLScrollListIcon::setValue(const LLSD& value)
+{
+	if (value.isUUID())
+	{
+		// don't use default image specified by LLUUID::null, use no image in that case
+		LLUUID image_id = value.asUUID();
+		mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL);
+	}
+	else
+	{
+		std::string value_string = value.asString();
+		if (LLUUID::validate(value_string))
+		{
+			setValue(LLUUID(value_string));
+		}
+		else if (!value_string.empty())
+		{
+			mIcon = LLUI::getUIImage(value.asString());
+		}
+		else
+		{
+			mIcon = NULL;
+		}
+	}
+}
+
+
+void LLScrollListIcon::setColor(const LLColor4& color)
+{
+	mColor = color;
+}
+
+S32	LLScrollListIcon::getWidth() const 
+{
+	// if no specified fix width, use width of icon
+	if (LLScrollListCell::getWidth() == 0 && mIcon.notNull())
+	{
+		return mIcon->getWidth();
+	}
+	return LLScrollListCell::getWidth();
+}
+
+
+void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color)	 const
+{
+	if (mIcon)
+	{
+		switch(mAlignment)
+		{
+		case LLFontGL::LEFT:
+			mIcon->draw(0, 0, mColor);
+			break;
+		case LLFontGL::RIGHT:
+			mIcon->draw(getWidth() - mIcon->getWidth(), 0, mColor);
+			break;
+		case LLFontGL::HCENTER:
+			mIcon->draw((getWidth() - mIcon->getWidth()) / 2, 0, mColor);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+//
+// LLScrollListText
+//
+U32 LLScrollListText::sCount = 0;
+
+LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p)
+:	LLScrollListCell(p),
+	mText(p.value().asString()),
+	mFont(p.font),
+	mColor(p.color),
+	mUseColor(p.color.isProvided()),
+	mFontStyle(LLFontGL::NORMAL),
+	mFontAlignment(p.font_halign),
+	mVisible(p.visible),
+	mHighlightCount( 0 ),
+	mHighlightOffset( 0 )
+{
+	sCount++;
+
+	// initialize rounded rect image
+	if (!mRoundedRectImage)
+	{
+		mRoundedRectImage = LLUI::getUIImage("rounded_square.tga");
+	}
+}
+
+//virtual 
+void LLScrollListText::highlightText(S32 offset, S32 num_chars)
+{
+	mHighlightOffset = offset;
+	mHighlightCount = num_chars;
+}
+
+//virtual 
+BOOL LLScrollListText::isText() const
+{
+	return TRUE;
+}
+
+//virtual 
+BOOL LLScrollListText::getVisible() const
+{
+	return mVisible;
+}
+
+//virtual 
+S32 LLScrollListText::getHeight() const
+{
+	return llround(mFont->getLineHeight());
+}
+
+
+LLScrollListText::~LLScrollListText()
+{
+	sCount--;
+}
+
+S32	LLScrollListText::getContentWidth() const
+{
+	return mFont->getWidth(mText.getString());
+}
+
+
+void LLScrollListText::setColor(const LLColor4& color)
+{
+	mColor = color;
+	mUseColor = TRUE;
+}
+
+void LLScrollListText::setText(const LLStringExplicit& text)
+{
+	mText = text;
+}
+
+//virtual
+void LLScrollListText::setValue(const LLSD& text)
+{
+	setText(text.asString());
+}
+
+//virtual 
+const LLSD LLScrollListText::getValue() const		
+{ 
+	return LLSD(mText.getString()); 
+}
+
+
+void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) const
+{
+	LLColor4 display_color;
+	if (mUseColor)
+	{
+		display_color = mColor;
+	}
+	else
+	{
+		display_color = color;
+	}
+
+	if (mHighlightCount > 0)
+	{
+		S32 left = 0;
+		switch(mFontAlignment)
+		{
+		case LLFontGL::LEFT:
+			left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
+			break;
+		case LLFontGL::RIGHT:
+			left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
+			break;
+		case LLFontGL::HCENTER:
+			left = (getWidth() - mFont->getWidth(mText.getString())) / 2;
+			break;
+		}
+		LLRect highlight_rect(left - 2, 
+				llround(mFont->getLineHeight()) + 1, 
+				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, 
+				1);
+		mRoundedRectImage->draw(highlight_rect, highlight_color);
+	}
+
+	// Try to draw the entire string
+	F32 right_x;
+	U32 string_chars = mText.length();
+	F32 start_x = 0.f;
+	switch(mFontAlignment)
+	{
+	case LLFontGL::LEFT:
+		start_x = 0.f;
+		break;
+	case LLFontGL::RIGHT:
+		start_x = (F32)getWidth();
+		break;
+	case LLFontGL::HCENTER:
+		start_x = (F32)getWidth() * 0.5f;
+		break;
+	}
+	mFont->render(mText.getWString(), 0, 
+						start_x, 2.f,
+						display_color,
+						mFontAlignment,
+						LLFontGL::BOTTOM, 
+						mFontStyle,
+						LLFontGL::NO_SHADOW,
+						string_chars, 
+						getWidth(),
+						&right_x, 
+						FALSE, 
+						TRUE);
+}
+
+//
+// LLScrollListCheck
+//
+LLScrollListCheck::LLScrollListCheck(const LLScrollListCell::Params& p)
+:	LLScrollListCell(p)
+{
+	LLCheckBoxCtrl::Params checkbox_p;
+	checkbox_p.name("checkbox");
+	checkbox_p.rect.left(0).bottom(0).width(p.width).height(p.width);
+	checkbox_p.enabled(p.enabled);
+	checkbox_p.initial_value(p.value());
+
+	mCheckBox = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
+	 
+	LLRect rect(mCheckBox->getRect());
+	if (p.width)
+	{
+		rect.mRight = rect.mLeft + p.width;
+		mCheckBox->setRect(rect);
+		setWidth(p.width);
+	}
+	else
+	{
+		setWidth(rect.getWidth()); //check_box->getWidth();
+	}
+
+	mCheckBox->setColor(p.color);
+}
+
+
+LLScrollListCheck::~LLScrollListCheck()
+{
+	delete mCheckBox;
+	mCheckBox = NULL;
+}
+
+void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) const
+{
+	mCheckBox->draw();
+}
+
+BOOL LLScrollListCheck::handleClick()
+{ 
+	if (mCheckBox->getEnabled())
+	{
+		mCheckBox->toggle();
+	}
+	// don't change selection when clicking on embedded checkbox
+	return TRUE; 
+}
+
+/*virtual*/
+const LLSD LLScrollListCheck::getValue() const
+{
+	return mCheckBox->getValue();
+}
+
+/*virtual*/
+void LLScrollListCheck::setValue(const LLSD& value)
+{
+	mCheckBox->setValue(value);
+}
+
+/*virtual*/
+void LLScrollListCheck::onCommit()
+{
+	mCheckBox->onCommit();
+}
+
+/*virtual*/
+void LLScrollListCheck::setEnabled(BOOL enable)
+{
+	mCheckBox->setEnabled(enable);
+}
+
+//
+// LLScrollListDate
+//
+
+LLScrollListDate::LLScrollListDate( const LLScrollListCell::Params& p)
+:	LLScrollListText(p),
+	mDate(p.value().asDate())
+{}
+
+void LLScrollListDate::setValue(const LLSD& value)
+{
+	mDate = value.asDate();
+	LLScrollListText::setValue(mDate.asRFC1123());
+}
+
+const LLSD LLScrollListDate::getValue() const
+{
+	return mDate;
+}
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
new file mode 100644
index 0000000000..2ab13f7618
--- /dev/null
+++ b/indra/llui/llscrolllistcell.h
@@ -0,0 +1,223 @@
+/** 
+ * @file llscrolllistcell.h
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSCROLLLISTCELL_H
+#define LLSCROLLLISTCELL_H
+
+#include "llfontgl.h"		// HAlign
+#include "llpointer.h"		// LLPointer<>
+#include "lluistring.h"
+#include "v4color.h"
+#include "llui.h"
+
+class LLCheckBoxCtrl;
+class LLSD;
+class LLUIImage;
+
+/*
+ * Represents a cell in a scrollable table.
+ *
+ * Sub-classes must return height and other properties 
+ * though width accessors are implemented by the base class.
+ * It is therefore important for sub-class constructors to call
+ * setWidth() with realistic values.
+ */
+class LLScrollListCell
+{
+public:
+	struct Params : public LLInitParam::Block<Params>
+	{
+		Optional<std::string>		type,
+									column;
+
+		Optional<S32>				width;
+		Optional<bool>				enabled,
+									visible;
+
+		Optional<void*>				userdata;
+		Optional<LLSD>				value;
+
+		Optional<const LLFontGL*>	font;
+		Optional<LLColor4>			font_color;
+		Optional<LLFontGL::HAlign>	font_halign;
+
+		Optional<LLColor4>			color;
+
+		Params()
+		:	type("type", "text"),
+			column("column"),
+			width("width"),
+			enabled("enabled", true),
+			visible("visible", true),
+			value("value"),
+			font("font", LLFontGL::getFontSansSerifSmall()),
+			font_color("font_color", LLColor4::black),
+			color("color", LLColor4::white),
+			font_halign("halign", LLFontGL::LEFT)
+		{
+			addSynonym(column, "name");
+			addSynonym(font_color, "font-color");
+		}
+	};
+
+	static LLScrollListCell* create(const Params&);
+
+	LLScrollListCell(const LLScrollListCell::Params&);
+	virtual ~LLScrollListCell() {};
+	virtual void			draw(const LLColor4& color, const LLColor4& highlight_color) const = 0;		// truncate to given width, if possible
+	virtual S32				getWidth() const {return mWidth;}
+	virtual S32				getContentWidth() const { return 0; }
+	virtual S32				getHeight() const = 0;
+	virtual const LLSD		getValue() const;
+	virtual void			setValue(const LLSD& value) { }
+	virtual BOOL			getVisible() const { return TRUE; }
+	virtual void			setWidth(S32 width) { mWidth = width; }
+	virtual void			highlightText(S32 offset, S32 num_chars) {}
+	virtual BOOL			isText() const = 0;
+	virtual void			setColor(const LLColor4&) {}
+	virtual void			onCommit() {};
+
+	virtual BOOL			handleClick() { return FALSE; }
+	virtual	void			setEnabled(BOOL enable) { }
+
+private:
+	S32 mWidth;
+};
+
+class LLScrollListSpacer : public LLScrollListCell
+{
+public:
+	LLScrollListSpacer(const LLScrollListCell::Params& p) : LLScrollListCell(p) {}
+	/*virtual*/ ~LLScrollListSpacer() {};
+	/*virtual*/ void			draw(const LLColor4& color, const LLColor4& highlight_color) const {}
+	/*virtual*/ S32				getHeight() const { return 0; }
+	/*virtual*/ BOOL			isText() const { return FALSE; }
+};
+
+/*
+ * Cell displaying a text label.
+ */
+class LLScrollListText : public LLScrollListCell
+{
+public:
+	LLScrollListText(const LLScrollListCell::Params&);
+	/*virtual*/ ~LLScrollListText();
+
+	/*virtual*/ void    draw(const LLColor4& color, const LLColor4& highlight_color) const;
+	/*virtual*/ S32		getContentWidth() const;
+	/*virtual*/ S32		getHeight() const;
+	/*virtual*/ void	setValue(const LLSD& value);
+	/*virtual*/ const LLSD getValue() const;
+	/*virtual*/ BOOL	getVisible() const;
+	/*virtual*/ void	highlightText(S32 offset, S32 num_chars);
+
+	/*virtual*/ void	setColor(const LLColor4&);
+	/*virtual*/ BOOL	isText() const;
+
+	void			setText(const LLStringExplicit& text);
+	void			setFontStyle(const U8 font_style) { mFontStyle = font_style; }
+
+private:
+	LLUIString		mText;
+	const LLFontGL*	mFont;
+	LLColor4		mColor;
+	U8				mUseColor;
+	U8				mFontStyle;
+	LLFontGL::HAlign mFontAlignment;
+	BOOL			mVisible;
+	S32				mHighlightCount;
+	S32				mHighlightOffset;
+
+	LLPointer<LLUIImage> mRoundedRectImage;
+
+	static U32 sCount;
+};
+
+/*
+ * Cell displaying an image.
+ */
+class LLScrollListIcon : public LLScrollListCell
+{
+public:
+	LLScrollListIcon(const LLScrollListCell::Params& p);
+	/*virtual*/ ~LLScrollListIcon();
+	/*virtual*/ void	draw(const LLColor4& color, const LLColor4& highlight_color) const;
+	/*virtual*/ S32		getWidth() const;
+	/*virtual*/ S32		getHeight() const;
+	/*virtual*/ const LLSD		getValue() const;
+	/*virtual*/ void	setColor(const LLColor4&);
+	/*virtual*/ BOOL	isText()const { return FALSE; }
+	/*virtual*/ void	setValue(const LLSD& value);
+
+private:
+	LLPointer<LLUIImage>	mIcon;
+	LLColor4				mColor;
+	LLFontGL::HAlign		mAlignment;
+};
+
+/*
+ * An interactive cell containing a check box.
+ */
+class LLScrollListCheck : public LLScrollListCell
+{
+public:
+	LLScrollListCheck( const LLScrollListCell::Params&);
+	/*virtual*/ ~LLScrollListCheck();
+	/*virtual*/ void	draw(const LLColor4& color, const LLColor4& highlight_color) const;
+	/*virtual*/ S32		getHeight() const			{ return 0; } 
+	/*virtual*/ const LLSD	getValue() const;
+	/*virtual*/ void	setValue(const LLSD& value);
+	/*virtual*/ void	onCommit();
+
+	/*virtual*/ BOOL	handleClick();
+	/*virtual*/ void	setEnabled(BOOL enable);
+
+	LLCheckBoxCtrl*	getCheckBox()				{ return mCheckBox; }
+	/*virtual*/ BOOL	isText() const				{ return FALSE; }
+
+private:
+	LLCheckBoxCtrl* mCheckBox;
+};
+
+class LLScrollListDate : public LLScrollListText
+{
+public:
+	LLScrollListDate( const LLScrollListCell::Params& p );
+	virtual void	setValue(const LLSD& value);
+	virtual const LLSD getValue() const;
+
+private:
+	LLDate		mDate;
+};
+
+#endif
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
new file mode 100644
index 0000000000..48fddbfb71
--- /dev/null
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -0,0 +1,320 @@
+/** 
+ * @file llscrollcolumnheader.cpp
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llscrolllistcolumn.h"
+
+#include "llbutton.h"
+#include "llresizebar.h"
+#include "llscrolllistcell.h"
+#include "llscrolllistctrl.h"
+#include "llscrolllistitem.h"
+#include "lluictrlfactory.h"
+
+const S32 MIN_COLUMN_WIDTH = 20;
+
+//---------------------------------------------------------------------------
+// LLScrollColumnHeader
+//---------------------------------------------------------------------------
+
+LLScrollColumnHeader::LLScrollColumnHeader(const LLScrollColumnHeader::Params& p) 
+:	LLButton(p), // use combobox params to steal images
+	mColumn(p.column),
+	mHasResizableElement(FALSE)
+{
+	setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2));
+	
+	// resize handles on left and right
+	const S32 RESIZE_BAR_THICKNESS = 3;
+	LLResizeBar::Params resize_bar_p;
+	resize_bar_p.resizing_view(this);
+	resize_bar_p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0));
+	resize_bar_p.min_size(MIN_COLUMN_WIDTH);
+	resize_bar_p.side(LLResizeBar::RIGHT);
+	resize_bar_p.enabled(false);
+	mResizeBar = LLUICtrlFactory::create<LLResizeBar>(resize_bar_p);
+	addChild(mResizeBar);
+
+	setToolTip(p.label());
+}
+
+LLScrollColumnHeader::~LLScrollColumnHeader()
+{}
+
+void LLScrollColumnHeader::draw()
+{
+	std::string sort_column = mColumn->mParentCtrl->getSortColumnName();
+	BOOL draw_arrow = !mColumn->mLabel.empty() 
+			&& mColumn->mParentCtrl->isSorted()
+			// check for indirect sorting column as well as column's sorting name
+			&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
+
+	BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
+	setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
+
+	// Draw children
+	LLButton::draw();
+}
+
+BOOL LLScrollColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+	if (canResize() && mResizeBar->getRect().pointInRect(x, y))
+	{
+		// reshape column to max content width
+		LLRect column_rect = getRect();
+		column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
+		setShape(column_rect, true);
+	}
+	else
+	{
+		onClick(LLSD());
+	}
+	return TRUE;
+}
+
+void LLScrollColumnHeader::onClick(const LLSD& data)
+{
+	if (mColumn)
+	{
+		LLScrollListCtrl::onClickColumn(mColumn);
+	}
+}
+
+LLView*	LLScrollColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
+{
+	// this logic assumes dragging on right
+	llassert(snap_edge == SNAP_RIGHT);
+
+	// use higher snap threshold for column headers
+	threshold = llmin(threshold, 10);
+
+	LLRect snap_rect = getSnapRect();
+
+	S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth();
+
+	// x coord growing means column growing, so same signs mean we're going in right direction
+	if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) 
+	{
+		new_edge_val = snap_rect.mRight + snap_delta;
+	}
+	else 
+	{
+		LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1);
+		while (next_column)
+		{
+			if (next_column->mHeader)
+			{
+				snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight;
+				if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) 
+				{
+					new_edge_val = snap_rect.mRight + snap_delta;
+				}
+				break;
+			}
+			next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1);
+		}
+	}
+
+	return this;
+}
+
+void LLScrollColumnHeader::handleReshape(const LLRect& new_rect, bool by_user)
+{
+	S32 new_width = new_rect.getWidth();
+	S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/);
+
+	if (delta_width != 0)
+	{
+		S32 remaining_width = -delta_width;
+		S32 col;
+		for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
+		{
+			LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
+			if (!columnp) continue;
+
+			if (columnp->mHeader && columnp->mHeader->canResize())
+			{
+				// how many pixels in width can this column afford to give up?
+				S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH);
+				
+				// user shrinking column, need to add width to other columns
+				if (delta_width < 0)
+				{
+					if (columnp->getWidth() > 0)
+					{
+						// statically sized column, give all remaining width to this column
+						columnp->setWidth(columnp->getWidth() + remaining_width);
+						if (columnp->mRelWidth > 0.f)
+						{
+							columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
+						}
+						// all padding went to this widget, we're done
+						break;
+					}
+				}
+				else
+				{
+					// user growing column, need to take width from other columns
+					remaining_width += resize_buffer_amt;
+
+					if (columnp->getWidth() > 0)
+					{
+						columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width));
+						if (columnp->mRelWidth > 0.f)
+						{
+							columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
+						}
+					}
+
+					if (remaining_width >= 0)
+					{
+						// width sucked up from neighboring columns, done
+						break;
+					}
+				}
+			}
+		}
+
+		// clamp resize amount to maximum that can be absorbed by other columns
+		if (delta_width > 0)
+		{
+			delta_width += llmin(remaining_width, 0);
+		}
+
+		// propagate constrained delta_width to new width for this column
+		new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
+
+		// use requested width
+		mColumn->setWidth(new_width);
+
+		// update proportional spacing
+		if (mColumn->mRelWidth > 0.f)
+		{
+			mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
+		}
+
+		// tell scroll list to layout columns again
+		// do immediate update to get proper feedback to resize handle
+		// which needs to know how far the resize actually went
+		mColumn->mParentCtrl->updateColumns();
+	}
+}
+
+void LLScrollColumnHeader::setHasResizableElement(BOOL resizable)
+{
+	if (mHasResizableElement != resizable)
+	{
+		mColumn->mParentCtrl->dirtyColumns();
+		mHasResizableElement = resizable;
+	}
+}
+
+void LLScrollColumnHeader::updateResizeBars()
+{
+	S32 num_resizable_columns = 0;
+	S32 col;
+	for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
+	{
+		LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
+		if (columnp->mHeader && columnp->mHeader->canResize())
+		{
+			num_resizable_columns++;
+		}
+	}
+
+	S32 num_resizers_enabled = 0;
+
+	// now enable/disable resize handles on resizable columns if we have at least two
+	for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
+	{
+		LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
+		if (!columnp->mHeader) continue;
+		BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
+		columnp->mHeader->enableResizeBar(enable);
+		if (enable)
+		{
+			num_resizers_enabled++;
+		}
+	}
+}
+
+void LLScrollColumnHeader::enableResizeBar(BOOL enable)
+{
+	mResizeBar->setEnabled(enable);
+}
+
+BOOL LLScrollColumnHeader::canResize()
+{
+	return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
+}
+
+void LLScrollListColumn::SortNames::declareValues()
+{
+	declare("ascending", LLScrollListColumn::ASCENDING);
+	declare("descending", LLScrollListColumn::DESCENDING);
+}
+
+LLScrollListColumn::LLScrollListColumn(const Params& p, LLScrollListCtrl* parent)
+:	mWidth(0),
+	mIndex (-1),
+	mParentCtrl(parent),
+	mName(p.name),
+	mLabel(p.header.label),
+	mHeader(NULL),
+	mMaxContentWidth(0),
+	mDynamicWidth(p.width.dynamic_width),
+	mRelWidth(p.width.relative_width),
+	mFontAlignment(p.halign),
+	mSortingColumn(p.sort_column)
+{
+	if (p.sort_ascending.isProvided())
+	{
+		mSortDirection = p.sort_ascending() ? ASCENDING : DESCENDING;
+	}
+	else
+	{
+		mSortDirection = p.sort_direction;
+	}
+
+	setWidth(p.width.pixel_width);
+}
+
+void LLScrollListColumn::setWidth(S32 width) 
+{ 
+	if (!mDynamicWidth && mRelWidth <= 0.f) 
+	{
+		mParentCtrl->updateStaticColumnWidth(this, width);
+	}
+	mWidth = width;
+}
diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h
new file mode 100644
index 0000000000..c1bb86577f
--- /dev/null
+++ b/indra/llui/llscrolllistcolumn.h
@@ -0,0 +1,189 @@
+/** 
+ * @file llscrollcolumnheader.h
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSCROLLLISTCOLUMN_H
+#define LLSCROLLLISTCOLUMN_H
+
+#include "llrect.h"
+#include "lluistring.h"
+#include "llbutton.h"
+#include "llinitparam.h"
+
+class LLScrollListColumn;
+class LLResizeBar;
+class LLScrollListCtrl;
+
+class LLScrollColumnHeader : public LLButton
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLButton::Params>
+	{
+		Mandatory<LLScrollListColumn*> column;
+
+		Params()
+		:	column("column")
+		{
+			name  = "column_header";
+			image_unselected.name("square_btn_32x128.tga");
+			image_selected.name("square_btn_selected_32x128.tga");
+			image_disabled.name("square_btn_32x128.tga");
+			image_disabled_selected.name("square_btn_selected_32x128.tga");
+			image_overlay.name("combobox_arrow.tga");
+			image_overlay_alignment("right");
+			font_halign = LLFontGL::LEFT;
+			tab_stop(false);
+			scale_image(true);
+		}
+	};
+	LLScrollColumnHeader(const Params&);
+	~LLScrollColumnHeader();
+
+	/*virtual*/ void draw();
+	/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
+
+	/*virtual*/ LLView*	findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding);
+	/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
+	
+	LLScrollListColumn* getColumn() { return mColumn; }
+	void setHasResizableElement(BOOL resizable);
+	void updateResizeBars();
+	BOOL canResize();
+	void enableResizeBar(BOOL enable);
+
+	void onClick(const LLSD& data);
+
+private:
+	LLScrollListColumn* mColumn;
+	LLResizeBar*		mResizeBar;
+	BOOL				mHasResizableElement;
+};
+
+/*
+ * A simple data class describing a column within a scroll list.
+ */
+class LLScrollListColumn
+{
+public:
+	typedef enum e_sort_direction
+	{
+		DESCENDING,
+		ASCENDING
+	} ESortDirection;
+
+	struct SortNames
+	:	public LLInitParam::TypeValuesHelper<LLScrollListColumn::ESortDirection, SortNames>
+	{
+		static void declareValues();
+	};
+
+	struct Params : public LLInitParam::Block<Params>
+	{
+		Optional<std::string>				name,
+											tool_tip;
+		Optional<std::string>				sort_column;
+		Optional<ESortDirection, SortNames>	sort_direction;
+		Optional<bool>						sort_ascending;
+
+		struct Width : public LLInitParam::Choice<Width>
+		{
+			Option<bool>	dynamic_width;
+			Option<S32>		pixel_width;
+			Option<F32>		relative_width;
+
+			Width()
+			:	dynamic_width("dynamicwidth", false),
+				pixel_width("width"),
+				relative_width("relative_width", -1.f)
+			{
+				addSynonym(relative_width, "relwidth");
+			}
+		};
+		Optional<Width>						width;
+
+		// either an image or label is used in column header
+		struct Header : public LLInitParam::Choice<Header>
+		{
+			Option<std::string>			label;
+			Option<LLUIImage*>			image;
+
+			Header()
+			:	label("label"),
+				image("image")
+			{}
+		};
+		Optional<Header>					header;
+
+		Optional<LLFontGL::HAlign>			halign;
+
+		Params()
+		:	name("name"),
+			tool_tip("tool_tip"),
+			sort_column("sort_column"),
+			sort_direction("sort_direction"),
+			sort_ascending("sort_ascending", true),
+			halign("halign", LLFontGL::LEFT)
+		{
+			// default choice to "dynamic_width"
+			width.dynamic_width = true;
+
+			addSynonym(sort_column, "sort");
+		}
+	};
+
+	//NOTE: this is default constructible so we can store it in a map.
+	LLScrollListColumn(const Params& p = Params(), LLScrollListCtrl* = NULL);
+
+	void setWidth(S32 width);
+	S32 getWidth() const { return mWidth; }
+
+public:
+	// Public data is fine so long as this remains a simple struct-like data class.
+	// If it ever gets any smarter than that, these should all become private
+	// with protected or public accessor methods added as needed. -MG
+	std::string				mName;
+	std::string				mSortingColumn;
+	ESortDirection			mSortDirection;
+	LLUIString				mLabel;
+	F32						mRelWidth;
+	BOOL					mDynamicWidth;
+	S32						mMaxContentWidth;
+	S32						mIndex;
+	LLScrollListCtrl*		mParentCtrl;
+	LLScrollColumnHeader*	mHeader;
+	LLFontGL::HAlign		mFontAlignment;
+
+private:
+	S32						mWidth;
+};
+
+#endif
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 5dd4e2d0ee..6f484b1875 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1,6 +1,7 @@
  /** 
  * @file llscrolllistctrl.cpp
- * @brief LLScrollListCtrl base class
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
  *
  * $LicenseInfo:firstyear=2001&license=viewergpl$
  * 
@@ -30,32 +31,36 @@
  * $/LicenseInfo$
  */
 
-#include <algorithm>
+#define INSTANTIATE_GETCHILD_SCROLLLIST
 
 #include "linden_common.h"
-#include "llstl.h"
-#include "llboost.h"
 
 #include "llscrolllistctrl.h"
 
-#include "indra_constants.h"
+#include <algorithm>
+
+#include "llstl.h"
+#include "llboost.h"
+//#include "indra_constants.h"
 
 #include "llcheckboxctrl.h"
 #include "llclipboard.h"
 #include "llfocusmgr.h"
-#include "llrender.h"
+//#include "llrender.h"
 #include "llresmgr.h"
 #include "llscrollbar.h"
+#include "llscrolllistcell.h"
 #include "llstring.h"
 #include "llui.h"
 #include "lluictrlfactory.h"
 #include "llwindow.h"
 #include "llcontrol.h"
 #include "llkeyboard.h"
-#include "llresizebar.h"
+#include "llviewborder.h"
+#include "lltextbox.h"
+#include "llsdparam.h"
 
-const S32 MIN_COLUMN_WIDTH = 20;
-const S32 LIST_SNAP_PADDING = 5;
+template LLScrollListCtrl* LLView::getChild<LLScrollListCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
 
 static LLRegisterWidget<LLScrollListCtrl> r("scroll_list");
 
@@ -96,510 +101,89 @@ struct SortScrollListItem
 	const sort_order_t& mSortOrders;
 };
 
-
-//
-// LLScrollListIcon
-//
-LLScrollListIcon::LLScrollListIcon(LLUIImagePtr icon, S32 width)
-	: LLScrollListCell(width),
-	  mIcon(icon),
-	  mColor(LLColor4::white)
-{
-}
-
-LLScrollListIcon::LLScrollListIcon(const LLSD& value, S32 width)
-	: LLScrollListCell(width),
-	mColor(LLColor4::white)
-{
-	setValue(value);
-}
-
-
-LLScrollListIcon::~LLScrollListIcon()
-{
-}
-
-void LLScrollListIcon::setValue(const LLSD& value)
-{
-	if (value.isUUID())
-	{
-		// don't use default image specified by LLUUID::null, use no image in that case
-		LLUUID image_id = value.asUUID();
-		mIcon = image_id.notNull() ? LLUI::sImageProvider->getUIImageByID(image_id) : LLUIImagePtr(NULL);
-	}
-	else
-	{
-		std::string value_string = value.asString();
-		if (LLUUID::validate(value_string))
-		{
-			setValue(LLUUID(value_string));
-		}
-		else if (!value_string.empty())
-		{
-			mIcon = LLUI::getUIImage(value.asString());
-		}
-		else
-		{
-			mIcon = NULL;
-		}
-	}
-}
-
-
-void LLScrollListIcon::setColor(const LLColor4& color)
-{
-	mColor = color;
-}
-
-S32	LLScrollListIcon::getWidth() const 
-{
-	// if no specified fix width, use width of icon
-	if (LLScrollListCell::getWidth() == 0 && mIcon.notNull())
-	{
-		return mIcon->getWidth();
-	}
-	return LLScrollListCell::getWidth();
-}
-
-
-void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color)	 const
-{
-	if (mIcon)
-	{
-		mIcon->draw(0, 0, mColor);
-	}
-}
-
-//
-// LLScrollListCheck
-//
-LLScrollListCheck::LLScrollListCheck(LLCheckBoxCtrl* check_box, S32 width)
-{
-	mCheckBox = check_box;
-	LLRect rect(mCheckBox->getRect());
-	if (width)
-	{
-		
-		rect.mRight = rect.mLeft + width;
-		mCheckBox->setRect(rect);
-		setWidth(width);
-	}
-	else
-	{
-		setWidth(rect.getWidth()); //check_box->getWidth();
-	}
-}
-
-LLScrollListCheck::~LLScrollListCheck()
-{
-	delete mCheckBox;
-}
-
-void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
-	mCheckBox->draw();
-}
-
-BOOL LLScrollListCheck::handleClick()
-{ 
-	if (mCheckBox->getEnabled())
-	{
-		mCheckBox->toggle();
-	}
-	// don't change selection when clicking on embedded checkbox
-	return TRUE; 
-}
-
-//
-// LLScrollListSeparator
-//
-LLScrollListSeparator::LLScrollListSeparator(S32 width) : LLScrollListCell(width)
-{
-}
-
-//virtual 
-S32 LLScrollListSeparator::getHeight() const
-{
-	return 5;
-}
-
-
-void LLScrollListSeparator::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
-	//*FIXME: use dynamic item heights and make separators narrow, and inactive
-	gl_line_2d(5, 8, llmax(5, getWidth() - 5), 8, color);
-}
-
-//
-// LLScrollListText
-//
-U32 LLScrollListText::sCount = 0;
-
-LLScrollListText::LLScrollListText( const std::string& text, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible)
-:	LLScrollListCell(width),
-	mText( text ),
-	mFont( font ),
-	mColor(color),
-	mUseColor(use_color),
-	mFontStyle( font_style ),
-	mFontAlignment( font_alignment ),
-	mVisible( visible ),
-	mHighlightCount( 0 ),
-	mHighlightOffset( 0 )
-{
-	sCount++;
-
-	// initialize rounded rect image
-	if (!mRoundedRectImage)
-	{
-		mRoundedRectImage = LLUI::sImageProvider->getUIImage("rounded_square.tga");
-	}
-}
-//virtual 
-void LLScrollListText::highlightText(S32 offset, S32 num_chars)
-{
-	mHighlightOffset = offset;
-	mHighlightCount = num_chars;
-}
-
-//virtual 
-BOOL LLScrollListText::isText() const
-{
-	return TRUE;
-}
-
-//virtual 
-BOOL LLScrollListText::getVisible() const
-{
-	return mVisible;
-}
-
-//virtual 
-S32 LLScrollListText::getHeight() const
-{
-	return llround(mFont->getLineHeight());
-}
-
-
-LLScrollListText::~LLScrollListText()
-{
-	sCount--;
-}
-
-S32	LLScrollListText::getContentWidth() const
-{
-	return mFont->getWidth(mText.getString());
-}
-
-
-void LLScrollListText::setColor(const LLColor4& color)
-{
-	mColor = color;
-	mUseColor = TRUE;
-}
-
-void LLScrollListText::setText(const LLStringExplicit& text)
-{
-	mText = text;
-}
-
-//virtual
-void LLScrollListText::setValue(const LLSD& text)
-{
-	setText(text.asString());
-}
-
-//virtual 
-const LLSD LLScrollListText::getValue() const		
-{ 
-	return LLSD(mText.getString()); 
-}
-
-
-void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) const
-{
-	LLColor4 display_color;
-	if (mUseColor)
-	{
-		display_color = mColor;
-	}
-	else
-	{
-		display_color = color;
-	}
-
-	if (mHighlightCount > 0)
-	{
-		S32 left = 0;
-		switch(mFontAlignment)
-		{
-		case LLFontGL::LEFT:
-			left = mFont->getWidth(mText.getString(), 0, mHighlightOffset);
-			break;
-		case LLFontGL::RIGHT:
-			left = getWidth() - mFont->getWidth(mText.getString(), mHighlightOffset, S32_MAX);
-			break;
-		case LLFontGL::HCENTER:
-			left = (getWidth() - mFont->getWidth(mText.getString())) / 2;
-			break;
-		}
-		LLRect highlight_rect(left - 2, 
-				llround(mFont->getLineHeight()) + 1, 
-				left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, 
-				1);
-		mRoundedRectImage->draw(highlight_rect, highlight_color);
-	}
-
-	// Try to draw the entire string
-	F32 right_x;
-	U32 string_chars = mText.length();
-	F32 start_x = 0.f;
-	switch(mFontAlignment)
-	{
-	case LLFontGL::LEFT:
-		start_x = 0.f;
-		break;
-	case LLFontGL::RIGHT:
-		start_x = (F32)getWidth();
-		break;
-	case LLFontGL::HCENTER:
-		start_x = (F32)getWidth() * 0.5f;
-		break;
-	}
-	mFont->render(mText.getWString(), 0, 
-						start_x, 2.f,
-						display_color,
-						mFontAlignment,
-						LLFontGL::BOTTOM, 
-						mFontStyle,
-						string_chars, 
-						getWidth(),
-						&right_x, 
-						FALSE, 
-						TRUE);
-}
-
-LLScrollListDate::LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width, U8 font_style, LLFontGL::HAlign font_alignment, LLColor4& color, BOOL use_color, BOOL visible)
-:	LLScrollListText(date.asRFC1123(), font, width, font_style, font_alignment, color, use_color, visible),
-	mDate(date)
-{
-}
-
-void LLScrollListDate::setValue(const LLSD& value)
-{
-	mDate = value.asDate();
-	LLScrollListText::setValue(mDate.asRFC1123());
-}
-
-const LLSD LLScrollListDate::getValue() const
-{
-	return mDate;
-}
-
-LLScrollListItem::~LLScrollListItem()
-{
-	std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
-}
-
-void LLScrollListItem::setNumColumns(S32 columns)
-{
-	S32 prev_columns = mColumns.size();
-	if (columns < prev_columns)
-	{
-		std::for_each(mColumns.begin()+columns, mColumns.end(), DeletePointer());
-	}
-	
-	mColumns.resize(columns);
-
-	for (S32 col = prev_columns; col < columns; ++col)
-	{
-		mColumns[col] = NULL;
-	}
-}
-
-void LLScrollListItem::setColumn( S32 column, LLScrollListCell *cell )
-{
-	if (column < (S32)mColumns.size())
-	{
-		delete mColumns[column];
-		mColumns[column] = cell;
-	}
-	else
-	{
-		llerrs << "LLScrollListItem::setColumn: bad column: " << column << llendl;
-	}
-}
-
-std::string LLScrollListItem::getContentsCSV() const
-{
-	std::string ret;
-
-	S32 count = getNumColumns();
-	for (S32 i=0; i<count; ++i)
-	{
-		ret += getColumn(i)->getValue().asString();
-		if (i < count-1)
-		{
-			ret += ", ";
-		}
-	}
-
-	return ret;
-}
-
-void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
-{
-	// draw background rect
-	LLRect bg_rect = rect;
-	{
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.color4fv(bg_color.mV);
-		gl_rect_2d( bg_rect );
-	}
-
-	S32 cur_x = rect.mLeft;
-	S32 num_cols = getNumColumns();
-	S32 cur_col = 0;
-
-	for (LLScrollListCell* cell = getColumn(0); cur_col < num_cols; cell = getColumn(++cur_col))
-	{
-		// Two ways a cell could be hidden
-		if (cell->getWidth() < 0
-			|| !cell->getVisible()) continue;
-
-		LLUI::pushMatrix();
-		{
-			LLUI::translate((F32) cur_x, (F32) rect.mBottom, 0.0f);
-
-			cell->draw( fg_color, highlight_color );
-		}
-		LLUI::popMatrix();
-		
-		cur_x += cell->getWidth() + column_padding;
-	}
-}
-
-
-void LLScrollListItem::setEnabled(BOOL b)
-{
-	mEnabled = b;
-}
-
-//---------------------------------------------------------------------------
-// LLScrollListItemComment
-//---------------------------------------------------------------------------
-LLScrollListItemComment::LLScrollListItemComment(const std::string& comment_string, const LLColor4& color)
-: LLScrollListItem(FALSE),
-	mColor(color)
-{
-	addColumn( comment_string, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ) );
-}
-
-void LLScrollListItemComment::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
-{
-	LLScrollListCell* cell = getColumn(0);
-	if (cell)
-	{
-		// Two ways a cell could be hidden
-		if (cell->getWidth() < 0
-			|| !cell->getVisible()) return;
-
-		LLUI::pushMatrix();
-		{
-			LLUI::translate((F32)rect.mLeft, (F32)rect.mBottom, 0.0f);
-
-			// force first cell to be width of entire item
-			cell->setWidth(rect.getWidth());
-			cell->draw( mColor, highlight_color );
-		}
-		LLUI::popMatrix();
-	}
-}
-
-//---------------------------------------------------------------------------
-// LLScrollListItemSeparator
-//---------------------------------------------------------------------------
-LLScrollListItemSeparator::LLScrollListItemSeparator()
-: LLScrollListItem(FALSE)
-{
-	LLScrollListSeparator* cell = new LLScrollListSeparator(0);
-	setNumColumns(1);
-	setColumn(0, cell);
-}
-
-void LLScrollListItemSeparator::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
-{
-	//TODO* move LLScrollListSeparator::draw into here and get rid of it
-	LLScrollListCell* cell = getColumn(0);
-	if (cell)
-	{
-		// Two ways a cell could be hidden
-		if (cell->getWidth() < 0
-			|| !cell->getVisible()) return;
-
-		LLUI::pushMatrix();
-		{
-			LLUI::translate((F32)rect.mLeft, (F32)rect.mBottom, 0.0f);
-
-			// force first cell to be width of entire item
-			cell->setWidth(rect.getWidth());
-			cell->draw( fg_color, highlight_color );
-		}
-		LLUI::popMatrix();
-	}
-}
-
 //---------------------------------------------------------------------------
 // LLScrollListCtrl
 //---------------------------------------------------------------------------
 
-LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect,
-	void (*commit_callback)(LLUICtrl* ctrl, void* userdata),
-	void* callback_user_data,
-	BOOL allow_multiple_selection,
-	BOOL show_border
-	)
- :	LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data),
+LLScrollListCtrl::Contents::Contents()
+:	columns("columns"),
+	rows("rows")
+{
+	addSynonym(columns, "column");
+	addSynonym(rows, "row");
+}
+
+LLScrollListCtrl::Params::Params()
+:	multi_select("multi_select", false),
+	has_border("draw_border"),
+	draw_heading("draw_heading"),
+	search_column("search_column", 0),
+	sort_column("sort_column", -1),
+	sort_ascending("sort_ascending", true),
+	commit_on_keyboard_movement("commit_on_keyboard_movement", true),
+	heading_height("heading_height"),
+	background_visible("background_visible"),
+	draw_stripes("draw_stripes"),
+	column_padding("column_padding"),
+	fg_unselected_color("fg_unselected_color"),
+	fg_selected_color("fg_selected_color"),
+	bg_selected_color("bg_selected_color"),
+	fg_disable_color("fg_disable_color"),
+	bg_writeable_color("bg_writeable_color"),
+	bg_read_only_color("bg_read_only_color"),
+	bg_stripe_color("bg_stripe_color"),
+	hovered_color("hovered_color"),
+	highlighted_color("highlighted_color")
+{
+	name = "scroll_list";
+	mouse_opaque = true;
+}
+
+LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
+:	LLUICtrl(p),
 	mLineHeight(0),
 	mScrollLines(0),
 	mPageLines(0),
-	mHeadingHeight(20),
 	mMaxSelectable(0),
-	mAllowMultipleSelection( allow_multiple_selection ),
 	mAllowKeyboardMovement(TRUE),
-	mCommitOnKeyboardMovement(TRUE),
+	mCommitOnKeyboardMovement(p.commit_on_keyboard_movement),
 	mCommitOnSelectionChange(FALSE),
 	mSelectionChanged(FALSE),
 	mNeedsScroll(FALSE),
 	mCanSelect(TRUE),
-	mDisplayColumnHeaders(FALSE),
 	mColumnsDirty(FALSE),
 	mMaxItemCount(INT_MAX), 
 	mMaxContentWidth(0),
-	mBackgroundVisible( TRUE ),
-	mDrawStripes(TRUE),
-	mBgWriteableColor(	LLUI::sColorsGroup->getColor( "ScrollBgWriteableColor" ) ),
-	mBgReadOnlyColor(	LLUI::sColorsGroup->getColor( "ScrollBgReadOnlyColor" ) ),
-	mBgSelectedColor( LLUI::sColorsGroup->getColor("ScrollSelectedBGColor") ),
-	mBgStripeColor( LLUI::sColorsGroup->getColor("ScrollBGStripeColor") ),
-	mFgSelectedColor( LLUI::sColorsGroup->getColor("ScrollSelectedFGColor") ),
-	mFgUnselectedColor( LLUI::sColorsGroup->getColor("ScrollUnselectedColor") ),
-	mFgDisabledColor( LLUI::sColorsGroup->getColor("ScrollDisabledColor") ),
-	mHighlightedColor( LLUI::sColorsGroup->getColor("ScrollHighlightedColor") ),
 	mBorderThickness( 2 ),
 	mOnDoubleClickCallback( NULL ),
 	mOnMaximumSelectCallback( NULL ),
 	mOnSortChangedCallback( NULL ),
 	mHighlightedItem(-1),
 	mBorder(NULL),
-	mSearchColumn(0),
 	mNumDynamicWidthColumns(0),
 	mTotalStaticColumnWidth(0),
 	mTotalColumnPadding(0),
-	mSorted(TRUE),
+	mSorted(FALSE),
 	mDirty(FALSE),
 	mOriginalSelection(-1),
-	mDrewSelected(FALSE)
+	mDrewSelected(FALSE),
+	mLastSelected(NULL),
+	mHeadingHeight(p.heading_height),
+	mAllowMultipleSelection(p.multi_select),
+	mDisplayColumnHeaders(p.draw_heading),
+	mBackgroundVisible(p.background_visible),
+	mDrawStripes(p.draw_stripes),
+	mBgWriteableColor(p.bg_writeable_color()),
+	mBgReadOnlyColor(p.bg_read_only_color()),
+	mBgSelectedColor(p.bg_selected_color()),
+	mBgStripeColor(p.bg_stripe_color()),
+	mFgSelectedColor(p.fg_selected_color()),
+	mFgUnselectedColor(p.fg_unselected_color()),
+	mFgDisabledColor(p.fg_disable_color()),
+	mHighlightedColor(p.highlighted_color()),
+	mHoveredColor(p.hovered_color()),
+	mSearchColumn(p.search_column),
+	mColumnPadding(p.column_padding)
 {
 	mItemListRect.setOriginAndSize(
 		mBorderThickness,
@@ -612,37 +196,73 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect,
 	mPageLines = mLineHeight? (mItemListRect.getHeight()) / mLineHeight : 0;
 
 	// Init the scrollbar
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+
 	LLRect scroll_rect;
 	scroll_rect.setOriginAndSize( 
-		getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE,
+		getRect().getWidth() - mBorderThickness - scrollbar_size,
 		mItemListRect.mBottom,
-		SCROLLBAR_SIZE,
+		scrollbar_size,
 		mItemListRect.getHeight());
-	mScrollbar = new LLScrollbar( std::string("Scrollbar"), scroll_rect,
-								  LLScrollbar::VERTICAL,
-								  getItemCount(),
-								  mScrollLines,
-								  mPageLines,
-								  &LLScrollListCtrl::onScrollChange, this );
-	mScrollbar->setFollowsRight();
-	mScrollbar->setFollowsTop();
-	mScrollbar->setFollowsBottom();
-	mScrollbar->setEnabled( TRUE );
-	// scrollbar is visible only when needed
-	mScrollbar->setVisible(FALSE);
+
+	LLScrollbar::Params sbparams;
+	sbparams.name("Scrollbar");
+	sbparams.rect(scroll_rect);
+	sbparams.orientation(LLScrollbar::VERTICAL);
+	sbparams.doc_size(getItemCount());
+	sbparams.doc_pos(mScrollLines);
+	sbparams.page_size(mPageLines);
+	sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2));
+	sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+	sbparams.visible(false);
+	mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
 	addChild(mScrollbar);
 
 	// Border
-	if (show_border)
-	{
-		LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
-		mBorder = new LLViewBorder( std::string("dlg border"), border_rect, LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, 1 );
+	if (p.has_border)
+	{
+		LLRect border_rect = getLocalRect();
+		LLViewBorder::Params params;
+		params.name("dig border");
+		params.rect(border_rect);
+		params.bevel_type(LLViewBorder::BEVEL_IN);
+		mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
 		addChild(mBorder);
 	}
 
-	mColumnPadding = 5;
+	// set border *after* rect is fully initialized
+	if (mBorder)
+	{
+		mBorder->setRect(getLocalRect());
+		mBorder->reshape(getRect().getWidth(), getRect().getHeight());
+	}
+
+	if (p.sort_column >= 0)
+	{
+		sortByColumnIndex(p.sort_column, p.sort_ascending);
+	}
 
-	mLastSelected = NULL;
+	
+	for (LLInitParam::ParamIterator<LLScrollListColumn::Params>::const_iterator row_it = p.contents.columns().begin();
+		row_it != p.contents.columns().end();
+		++row_it)
+	{
+		addColumn(*row_it);
+	}
+
+	for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = p.contents.rows().begin();
+		row_it != p.contents.rows().end();
+		++row_it)
+	{
+		addRow(*row_it);
+	}
+
+	LLTextBox::Params text_p;
+	text_p.name("comment_text");
+	text_p.border_visible(false);
+	text_p.rect(mItemListRect);
+	text_p.follows.flags(FOLLOWS_ALL);
+	addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
 }
 
 S32 LLScrollListCtrl::getSearchColumn()
@@ -666,6 +286,18 @@ S32 LLScrollListCtrl::getSearchColumn()
 	}
 	return llclamp(mSearchColumn, 0, getNumColumns());
 }
+/*virtual*/
+bool LLScrollListCtrl::preProcessChildNode(LLXMLNodePtr child)
+{
+	if (child->hasName("column") || child->hasName("row"))
+	{
+		return true; // skip
+	}
+	else
+	{
+		return false;
+	}
+}
 
 LLScrollListCtrl::~LLScrollListCtrl()
 {
@@ -818,6 +450,7 @@ void LLScrollListCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
 
 void LLScrollListCtrl::updateLayout()
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	// reserve room for column headers, if needed
 	S32 heading_size = (mDisplayColumnHeaders ? mHeadingHeight : 0);
 	mItemListRect.setOriginAndSize(
@@ -826,22 +459,19 @@ void LLScrollListCtrl::updateLayout()
 		getRect().getWidth() - 2 * mBorderThickness,
 		getRect().getHeight() - (2 * mBorderThickness ) - heading_size );
 
+	getChildView("comment_text")->setShape(mItemListRect);
+
 	// how many lines of content in a single "page"
 	mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0;
 	BOOL scrollbar_visible = getItemCount() > mPageLines;
 	if (scrollbar_visible)
 	{
 		// provide space on the right for scrollbar
-		mItemListRect.mRight = getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE;
+		mItemListRect.mRight = getRect().getWidth() - mBorderThickness - scrollbar_size;
 	}
 
-	// don't allow scrolling off bottom
-	if (mScrollLines + mPageLines > getItemCount())
-	{
-		setScrollPos(llmax(0, getItemCount() - mPageLines));
-	}
-
-	mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
+	mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom);
+	mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0));
 	mScrollbar->setPageSize( mPageLines );
 	mScrollbar->setDocSize( getItemCount() );
 	mScrollbar->setVisible(scrollbar_visible);
@@ -916,11 +546,11 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
 		// create new column on demand
 		if (mColumns.empty() && requires_column)
 		{
-			LLSD new_column;
-			new_column["name"] = "default_column";
-			new_column["label"] = "";
-			new_column["dynamicwidth"] = TRUE;
-			addColumn(new_column);
+			LLScrollListColumn::Params col_params;
+			col_params.name =  "default_column";
+			col_params.header.label = "";
+			col_params.width.dynamic_width = true;
+			addColumn(col_params);
 		}
 
 		updateLineHeightInsert(item);
@@ -1017,7 +647,7 @@ void LLScrollListCtrl::updateColumns()
 	// update column headers
 	std::vector<LLScrollListColumn*>::iterator column_ordered_it;
 	S32 left = mItemListRect.mLeft;
-	LLColumnHeader* last_header = NULL;
+	LLScrollColumnHeader* last_header = NULL;
 	for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it)
 	{
 		if ((*column_ordered_it)->getWidth() < 0)
@@ -1052,7 +682,7 @@ void LLScrollListCtrl::updateColumns()
 	}
 
 	// expand last column header we encountered to full list width
-	if (last_header && last_header->canResize())
+	if (last_header)
 	{
 		S32 new_width = llmax(0, mItemListRect.mRight - last_header->getRect().mLeft);
 		last_header->reshape(new_width, last_header->getRect().getHeight());
@@ -1077,13 +707,6 @@ void LLScrollListCtrl::updateColumns()
 
 }
 
-void LLScrollListCtrl::setDisplayHeading(BOOL display)
-{
-	mDisplayColumnHeaders = display;
-
-	updateLayout();
-}
-
 void LLScrollListCtrl::setHeadingHeight(S32 heading_height)
 {
 	mHeadingHeight = heading_height;
@@ -1275,7 +898,15 @@ void LLScrollListCtrl::deleteSelectedItems()
 	dirtyColumns();
 }
 
-void LLScrollListCtrl::highlightNthItem(S32 target_index)
+void LLScrollListCtrl::clearHighlightedItems()
+{	
+	for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter)
+	{
+		(*iter)->setHighlighted(false);
+	}
+}
+
+void LLScrollListCtrl::mouseOverHighlightNthItem(S32 target_index)
 {
 	if (mHighlightedItem != target_index)
 	{
@@ -1283,14 +914,14 @@ void LLScrollListCtrl::highlightNthItem(S32 target_index)
 	}
 }
 
-S32	LLScrollListCtrl::selectMultiple( LLDynamicArray<LLUUID> ids )
+S32	LLScrollListCtrl::selectMultiple( std::vector<LLUUID> ids )
 {
 	item_list::iterator iter;
 	S32 count = 0;
 	for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
 	{
 		LLScrollListItem* item = *iter;
-		LLDynamicArray<LLUUID>::iterator iditr;
+		std::vector<LLUUID>::iterator iditr;
 		for(iditr = ids.begin(); iditr != ids.end(); ++iditr)
 		{
 			if (item->getEnabled() && (item->getUUID() == (*iditr)))
@@ -1446,35 +1077,51 @@ void LLScrollListCtrl::deselectAllItems(BOOL no_commit_on_change)
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Use this to add comment text such as "Searching", which ignores column settings of list
 
-LLScrollListItem* LLScrollListCtrl::addCommentText(const std::string& comment_text, EAddPosition pos)
+void LLScrollListCtrl::setCommentText(const std::string& comment_text)
 {
-	LLScrollListItem* item = NULL;
-	if (getItemCount() < mMaxItemCount)
-	{
-		// always draw comment text with "enabled" color
-		item = new LLScrollListItemComment( comment_text, mFgUnselectedColor );
-		addItem( item, pos, FALSE );
-	}
-	return item;
+	getChild<LLTextBox>("comment_text")->setValue(comment_text);
 }
 
 LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos)
 {
-	LLScrollListItem* item = new LLScrollListItemSeparator();
-	addItem(item, pos, FALSE);
-	return item;
+	LLScrollListItem::Params separator_params;
+	separator_params.enabled(false);
+	LLScrollListCell::Params cell_params;
+	cell_params.type = "icon";
+	cell_params.value = "menu_separator";
+	cell_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f);
+	cell_params.font_halign = LLFontGL::HCENTER;
+	separator_params.cells.add(cell_params);
+	return addRow( separator_params, pos );
 }
 
 // Selects first enabled item of the given name.
 // Returns false if item not found.
+// Calls getItemByLabel in order to combine functionality
 BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sensitive)
 {
-	// ensure that no stale items are selected, even if we don't find a match
-	deselectAllItems(TRUE);
-	//RN: assume no empty items
-	if (label.empty())
+	deselectAllItems(TRUE); 	// ensure that no stale items are selected, even if we don't find a match
+	LLScrollListItem* item = getItemByLabel(label, case_sensitive);
+
+	bool found = NULL != item;
+	if(found)
 	{
-		return FALSE;
+		selectItem(item);
+	}
+
+	if (mCommitOnSelectionChange)
+	{
+		commitIfChanged();
+	}
+
+	return found;
+}
+
+LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOOL case_sensitive, S32 column)
+{
+	if (label.empty()) 	//RN: assume no empty items
+	{
+		return NULL;
 	}
 
 	std::string target_text = label;
@@ -1483,34 +1130,21 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
 		LLStringUtil::toLower(target_text);
 	}
 
-	BOOL found = FALSE;
-
 	item_list::iterator iter;
-	S32 index = 0;
 	for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
 	{
 		LLScrollListItem* item = *iter;
-		// Only select enabled items with matching names
-		std::string item_text = item->getColumn(0)->getValue().asString();
+		std::string item_text = item->getColumn(column)->getValue().asString();	// Only select enabled items with matching names
 		if (!case_sensitive)
 		{
 			LLStringUtil::toLower(item_text);
 		}
-		BOOL select = !found && item->getEnabled() && item_text == target_text;
-		if (select)
+		if(item_text == target_text)
 		{
-			selectItem(item);
+			return item;
 		}
-		found = found || select;
-		index++;
 	}
-
-	if (mCommitOnSelectionChange)
-	{
-		commitIfChanged();
-	}
-
-	return found;
+	return NULL;
 }
 
 
@@ -1614,14 +1248,16 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const
 
 LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled, S32 column_width)
 {
-	LLScrollListItem* item = NULL;
 	if (getItemCount() < mMaxItemCount)
 	{
-		item = new LLScrollListItem( enabled, NULL, id );
-		item->addColumn(item_text, LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF_SMALL), column_width);
-		addItem( item, pos );
+		LLScrollListItem::Params item_p;
+		item_p.enabled(enabled);
+		item_p.value(id);
+		item_p.cells.add().value(item_text).width(column_width).type("text");
+
+		return addRow( item_p, pos );
 	}
-	return item;
+	return NULL;
 }
 
 // Select the line or lines that match this UUID
@@ -1726,7 +1362,7 @@ void LLScrollListCtrl::drawItems()
 		S32 max_columns = 0;
 
 		LLColor4 highlight_color = LLColor4::white;
-		F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout");
+		static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
 		highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f);
 
 		item_list::iterator iter;
@@ -1754,27 +1390,46 @@ void LLScrollListCtrl::drawItems()
 
 			if( mScrollLines <= line && line < mScrollLines + num_page_lines )
 			{
-				fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor);
+				fg_color = (item->getEnabled() ? mFgUnselectedColor.get() : mFgDisabledColor.get());
 				if( item->getSelected() && mCanSelect)
 				{
-					bg_color = mBgSelectedColor;
-					fg_color = (item->getEnabled() ? mFgSelectedColor : mFgDisabledColor);
+					if(item->getHighlighted())	// if it's highlighted, average the colors
+					{
+						bg_color = lerp(mBgSelectedColor.get(), mHighlightedColor.get(), 0.5f);
+					}
+					else						// otherwise just select-highlight it
+					{
+						bg_color = mBgSelectedColor.get();
+					}
+
+					fg_color = (item->getEnabled() ? mFgSelectedColor.get() : mFgDisabledColor.get());
 				}
 				else if (mHighlightedItem == line && mCanSelect)
 				{
-					bg_color = mHighlightedColor;
+					if(item->getHighlighted())	// if it's highlighted, average the colors
+					{
+						bg_color = lerp(mHoveredColor.get(), mHighlightedColor.get(), 0.5f);
+					}
+					else						// otherwise just hover-highlight it
+					{
+						bg_color = mHoveredColor.get();
+					}
+				}
+				else if (item->getHighlighted())
+				{
+					bg_color = mHighlightedColor.get();
 				}
 				else 
 				{
 					if (mDrawStripes && (line % 2 == 0) && (max_columns > 1))
 					{
-						bg_color = mBgStripeColor;
+						bg_color = mBgStripeColor.get();
 					}
 				}
 
 				if (!item->getEnabled())
 				{
-					bg_color = mBgReadOnlyColor;
+					bg_color = mBgReadOnlyColor.get();
 				}
 
 				item->draw(item_rect, fg_color, bg_color, highlight_color, mColumnPadding);
@@ -1807,8 +1462,7 @@ void LLScrollListCtrl::draw()
 	if (mBackgroundVisible)
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.color4fv( getEnabled() ? mBgWriteableColor.mV : mBgReadOnlyColor.mV );
-		gl_rect_2d(background);
+		gl_rect_2d(background, getEnabled() ? mBgWriteableColor.get() : mBgReadOnlyColor.get() );
 	}
 
 	if (mColumnsDirty)
@@ -1817,6 +1471,8 @@ void LLScrollListCtrl::draw()
 		mColumnsDirty = FALSE;
 	}
 
+	getChildView("comment_text")->setVisible(mItemList.empty());
+
 	drawItems();
 
 	if (mBorder)
@@ -1879,7 +1535,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sti
 	}
 
 	// otherwise, look for a tooltip associated with this column
-	LLColumnHeader* headerp = columnp->mHeader;
+	LLScrollColumnHeader* headerp = columnp->mHeader;
 	if (headerp && !handled)
 	{
 		headerp->handleToolTip(x, y, msg, sticky_rect_screen);
@@ -1922,7 +1578,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 						{
 							if(mOnMaximumSelectCallback)
 							{
-								mOnMaximumSelectCallback(mCallbackUserData);
+								mOnMaximumSelectCallback();
 							}
 							break;
 						}
@@ -1960,7 +1616,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
 					{
 						if(mOnMaximumSelectCallback)
 						{
-							mOnMaximumSelectCallback(mCallbackUserData);
+							mOnMaximumSelectCallback();
 						}
 					}
 				}
@@ -2051,7 +1707,7 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
 		{
 			if( mCanSelect && mOnDoubleClickCallback )
 			{
-				mOnDoubleClickCallback( mCallbackUserData );
+				mOnDoubleClickCallback();
 			}
 		}
 	}
@@ -2221,11 +1877,11 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 		LLScrollListItem* item = hitItem(x, y);
 		if (item)
 		{
-			highlightNthItem(getItemIndex(item));
+			mouseOverHighlightNthItem(getItemIndex(item));
 		}
 		else
 		{
-			highlightNthItem(-1);
+			mouseOverHighlightNthItem(-1);
 		}
 	}
 
@@ -2234,6 +1890,11 @@ BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
 	return handled;
 }
 
+void LLScrollListCtrl::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+	// clear mouse highlight
+	mouseOverHighlightNthItem(-1);
+}
 
 BOOL LLScrollListCtrl::handleKeyHere(KEY key,MASK mask )
 {
@@ -2378,7 +2039,8 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
 	}
 
 	// perform incremental search based on keyboard input
-	if (mSearchTimer.getElapsedTimeF32() > LLUI::sConfigGroup->getF32("TypeAheadTimeout"))
+	static LLUICachedControl<F32> type_ahead_timeout ("TypeAheadTimeout", 0);
+	if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout)
 	{
 		mSearchString.clear();
 	}
@@ -2554,7 +2216,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
 	LLScrollListColumn* sort_column = getColumn(column_idx);
 	if (!sort_column) return FALSE;
 
-	sort_column->mSortAscending = ascending;
+	sort_column->mSortDirection = ascending ? LLScrollListColumn::ASCENDING : LLScrollListColumn::DESCENDING;
 
 	sort_column_t new_sort_column(column_idx, ascending);
 
@@ -2579,11 +2241,9 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
 }
 
 // Called by scrollbar
-//static
-void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar, void* userdata )
+void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar )
 {
-	LLScrollListCtrl* self = (LLScrollListCtrl*) userdata;
-	self->mScrollLines = new_pos;
+	mScrollLines = new_pos;
 }
 
 
@@ -2656,7 +2316,7 @@ void LLScrollListCtrl::setScrollPos( S32 pos )
 {
 	mScrollbar->setDocPos( pos );
 
-	onScrollChange(mScrollbar->getDocPos(), mScrollbar, this);
+	onScrollChange(mScrollbar->getDocPos(), mScrollbar);
 }
 
 
@@ -2706,293 +2366,6 @@ void LLScrollListCtrl::updateStaticColumnWidth(LLScrollListColumn* col, S32 new_
 	mTotalStaticColumnWidth += llmax(0, new_width) - llmax(0, col->getWidth());
 }
 
-
-// virtual
-LLXMLNodePtr LLScrollListCtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	// Attributes
-
-	node->createChild("multi_select", TRUE)->setBoolValue(mAllowMultipleSelection);
-
-	node->createChild("draw_border", TRUE)->setBoolValue((mBorder != NULL));
-
-	node->createChild("draw_heading", TRUE)->setBoolValue(mDisplayColumnHeaders);
-
-	node->createChild("background_visible", TRUE)->setBoolValue(mBackgroundVisible);
-
-	node->createChild("draw_stripes", TRUE)->setBoolValue(mDrawStripes);
-
-	node->createChild("column_padding", TRUE)->setIntValue(mColumnPadding);
-
-	addColorXML(node, mBgWriteableColor, "bg_writeable_color", "ScrollBgWriteableColor");
-	addColorXML(node, mBgReadOnlyColor, "bg_read_only_color", "ScrollBgReadOnlyColor");
-	addColorXML(node, mBgSelectedColor, "bg_selected_color", "ScrollSelectedBGColor");
-	addColorXML(node, mBgStripeColor, "bg_stripe_color", "ScrollBGStripeColor");
-	addColorXML(node, mFgSelectedColor, "fg_selected_color", "ScrollSelectedFGColor");
-	addColorXML(node, mFgUnselectedColor, "fg_unselected_color", "ScrollUnselectedColor");
-	addColorXML(node, mFgDisabledColor, "fg_disable_color", "ScrollDisabledColor");
-	addColorXML(node, mHighlightedColor, "highlighted_color", "ScrollHighlightedColor");
-
-	// Contents
-
-	std::map<std::string, LLScrollListColumn>::const_iterator itor;
-	std::vector<const LLScrollListColumn*> sorted_list;
-	sorted_list.resize(mColumns.size());
-	for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
-	{
-		sorted_list[itor->second.mIndex] = &itor->second;
-	}
-
-	std::vector<const LLScrollListColumn*>::iterator itor2;
-	for (itor2 = sorted_list.begin(); itor2 != sorted_list.end(); ++itor2)
-	{
-		LLXMLNodePtr child_node = node->createChild("column", FALSE);
-		const LLScrollListColumn *column = *itor2;
-
-		child_node->createChild("name", TRUE)->setStringValue(column->mName);
-		child_node->createChild("label", TRUE)->setStringValue(column->mLabel);
-		child_node->createChild("width", TRUE)->setIntValue(column->getWidth());
-	}
-
-	return node;
-}
-
-void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node)
-{
-	// James: This is not a good way to do colors. We need a central "UI style"
-	// manager that sets the colors for ALL scroll lists, buttons, etc.
-
-	LLColor4 color;
-	if(node->hasAttribute("fg_unselected_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"fg_unselected_color", color);
-		setFgUnselectedColor(color);
-	}
-	if(node->hasAttribute("fg_selected_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"fg_selected_color", color);
-		setFgSelectedColor(color);
-	}
-	if(node->hasAttribute("bg_selected_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"bg_selected_color", color);
-		setBgSelectedColor(color);
-	}
-	if(node->hasAttribute("fg_disable_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"fg_disable_color", color);
-		setFgDisableColor(color);
-	}
-	if(node->hasAttribute("bg_writeable_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"bg_writeable_color", color);
-		setBgWriteableColor(color);
-	}
-	if(node->hasAttribute("bg_read_only_color"))
-	{
-		LLUICtrlFactory::getAttributeColor(node,"bg_read_only_color", color);
-		setReadOnlyBgColor(color);
-	}
-	if (LLUICtrlFactory::getAttributeColor(node,"bg_stripe_color", color))
-	{
-		setBgStripeColor(color);
-	}
-	if (LLUICtrlFactory::getAttributeColor(node,"highlighted_color", color))
-	{
-		setHighlightedColor(color);
-	}
-
-	if(node->hasAttribute("background_visible"))
-	{
-		BOOL background_visible;
-		node->getAttributeBOOL("background_visible", background_visible);
-		setBackgroundVisible(background_visible);
-	}
-
-	if(node->hasAttribute("draw_stripes"))
-	{
-		BOOL draw_stripes;
-		node->getAttributeBOOL("draw_stripes", draw_stripes);
-		setDrawStripes(draw_stripes);
-	}
-	
-	if(node->hasAttribute("column_padding"))
-	{
-		S32 column_padding;
-		node->getAttributeS32("column_padding", column_padding);
-		setColumnPadding(column_padding);
-	}
-}
-
-// static
-LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("scroll_list");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	BOOL multi_select = FALSE;
-	node->getAttributeBOOL("multi_select", multi_select);
-
-	BOOL draw_border = TRUE;
-	node->getAttributeBOOL("draw_border", draw_border);
-
-	BOOL draw_heading = FALSE;
-	node->getAttributeBOOL("draw_heading", draw_heading);
-
-	S32 search_column = 0;
-	node->getAttributeS32("search_column", search_column);
-
-	S32 sort_column = -1;
-	node->getAttributeS32("sort_column", sort_column);
-
-	BOOL sort_ascending = TRUE;
-	node->getAttributeBOOL("sort_ascending", sort_ascending);
-
-	LLUICtrlCallback callback = NULL;
-
-	LLScrollListCtrl* scroll_list = new LLScrollListCtrl(
-		name,
-		rect,
-		callback,
-		NULL,
-		multi_select,
-		draw_border);
-
-	scroll_list->setDisplayHeading(draw_heading);
-	if (node->hasAttribute("heading_height"))
-	{
-		S32 heading_height;
-		node->getAttributeS32("heading_height", heading_height);
-		scroll_list->setHeadingHeight(heading_height);
-	}
-
-	scroll_list->setScrollListParameters(node);
-
-	scroll_list->initFromXML(node, parent);
-
-	scroll_list->setSearchColumn(search_column);
-
-	LLSD columns;
-	S32 index = 0;
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		if (child->hasName("column"))
-		{
-			std::string labelname("");
-			child->getAttributeString("label", labelname);
-
-			std::string columnname(labelname);
-			child->getAttributeString("name", columnname);
-
-			std::string sortname(columnname);
-			child->getAttributeString("sort", sortname);
-		
-			BOOL sort_ascending = TRUE;
-			child->getAttributeBOOL("sort_ascending", sort_ascending);
-
-			std::string imagename;
-			child->getAttributeString("image", imagename);
-
-			BOOL columndynamicwidth = FALSE;
-			child->getAttributeBOOL("dynamicwidth", columndynamicwidth);
-
-			S32 columnwidth = -1;
-			child->getAttributeS32("width", columnwidth);	
-
-			std::string tooltip;
-			child->getAttributeString("tool_tip", tooltip);
-
-			F32 columnrelwidth = 0.f;
-			child->getAttributeF32("relwidth", columnrelwidth);
-
-			LLFontGL::HAlign h_align = LLFontGL::LEFT;
-			h_align = LLView::selectFontHAlign(child);
-
-			columns[index]["name"] = columnname;
-			columns[index]["sort"] = sortname;
-			columns[index]["sort_ascending"] = sort_ascending;
-			columns[index]["image"] = imagename;
-			columns[index]["label"] = labelname;
-			columns[index]["width"] = columnwidth;
-			columns[index]["relwidth"] = columnrelwidth;
-			columns[index]["dynamicwidth"] = columndynamicwidth;
-			columns[index]["halign"] = (S32)h_align;
-			columns[index]["tool_tip"] = tooltip;
-			
-			index++;
-		}
-	}
-	scroll_list->setColumnHeadings(columns);
-
-	if (sort_column >= 0)
-	{
-		scroll_list->sortByColumnIndex(sort_column, sort_ascending);
-	}
-
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		if (child->hasName("row"))
-		{
-			LLUUID id;
-			child->getAttributeUUID("id", id);
-
-			LLSD row;
-
-			row["id"] = id;
-
-			S32 column_idx = 0;
-			LLXMLNodePtr row_child;
-			for (row_child = child->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling())
-			{
-				if (row_child->hasName("column"))
-				{
-					std::string value = row_child->getTextContents();
-
-					std::string columnname("");
-					row_child->getAttributeString("name", columnname);
-
-					std::string font("");
-					row_child->getAttributeString("font", font);
-
-					std::string font_style("");
-					row_child->getAttributeString("font-style", font_style);
-
-					row["columns"][column_idx]["column"] = columnname;
-					row["columns"][column_idx]["value"] = value;
-					row["columns"][column_idx]["font"] = font;
-					row["columns"][column_idx]["font-style"] = font_style;
-					column_idx++;
-				}
-			}
-			scroll_list->addElement(row);
-		}
-	}
-
-	std::string contents = node->getTextContents();
-	if (!contents.empty())
-	{
-		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-		boost::char_separator<char> sep("\t\n");
-		tokenizer tokens(contents, sep);
-		tokenizer::iterator token_iter = tokens.begin();
-
-		while(token_iter != tokens.end())
-		{
-			const std::string& line = *token_iter;
-			scroll_list->addSimpleElement(line);
-			++token_iter;
-		}
-	}
-	
-	return scroll_list;
-}
-
 // LLEditMenuHandler functions
 
 // virtual
@@ -3068,20 +2441,27 @@ BOOL	LLScrollListCtrl::canDeselect() const
 
 void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
 {
-	std::string name = column["name"].asString();
+	LLScrollListColumn::Params p;
+	LLParamSDParser::instance().readSD(column, p);
+	addColumn(p, pos);
+}
+
+void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params, EAddPosition pos)
+{
+	if (!column_params.validateBlock()) return;
+
+	std::string name = column_params.name;
 	// if no column name provided, just use ordinal as name
 	if (name.empty())
 	{
-		std::ostringstream new_name;
-		new_name << mColumnsIndexed.size();
-		name = new_name.str();
+		name = llformat("%d", mColumnsIndexed.size());
 	}
+
 	if (mColumns.find(name) == mColumns.end())
 	{
 		// Add column
-		mColumns[name] = LLScrollListColumn(column, this);
+		mColumns[name] = LLScrollListColumn(column_params, this);
 		LLScrollListColumn* new_column = &mColumns[name];
-		new_column->mParentCtrl = this;
 		new_column->mIndex = mColumns.size()-1;
 
 		// Add button
@@ -3101,44 +2481,47 @@ void LLScrollListCtrl::addColumn(const LLSD& column, EAddPosition pos)
 				new_column->setWidth((mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns);
 			}
 			S32 top = mItemListRect.mTop;
+
 			S32 left = mItemListRect.mLeft;
+			for (std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.begin(); 
+				itor != mColumns.end(); 
+				++itor)
 			{
-				std::map<std::string, LLScrollListColumn>::iterator itor;
-				for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
+				if (itor->second.mIndex < new_column->mIndex &&
+					itor->second.getWidth() > 0)
 				{
-					if (itor->second.mIndex < new_column->mIndex &&
-						itor->second.getWidth() > 0)
-					{
-						left += itor->second.getWidth() + mColumnPadding;
-					}
+					left += itor->second.getWidth() + mColumnPadding;
 				}
 			}
-			std::string button_name = "btn_" + name;
+
 			S32 right = left+new_column->getWidth();
 			if (new_column->mIndex != (S32)mColumns.size()-1)
 			{
 				right += mColumnPadding;
 			}
+
 			LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
-			new_column->mHeader = new LLColumnHeader(button_name, temp_rect, new_column); 
-			if(column["image"].asString() != "")
+
+			LLScrollColumnHeader::Params params;
+			params.name = "btn_" + name;
+			params.rect = temp_rect;
+			params.column = new_column;
+			params.tool_tip = column_params.tool_tip;
+			params.tab_stop = false;
+			params.visible = mDisplayColumnHeaders;
+
+			if(column_params.header.image.isProvided())
 			{
-				//new_column->mHeader->setScaleImage(false);
-				new_column->mHeader->setImage(column["image"].asString());				
+				params.image_selected = column_params.header.image;
+				params.image_unselected = column_params.header.image;
 			}
 			else
 			{
-				new_column->mHeader->setLabel(new_column->mLabel);
-				//new_column->mHeader->setLabel(new_column->mLabel);
+				params.label = column_params.header.label;
 			}
 
-			new_column->mHeader->setToolTip(column["tool_tip"].asString());
-
-			//RN: although it might be useful to change sort order with the keyboard,
-			// mixing tab stops on child items along with the parent item is not supported yet
-			new_column->mHeader->setTabStop(FALSE);
+			new_column->mHeader = LLUICtrlFactory::create<LLScrollColumnHeader>(params); 
 			addChild(new_column->mHeader);
-			new_column->mHeader->setVisible(mDisplayColumnHeaders);
 
 			sendChildToFront(mScrollbar);
 		}
@@ -3159,7 +2542,7 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
 	S32 column_index = info->mIndex;
 
 	LLScrollListColumn* column = parent->mColumnsIndexed[info->mIndex];
-	bool ascending = column->mSortAscending;
+	bool ascending = column->mSortDirection == LLScrollListColumn::ASCENDING;
 	if (column->mSortingColumn != column->mName
 		&& parent->mColumns.find(column->mSortingColumn) != parent->mColumns.end())
 	{
@@ -3178,7 +2561,7 @@ void LLScrollListCtrl::onClickColumn(void *userdata)
 
 	if (parent->mOnSortChangedCallback)
 	{
-		parent->mOnSortChangedCallback(parent->getCallbackUserData());
+		parent->mOnSortChangedCallback();
 	}
 }
 
@@ -3200,7 +2583,7 @@ void LLScrollListCtrl::clearColumns()
 	std::map<std::string, LLScrollListColumn>::iterator itor;
 	for (itor = mColumns.begin(); itor != mColumns.end(); ++itor)
 	{
-		LLColumnHeader *header = itor->second.mHeader;
+		LLScrollColumnHeader *header = itor->second.mHeader;
 		if (header)
 		{
 			removeChild(header);
@@ -3215,13 +2598,13 @@ void LLScrollListCtrl::clearColumns()
 
 void LLScrollListCtrl::setColumnLabel(const std::string& column, const std::string& label)
 {
-	std::map<std::string, LLScrollListColumn>::iterator itor = mColumns.find(column);
-	if (itor != mColumns.end())
+	LLScrollListColumn* columnp = getColumn(column);
+	if (columnp)
 	{
-		itor->second.mLabel = label;
-		if (itor->second.mHeader)
+		columnp->mLabel = label;
+		if (columnp->mHeader)
 		{
-			itor->second.mHeader->setLabel(label);
+			columnp->mHeader->setLabel(label);
 		}
 	}
 }
@@ -3235,74 +2618,62 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(S32 index)
 	return mColumnsIndexed[index];
 }
 
-void LLScrollListCtrl::setColumnHeadings(LLSD headings)
+LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name)
 {
-	mColumns.clear();
-	LLSD::array_const_iterator itor;
-	for (itor = headings.beginArray(); itor != headings.endArray(); ++itor)
+	column_map_t::iterator column_itor = mColumns.find(name);
+	if (column_itor != mColumns.end()) 
 	{
-		addColumn(*itor);
+		return &column_itor->second;
 	}
+	return NULL;
 }
 
-LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition pos, void* userdata)
+
+LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata)
 {
-	// ID
-	LLSD id = value["id"];
+	LLScrollListItem::Params item_params;
+	LLParamSDParser::instance().readSD(element, item_params);
+	item_params.userdata = userdata;
+	return addRow(item_params, pos);
+}
 
-	LLScrollListItem *new_item = new LLScrollListItem(id, userdata);
-	if (value.has("enabled"))
-	{
-		new_item->setEnabled( value["enabled"].asBoolean() );
-	}
+LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos)
+{
+	if (!item_p.validateBlock()) return NULL;
 
+	LLScrollListItem *new_item = new LLScrollListItem(item_p);
 	new_item->setNumColumns(mColumns.size());
 
 	// Add any columns we don't already have
-	LLSD columns = value["columns"];
-	LLSD::array_const_iterator itor;
-	S32 col_index = 0 ;
-	for (itor = columns.beginArray(); itor != columns.endArray(); ++itor)
-	{
-		if (itor->isUndefined())
-		{
-			// skip unused columns in item passed in
-			continue;
-		}
-		std::string column = (*itor)["column"].asString();
+	S32 col_index = 0;
 
-		LLScrollListColumn* columnp = NULL;
+	for(LLInitParam::ParamIterator<LLScrollListCell::Params>::const_iterator itor = item_p.cells().begin();
+		itor != item_p.cells().end();
+		++itor)
+	{
+		LLScrollListCell::Params cell_p = *itor;
+		std::string column = cell_p.column;
 
 		// empty columns strings index by ordinal
 		if (column.empty())
 		{
-			std::ostringstream new_name;
-			new_name << col_index;
-			column = new_name.str();
+			column = llformat("%d", col_index);
 		}
 
-		std::map<std::string, LLScrollListColumn>::iterator column_itor;
-		column_itor = mColumns.find(column);
-		if (column_itor != mColumns.end()) 
-		{
-			columnp = &column_itor->second;
-		}
+		LLScrollListColumn* columnp = getColumn(column);
 
 		// create new column on demand
 		if (!columnp)
 		{
-			LLSD new_column;
-			new_column["name"] = column;
-			new_column["label"] = column;
+			LLScrollListColumn::Params new_column;
+			new_column.name = column;
+			new_column.header.label = column;
+
 			// if width supplied for column, use it, otherwise 
 			// use adaptive width
-			if (itor->has("width"))
-			{
-				new_column["width"] = (*itor)["width"];
-			}
-			else
+			if (cell_p.width.isProvided())
 			{
-				new_column["dynamicwidth"] = true;
+				new_column.width.pixel_width = cell_p.width;
 			}
 			addColumn(new_column);
 			columnp = &mColumns[column];
@@ -3310,91 +2681,48 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
 		}
 
 		S32 index = columnp->mIndex;
-		S32 width = columnp->getWidth();
-		LLFontGL::HAlign font_alignment = columnp->mFontAlignment;
-		LLColor4 fcolor = LLColor4::black;
-		
-		LLSD value = (*itor)["value"];
-		std::string fontname = (*itor)["font"].asString();
-		std::string fontstyle = (*itor)["font-style"].asString();
-		std::string type = (*itor)["type"].asString();
-		
-		if ((*itor).has("font-color"))
-		{
-			LLSD sd_color = (*itor)["font-color"];
-			fcolor.setValue(sd_color);
-		}
-		
-		BOOL has_color = (*itor).has("color");
-		LLColor4 color = ((*itor)["color"]);
-		BOOL enabled = !(*itor).has("enabled") || (*itor)["enabled"].asBoolean() == true;
+		cell_p.width.setIfNotProvided(columnp->getWidth());
 
-		const LLFontGL *font = LLResMgr::getInstance()->getRes(fontname);
-		if (!font)
-		{
-			font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
-		}
-		U8 font_style = LLFontGL::getStyleFromString(fontstyle);
+		LLScrollListCell* cell = LLScrollListCell::create(cell_p);
 
-		if (type == "icon")
+		if (cell)
 		{
-			LLScrollListIcon* cell = new LLScrollListIcon(value, width);
-			if (has_color)
-			{
-				cell->setColor(color);
-			}
 			new_item->setColumn(index, cell);
-		}
-		else if (type == "checkbox")
-		{
-			LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(std::string("check"),
-													  LLRect(0, width, width, 0), std::string(" "));
-			ctrl->setEnabled(enabled);
-			ctrl->setValue(value);
-			LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width);
-			if (has_color)
+			if (columnp->mHeader 
+				&& cell->isText() 
+				&& !cell->getValue().asString().empty())
 			{
-				cell->setColor(color);
-			}
-			new_item->setColumn(index, cell);
-		}
-		else if (type == "separator")
-		{
-			LLScrollListSeparator* cell = new LLScrollListSeparator(width);
-			if (has_color)
-			{
-				cell->setColor(color);
+				columnp->mHeader->setHasResizableElement(TRUE);
 			}
-			new_item->setColumn(index, cell);
 		}
-		else if (type == "date")
+
+		col_index++;
+	}
+
+	if (item_p.cells().empty())
+	{
+		if (mColumns.empty())
 		{
-			LLScrollListDate* cell = new LLScrollListDate(value.asDate(), font, width, font_style, font_alignment);
-			if (has_color)
-			{
-				cell->setColor(color);
-			}
-			new_item->setColumn(index, cell);
-			if (columnp->mHeader && !value.asString().empty())
-			{
-				columnp->mHeader->setHasResizableElement(TRUE);
-			}
+			LLScrollListColumn::Params new_column;
+			new_column.name = "0";
+
+			addColumn(new_column);
+			new_item->setNumColumns(mColumns.size());
 		}
-		else
+
+		LLScrollListCell* cell = LLScrollListCell::create(LLScrollListCell::Params().value(item_p.value));
+		if (cell)
 		{
-			LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment, fcolor, TRUE);
-			if (has_color)
-			{
-				cell->setColor(color);
-			}
-			new_item->setColumn(index, cell);
-			if (columnp->mHeader && !value.asString().empty())
+			LLScrollListColumn* columnp = &(mColumns.begin()->second);
+
+			new_item->setColumn(0, cell);
+			if (columnp->mHeader 
+				&& cell->isText() 
+				&& !cell->getValue().asString().empty())
 			{
 				columnp->mHeader->setHasResizableElement(TRUE);
 			}
 		}
-
-		col_index++;
 	}
 
 	// add dummy cells for missing columns
@@ -3404,12 +2732,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
 		if (new_item->getColumn(column_idx) == NULL)
 		{
 			LLScrollListColumn* column_ptr = &column_it->second;
-			new_item->setColumn(column_idx, new LLScrollListText(LLStringUtil::null, LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ), column_ptr->getWidth(), LLFontGL::NORMAL));
+			LLScrollListCell::Params cell_p;
+			cell_p.width = column_ptr->getWidth();
+			
+			new_item->setColumn(column_idx, new LLScrollListSpacer(cell_p));
 		}
 	}
 
 	addItem(new_item, pos);
-
 	return new_item;
 }
 
@@ -3422,14 +2752,13 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, E
 		entry_id = value;
 	}
 
-	LLScrollListItem *new_item = new LLScrollListItem(entry_id);
-
-	const LLFontGL *font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
-
-	new_item->addColumn(value, font, getRect().getWidth());
-
-	addItem(new_item, pos);
-	return new_item;
+	LLScrollListItem::Params item_params;
+	item_params.value(entry_id);
+	item_params.cells.add()
+		.value(value)
+		.font(LLFontGL::getFontSansSerifSmall());
+	
+	return addRow(item_params, pos);
 }
 
 void LLScrollListCtrl::setValue(const LLSD& value )
@@ -3530,484 +2859,3 @@ void LLScrollListCtrl::onFocusLost()
 	LLUICtrl::onFocusLost();
 }
 
-LLColumnHeader::LLColumnHeader(const std::string& label, const LLRect &rect, LLScrollListColumn* column, const LLFontGL* fontp) : 
-	LLComboBox(label, rect, label, NULL, NULL), 
-	mColumn(column),
-	mOrigLabel(label),
-	mShowSortOptions(FALSE),
-	mHasResizableElement(FALSE)
-{
-	mListPosition = LLComboBox::ABOVE;
-	setCommitCallback(onSelectSort);
-	setCallbackUserData(this);
-	mButton->setTabStop(FALSE);
-	// require at least two frames between mouse down and mouse up event to capture intentional "hold" not just bad framerate
-	mButton->setHeldDownDelay(LLUI::sConfigGroup->getF32("ColumnHeaderDropDownDelay"), 2);
-	mButton->setHeldDownCallback(onHeldDown);
-	mButton->setClickedCallback(onClick);
-	mButton->setMouseDownCallback(onMouseDown);
-
-	mButton->setCallbackUserData(this);
-	mButton->setToolTip(label);
-
-	mAscendingText = std::string("[LOW]...[HIGH](Ascending)"); // *TODO: Translate
-	mDescendingText = std::string("[HIGH]...[LOW](Descending)"); // *TODO: Translate
-
-	mList->reshape(llmax(mList->getRect().getWidth(), 110, getRect().getWidth()), mList->getRect().getHeight());
-
-	// resize handles on left and right
-	const S32 RESIZE_BAR_THICKNESS = 3;
-	mResizeBar = new LLResizeBar( 
-		std::string("resizebar"),
-		this,
-		LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0), 
-		MIN_COLUMN_WIDTH, S32_MAX, LLResizeBar::RIGHT );
-	addChild(mResizeBar);
-
-	mResizeBar->setEnabled(FALSE);
-}
-
-LLColumnHeader::~LLColumnHeader()
-{
-}
-
-void LLColumnHeader::draw()
-{
-	BOOL draw_arrow = !mColumn->mLabel.empty() && mColumn->mParentCtrl->isSorted() && mColumn->mParentCtrl->getSortColumnName() == mColumn->mSortingColumn;
-
-	BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
-	mButton->setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, draw_arrow ? LLColor4::white : LLColor4::transparent);
-	mArrowImage = mButton->getImageOverlay();
-
-	//BOOL clip = getRect().mRight > mColumn->mParentCtrl->getItemListRect().getWidth();
-	//LLGLEnable scissor_test(clip ? GL_SCISSOR_TEST : GL_FALSE);
-
-	//LLRect column_header_local_rect(-getRect().mLeft, getRect().getHeight(), mColumn->mParentCtrl->getItemListRect().getWidth() - getRect().mLeft, 0);
-	//LLUI::setScissorRegionLocal(column_header_local_rect);
-
-	// Draw children
-	LLComboBox::draw();
-
-	if (mList->getVisible())
-	{
-		// sync sort order with list selection every frame
-		mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, getCurrentIndex() == 0);
-	}
-}
-
-BOOL LLColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
-	if (canResize() && mResizeBar->getRect().pointInRect(x, y))
-	{
-		// reshape column to max content width
-		LLRect column_rect = getRect();
-		column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
-		userSetShape(column_rect);
-	}
-	else
-	{
-		onClick(this);
-	}
-	return TRUE;
-}
-
-void LLColumnHeader::setImage(const std::string &image_name)
-{
-	if (mButton)
-	{
-		mButton->setImageSelected(image_name);
-		mButton->setImageUnselected(image_name);
-	}
-}
-
-//static
-void LLColumnHeader::onClick(void* user_data)
-{
-	LLColumnHeader* headerp = (LLColumnHeader*)user_data;
-	if (!headerp) return;
-
-	LLScrollListColumn* column = headerp->mColumn;
-	if (!column) return;
-
-	if (headerp->mList->getVisible())
-	{
-		headerp->hideList();
-	}
-
-	LLScrollListCtrl::onClickColumn(column);
-
-	// propagate new sort order to sort order list
-	headerp->mList->selectNthItem(column->mParentCtrl->getSortAscending() ? 0 : 1);
-}
-
-//static
-void LLColumnHeader::onMouseDown(void* user_data)
-{
-	// for now, do nothing but block the normal showList() behavior
-	return;
-}
-
-//static
-void LLColumnHeader::onHeldDown(void* user_data)
-{
-	LLColumnHeader* headerp = (LLColumnHeader*)user_data;
-	headerp->showList();
-}
-
-void LLColumnHeader::showList()
-{
-	if (mShowSortOptions)
-	{
-		//LLSD item_val = mColumn->mParentCtrl->getFirstData()->getValue();
-		mOrigLabel = mButton->getLabelSelected();
-
-		// move sort column over to this column and do initial sort
-		mColumn->mParentCtrl->sortByColumn(mColumn->mSortingColumn, mColumn->mParentCtrl->getSortAscending());
-
-		std::string low_item_text;
-		std::string high_item_text;
-
-		LLScrollListItem* itemp = mColumn->mParentCtrl->getFirstData();
-		if (itemp)
-		{
-			LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
-			if (cell && cell->isText())
-			{
-				if (mColumn->mParentCtrl->getSortAscending())
-				{
-					low_item_text = cell->getValue().asString();
-				}
-				else
-				{
-					high_item_text = cell->getValue().asString();
-				}
-			}
-		}
-
-		itemp = mColumn->mParentCtrl->getLastData();
-		if (itemp)
-		{
-			LLScrollListCell* cell = itemp->getColumn(mColumn->mIndex);
-			if (cell && cell->isText())
-			{
-				if (mColumn->mParentCtrl->getSortAscending())
-				{
-					high_item_text = cell->getValue().asString();
-				}
-				else
-				{
-					low_item_text = cell->getValue().asString();
-				}
-			}
-		}
-
-		LLStringUtil::truncate(low_item_text, 3);
-		LLStringUtil::truncate(high_item_text, 3);
-
-		std::string ascending_string;
-		std::string descending_string;
-
-		if (low_item_text.empty() || high_item_text.empty())
-		{
-			ascending_string = "Ascending";
-			descending_string = "Descending";
-		}
-		else
-		{
-			mAscendingText.setArg("[LOW]", low_item_text);
-			mAscendingText.setArg("[HIGH]", high_item_text);
-			mDescendingText.setArg("[LOW]", low_item_text);
-			mDescendingText.setArg("[HIGH]", high_item_text);
-			ascending_string = mAscendingText.getString();
-			descending_string = mDescendingText.getString();
-		}
-
-		S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(ascending_string);
-		text_width = llmax(text_width, LLFontGL::getFontSansSerifSmall()->getWidth(descending_string)) + 10;
-		text_width = llmax(text_width, getRect().getWidth() - 30);
-
-		mList->getColumn(0)->setWidth(text_width);
-		((LLScrollListText*)mList->getFirstData()->getColumn(0))->setText(ascending_string);
-		((LLScrollListText*)mList->getLastData()->getColumn(0))->setText(descending_string);
-
-		mList->reshape(llmax(text_width + 30, 110, getRect().getWidth()), mList->getRect().getHeight());
-
-		LLComboBox::showList();
-	}
-}
-
-//static 
-void LLColumnHeader::onSelectSort(LLUICtrl* ctrl, void* user_data)
-{
-	LLColumnHeader* headerp = (LLColumnHeader*)user_data;
-	if (!headerp) return;
-
-	LLScrollListColumn* column = headerp->mColumn;
-	if (!column) return;
-	LLScrollListCtrl *parent = column->mParentCtrl;
-	if (!parent) return;
-
-	if (headerp->getCurrentIndex() == 0)
-	{
-		// ascending
-		parent->sortByColumn(column->mSortingColumn, TRUE);
-	}
-	else
-	{
-		// descending
-		parent->sortByColumn(column->mSortingColumn, FALSE);
-	}
-
-	// restore original column header
-	headerp->setLabel(headerp->mOrigLabel);
-}
-
-LLView*	LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
-{
-	// this logic assumes dragging on right
-	llassert(snap_edge == SNAP_RIGHT);
-
-	// use higher snap threshold for column headers
-	threshold = llmin(threshold, 10);
-
-	LLRect snap_rect = getSnapRect();
-
-	S32 snap_delta = mColumn->mMaxContentWidth - snap_rect.getWidth();
-
-	// x coord growing means column growing, so same signs mean we're going in right direction
-	if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) 
-	{
-		new_edge_val = snap_rect.mRight + snap_delta;
-	}
-	else 
-	{
-		LLScrollListColumn* next_column = mColumn->mParentCtrl->getColumn(mColumn->mIndex + 1);
-		while (next_column)
-		{
-			if (next_column->mHeader)
-			{
-				snap_delta = (next_column->mHeader->getSnapRect().mRight - next_column->mMaxContentWidth) - snap_rect.mRight;
-				if (llabs(snap_delta) <= threshold && mouse_dir.mX * snap_delta > 0 ) 
-				{
-					new_edge_val = snap_rect.mRight + snap_delta;
-				}
-				break;
-			}
-			next_column = mColumn->mParentCtrl->getColumn(next_column->mIndex + 1);
-		}
-	}
-
-	return this;
-}
-
-void LLColumnHeader::userSetShape(const LLRect& new_rect)
-{
-	S32 new_width = new_rect.getWidth();
-	S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/);
-
-	if (delta_width != 0)
-	{
-		S32 remaining_width = -delta_width;
-		S32 col;
-		for (col = mColumn->mIndex + 1; col < mColumn->mParentCtrl->getNumColumns(); col++)
-		{
-			LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
-			if (!columnp) continue;
-
-			if (columnp->mHeader && columnp->mHeader->canResize())
-			{
-				// how many pixels in width can this column afford to give up?
-				S32 resize_buffer_amt = llmax(0, columnp->getWidth() - MIN_COLUMN_WIDTH);
-				
-				// user shrinking column, need to add width to other columns
-				if (delta_width < 0)
-				{
-					if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0)
-					{
-						// statically sized column, give all remaining width to this column
-						columnp->setWidth(columnp->getWidth() + remaining_width);
-						if (columnp->mRelWidth > 0.f)
-						{
-							columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
-						}
-						// all padding went to this widget, we're done
-						break;
-					}
-				}
-				else
-				{
-					// user growing column, need to take width from other columns
-					remaining_width += resize_buffer_amt;
-
-					if (/*!columnp->mDynamicWidth && */columnp->getWidth() > 0)
-					{
-						columnp->setWidth(columnp->getWidth() - llmin(columnp->getWidth() - MIN_COLUMN_WIDTH, delta_width));
-						if (columnp->mRelWidth > 0.f)
-						{
-							columnp->mRelWidth = (F32)columnp->getWidth() / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
-						}
-					}
-
-					if (remaining_width >= 0)
-					{
-						// width sucked up from neighboring columns, done
-						break;
-					}
-				}
-			}
-		}
-
-		// clamp resize amount to maximum that can be absorbed by other columns
-		if (delta_width > 0)
-		{
-			delta_width += llmin(remaining_width, 0);
-		}
-
-		// propagate constrained delta_width to new width for this column
-		new_width = getRect().getWidth() + delta_width - mColumn->mParentCtrl->getColumnPadding();
-
-		// use requested width
-		mColumn->setWidth(new_width);
-
-		// update proportional spacing
-		if (mColumn->mRelWidth > 0.f)
-		{
-			mColumn->mRelWidth = (F32)new_width / (F32)mColumn->mParentCtrl->getItemListRect().getWidth();
-		}
-
-		// tell scroll list to layout columns again
-		// do immediate update to get proper feedback to resize handle
-		// which needs to know how far the resize actually went
-		mColumn->mParentCtrl->updateColumns();
-	}
-}
-
-void LLColumnHeader::setHasResizableElement(BOOL resizable)
-{
-	// for now, dynamically spaced columns can't be resized
-//	if (mColumn->mDynamicWidth) return;
-
-	if (mHasResizableElement != resizable)
-	{
-		mColumn->mParentCtrl->dirtyColumns();
-		mHasResizableElement = resizable;
-	}
-}
-
-void LLColumnHeader::updateResizeBars()
-{
-	S32 num_resizable_columns = 0;
-	S32 col;
-	for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
-	{
-		LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
-		if (columnp->mHeader && columnp->mHeader->canResize())
-		{
-			num_resizable_columns++;
-		}
-	}
-
-	S32 num_resizers_enabled = 0;
-
-	// now enable/disable resize handles on resizable columns if we have at least two
-	for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++)
-	{
-		LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col);
-		if (!columnp->mHeader) continue;
-		BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize();
-		columnp->mHeader->enableResizeBar(enable);
-		if (enable)
-		{
-			num_resizers_enabled++;
-		}
-	}
-}
-
-void LLColumnHeader::enableResizeBar(BOOL enable)
-{
-	// for now, dynamically spaced columns can't be resized
-	//if (!mColumn->mDynamicWidth)
-	{
-		mResizeBar->setEnabled(enable);
-	}
-}
-
-BOOL LLColumnHeader::canResize()
-{
-	return getVisible() && (mHasResizableElement || mColumn->mDynamicWidth);
-}
-
-void LLScrollListColumn::setWidth(S32 width) 
-{ 
-	if (!mDynamicWidth && mRelWidth <= 0.f) 
-	{
-		mParentCtrl->updateStaticColumnWidth(this, width);
-	}
-	mWidth = width;
-}
-
-// Default constructor
-LLScrollListColumn::LLScrollListColumn() : 
-	mName(), 
-	mSortingColumn(), 
-	mSortAscending(TRUE), 
-	mLabel(), 
-	mWidth(-1), 
-	mRelWidth(-1.0), 
-	mDynamicWidth(FALSE), 
-	mMaxContentWidth(0),
-	mIndex(-1), 
-	mParentCtrl(NULL), 
-	mHeader(NULL), 
-	mFontAlignment(LLFontGL::LEFT)
-{ }
-
-LLScrollListColumn::LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent) :
-	mWidth(0),
-	mIndex (-1),
-	mParentCtrl(parent),
-	mHeader(NULL),
-	mMaxContentWidth(0),
-	mDynamicWidth(FALSE),
-	mRelWidth(-1.f)
-{
-	mName = sd.get("name").asString();
-	mSortingColumn = mName;
-	if (sd.has("sort"))
-	{
-		mSortingColumn = sd.get("sort").asString();
-	}
-	mSortAscending = TRUE;
-	if (sd.has("sort_ascending"))
-	{
-		mSortAscending = sd.get("sort_ascending").asBoolean();
-	}
-	mLabel = sd.get("label").asString();
-	if (sd.has("relwidth") && (F32)sd.get("relwidth").asReal() > 0)
-	{
-		mRelWidth = (F32)sd.get("relwidth").asReal();
-		if (mRelWidth < 0) mRelWidth = 0;
-		if (mRelWidth > 1) mRelWidth = 1;
-		mDynamicWidth = FALSE;
-	}
-	else if(sd.has("dynamicwidth") && (BOOL)sd.get("dynamicwidth").asBoolean() == TRUE)
-	{
-		mDynamicWidth = TRUE;
-		mRelWidth = -1;
-	}
-	else
-	{
-
-		setWidth(sd.get("width").asInteger());
-	}
-
-	if (sd.has("halign"))
-	{
-		mFontAlignment = (LLFontGL::HAlign)llclamp(sd.get("halign").asInteger(), (S32)LLFontGL::LEFT, (S32)LLFontGL::HCENTER);
-	}
-	else
-	{
-		mFontAlignment = LLFontGL::LEFT;
-	}
-
-}
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 72d8894afa..461df6760f 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -1,5 +1,8 @@
 /** 
  * @file llscrolllistctrl.h
+ * @brief A scrolling list of items.  This is the one you want to use
+ * in UI code.  LLScrollListCell, LLScrollListItem, etc. are utility
+ * classes.
  *
  * $LicenseInfo:firstyear=2001&license=viewergpl$
  * 
@@ -37,346 +40,109 @@
 
 #include "lluictrl.h"
 #include "llctrlselectioninterface.h"
-#include "lldarray.h"
+//#include "lldarray.h"
 #include "llfontgl.h"
 #include "llui.h"
-#include "llstring.h"
-#include "llimagegl.h"
+#include "llstring.h"	// LLWString
+//#include "llimagegl.h"
 #include "lleditmenuhandler.h"
 #include "llframetimer.h"
-#include "llcheckboxctrl.h"
-#include "llcombobox.h"
+
 #include "llscrollbar.h"
-#include "llresizebar.h"
 #include "lldate.h"
+#include "llscrolllistitem.h"
+#include "llscrolllistcolumn.h"
 
-/*
- * Represents a cell in a scrollable table.
- *
- * Sub-classes must return height and other properties 
- * though width accessors are implemented by the base class.
- * It is therefore important for sub-class constructors to call
- * setWidth() with realistic values.
- */
-class LLScrollListCell
-{
-public:
-	LLScrollListCell(S32 width = 0) : mWidth(width) {};
-	virtual ~LLScrollListCell() {};
-	virtual void			draw(const LLColor4& color, const LLColor4& highlight_color) const = 0;		// truncate to given width, if possible
-	virtual S32				getWidth() const {return mWidth;}
-	virtual S32				getContentWidth() const { return 0; }
-	virtual S32				getHeight() const = 0;
-	virtual const LLSD		getValue() const { return LLStringUtil::null; }
-	virtual void			setValue(const LLSD& value) { }
-	virtual BOOL			getVisible() const { return TRUE; }
-	virtual void			setWidth(S32 width) { mWidth = width; }
-	virtual void			highlightText(S32 offset, S32 num_chars) {}
-	virtual BOOL			isText() const = 0;
-	virtual void			setColor(const LLColor4&) {}
-	virtual void			onCommit() {};
-
-	virtual BOOL			handleClick() { return FALSE; }
-	virtual	void			setEnabled(BOOL enable) { }
-
-private:
-	S32 mWidth;
-};
-
-/*
- * Draws a horizontal line.
- */
-class LLScrollListSeparator : public LLScrollListCell
-{
-public:
-	LLScrollListSeparator(S32 width);
-	virtual ~LLScrollListSeparator() {};
-	virtual void			draw(const LLColor4& color, const LLColor4& highlight_color) const;		// truncate to given width, if possible
-	virtual S32				getHeight() const;
-	virtual BOOL			isText() const { return FALSE; }
-};
-
-/*
- * Cell displaying a text label.
- */
-class LLScrollListText : public LLScrollListCell
-{
-public:
-	LLScrollListText( const std::string& text, const LLFontGL* font, S32 width = 0, U8 font_style = LLFontGL::NORMAL, LLFontGL::HAlign font_alignment = LLFontGL::LEFT, LLColor4& color = LLColor4::black, BOOL use_color = FALSE, BOOL visible = TRUE);
-	/*virtual*/ ~LLScrollListText();
-
-	virtual void    draw(const LLColor4& color, const LLColor4& highlight_color) const;
-	virtual S32		getContentWidth() const;
-	virtual S32		getHeight() const;
-	virtual void	setValue(const LLSD& value);
-	virtual const LLSD getValue() const;
-	virtual BOOL	getVisible() const;
-	virtual void	highlightText(S32 offset, S32 num_chars);
-
-	virtual void	setColor(const LLColor4&);
-	virtual BOOL	isText() const;
-
-	void			setText(const LLStringExplicit& text);
-	void			setFontStyle(const U8 font_style) { mFontStyle = font_style; }
-
-private:
-	LLUIString		mText;
-	const LLFontGL*	mFont;
-	LLColor4		mColor;
-	U8				mUseColor;
-	U8				mFontStyle;
-	LLFontGL::HAlign mFontAlignment;
-	BOOL			mVisible;
-	S32				mHighlightCount;
-	S32				mHighlightOffset;
-
-	LLPointer<LLUIImage> mRoundedRectImage;
-
-	static U32 sCount;
-};
-
+class LLScrollListCell;
+class LLTextBox;
 
-class LLScrollListDate : public LLScrollListText
-{
-public:
-	LLScrollListDate( const LLDate& date, const LLFontGL* font, S32 width=0, U8 font_style = LLFontGL::NORMAL, LLFontGL::HAlign font_alignment = LLFontGL::LEFT, LLColor4& color = LLColor4::black, BOOL use_color = FALSE, BOOL visible = TRUE);
-	virtual void	setValue(const LLSD& value);
-	virtual const LLSD getValue() const;
-
-private:
-	LLDate		mDate;
-};
-
-/*
- * Cell displaying an image.
- */
-class LLScrollListIcon : public LLScrollListCell
-{
-public:
-	LLScrollListIcon( LLUIImagePtr icon, S32 width = 0);
-	LLScrollListIcon(const LLSD& value, S32 width = 0);
-	/*virtual*/ ~LLScrollListIcon();
-	virtual void	draw(const LLColor4& color, const LLColor4& highlight_color) const;
-	virtual S32		getWidth() const;
-	virtual S32		getHeight() const			{ return mIcon ? mIcon->getHeight() : 0; }
-	virtual const LLSD		getValue() const { return mIcon.isNull() ? LLStringUtil::null : mIcon->getName(); }
-	virtual void	setColor(const LLColor4&);
-	virtual BOOL	isText()const { return FALSE; }
-	virtual void	setValue(const LLSD& value);
-
-private:
-	LLUIImagePtr mIcon;
-	LLColor4 mColor;
-};
-
-/*
- * An interactive cell containing a check box.
- */
-class LLScrollListCheck : public LLScrollListCell
-{
-public:
-	LLScrollListCheck( LLCheckBoxCtrl* check_box, S32 width = 0);
-	/*virtual*/ ~LLScrollListCheck();
-	virtual void	draw(const LLColor4& color, const LLColor4& highlight_color) const;
-	virtual S32		getHeight() const			{ return 0; } 
-	virtual const LLSD	getValue() const { return mCheckBox->getValue(); }
-	virtual void	setValue(const LLSD& value) { mCheckBox->setValue(value); }
-	virtual void	onCommit() { mCheckBox->onCommit(); }
-
-	virtual BOOL	handleClick();
-	virtual void	setEnabled(BOOL enable)		{ mCheckBox->setEnabled(enable); }
-
-	LLCheckBoxCtrl*	getCheckBox()				{ return mCheckBox; }
-	virtual BOOL	isText() const				{ return FALSE; }
-
-private:
-	LLCheckBoxCtrl* mCheckBox;
-};
-
-/*
- * A simple data class describing a column within a scroll list.
- */
-class LLScrollListColumn
-{
-public:
-	LLScrollListColumn();
-	LLScrollListColumn(const LLSD &sd, LLScrollListCtrl* parent);
-
-	void setWidth(S32 width);
-	S32 getWidth() const { return mWidth; }
-
-	// Public data is fine so long as this remains a simple struct-like data class.
-	// If it ever gets any smarter than that, these should all become private
-	// with protected or public accessor methods added as needed. -MG
-	std::string			mName;
-	std::string			mSortingColumn;
-	BOOL				mSortAscending;
-	std::string			mLabel;
-	F32					mRelWidth;
-	BOOL				mDynamicWidth;
-	S32					mMaxContentWidth;
-	S32					mIndex;
-	LLScrollListCtrl*	mParentCtrl;
-	class LLColumnHeader*		mHeader;
-	LLFontGL::HAlign	mFontAlignment;
-
-private:
-	S32					mWidth;
-
-};
-
-class LLColumnHeader : public LLComboBox
-{
-public:
-	LLColumnHeader(const std::string& label, const LLRect &rect, LLScrollListColumn* column, const LLFontGL *font = NULL);
-	~LLColumnHeader();
-
-	/*virtual*/ void draw();
-	/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
-
-	/*virtual*/ void showList();
-	/*virtual*/ LLView*	findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding);
-	/*virtual*/ void userSetShape(const LLRect& new_rect);
-	
-	void setImage(const std::string &image_name);
-	LLScrollListColumn* getColumn() { return mColumn; }
-	void setHasResizableElement(BOOL resizable);
-	void updateResizeBars();
-	BOOL canResize();
-	void enableResizeBar(BOOL enable);
-	std::string getLabel() { return mOrigLabel; }
-
-	static void onSelectSort(LLUICtrl* ctrl, void* user_data);
-	static void onClick(void* user_data);
-	static void onMouseDown(void* user_data);
-	static void onHeldDown(void* user_data);
-
-private:
-	LLScrollListColumn* mColumn;
-	LLResizeBar*		mResizeBar;
-	std::string			mOrigLabel;
-	LLUIString			mAscendingText;
-	LLUIString			mDescendingText;
-	BOOL				mShowSortOptions;
-	BOOL				mHasResizableElement;
-};
-
-class LLScrollListItem
+class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, 
+	public LLCtrlListInterface, public LLCtrlScrollInterface
 {
 public:
-	LLScrollListItem( BOOL enabled = TRUE, void* userdata = NULL, const LLUUID& uuid = LLUUID::null )
-		: mSelected(FALSE), mEnabled( enabled ), mUserdata( userdata ), mItemValue( uuid ), mColumns() {}
-	LLScrollListItem( LLSD item_value, void* userdata = NULL )
-		: mSelected(FALSE), mEnabled( TRUE ), mUserdata( userdata ), mItemValue( item_value ), mColumns() {}
-
-	virtual ~LLScrollListItem();
-
-	void	setSelected( BOOL b )			{ mSelected = b; }
-	BOOL	getSelected() const				{ return mSelected; }
-
-	void	setEnabled( BOOL b );
-	BOOL	getEnabled() const 				{ return mEnabled; }
-
-	void	setUserdata( void* userdata )	{ mUserdata = userdata; }
-	void*	getUserdata() const 			{ return mUserdata; }
+	struct Contents : public LLInitParam::Block<Contents>
+	{
+		Multiple<LLScrollListColumn::Params>	columns;
+		Multiple<LLScrollListItem::Params>		rows;
 
-	LLUUID	getUUID() const					{ return mItemValue.asUUID(); }
-	LLSD	getValue() const				{ return mItemValue; }
+		//Multiple<Contents>						groups;
 
-	// If width = 0, just use the width of the text.  Otherwise override with
-	// specified width in pixels.
-	void	addColumn( const std::string& text, const LLFontGL* font, S32 width = 0 , U8 font_style = LLFontGL::NORMAL, LLFontGL::HAlign font_alignment = LLFontGL::LEFT, BOOL visible = TRUE)
-				{ mColumns.push_back( new LLScrollListText(text, font, width, font_style, font_alignment, LLColor4::black, FALSE, visible) ); }
+		Contents();
+	};
 
-	void	addColumn( LLUIImagePtr icon, S32 width = 0 )
-				{ mColumns.push_back( new LLScrollListIcon(icon, width) ); }
-
-	void	addColumn( LLCheckBoxCtrl* check, S32 width = 0 )
-				{ mColumns.push_back( new LLScrollListCheck(check,width) ); }
-
-	void	setNumColumns(S32 columns);
-
-	void	setColumn( S32 column, LLScrollListCell *cell );
+	// *TODO: Add callbacks to Params
+	typedef boost::function<void (void)> callback_t;
 	
-	S32		getNumColumns() const			{ return mColumns.size(); }
-
-	LLScrollListCell *getColumn(const S32 i) const	{ if (0 <= i && i < (S32)mColumns.size()) { return mColumns[i]; } return NULL; }
-
-	std::string getContentsCSV() const;
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		// behavioral flags
+		Optional<bool>	multi_select,
+						commit_on_keyboard_movement;
+
+		// display flags
+		Optional<bool>	has_border,
+						draw_heading,
+						draw_stripes,
+						background_visible;
+
+		// layout
+		Optional<S32>	column_padding,
+						heading_height;
+
+		// sort and search behavior
+		Optional<S32>	search_column,
+						sort_column;
+		Optional<bool>	sort_ascending;
+
+		// colors
+		Optional<LLUIColor>	fg_unselected_color,
+							fg_selected_color,
+							bg_selected_color,
+							fg_disable_color,
+							bg_writeable_color,
+							bg_read_only_color,
+							bg_stripe_color,
+							hovered_color,
+							highlighted_color;
+
+		Optional<Contents> contents;
+		
+		Params();
+	};
 
-	virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
+protected:
+	friend class LLUICtrlFactory;
 
-private:
-	BOOL	mSelected;
-	BOOL	mEnabled;
-	void*	mUserdata;
-	LLSD	mItemValue;
-	std::vector<LLScrollListCell *> mColumns;
-};
-
-/*
- * A graphical control representing a scrollable table.
- * Cells in the table can be simple text or more complicated things
- * such as icons or even interactive elements like check boxes.
- */
-class LLScrollListItemComment : public LLScrollListItem
-{
-public:
-	LLScrollListItemComment(const std::string& comment_string, const LLColor4& color);
+	LLScrollListCtrl(const Params&);
 
-	/*virtual*/ void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
-private:
-	LLColor4 mColor;
-};
-
-class LLScrollListItemSeparator : public LLScrollListItem
-{
 public:
-	LLScrollListItemSeparator();
-
-	/*virtual*/ void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
-};
-
-class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, 
-	public LLCtrlListInterface, public LLCtrlScrollInterface
-{
-public:
-	LLScrollListCtrl(
-		const std::string& name,
-		const LLRect& rect,
-		void (*commit_callback)(LLUICtrl*, void*),
-		void* callback_userdata,
-		BOOL allow_multiple_selection,
-		BOOL draw_border = TRUE);
-
 	virtual ~LLScrollListCtrl();
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	void setScrollListParameters(LLXMLNodePtr node);
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-
 	S32				isEmpty() const;
 
 	void			deleteAllItems() { clearRows(); }
 	
 	// Sets an array of column descriptors
-	void 	   		setColumnHeadings(LLSD headings);
+	void 	   		setColumnHeadings(const LLSD& headings);
 	void   			sortByColumnIndex(U32 column, BOOL ascending);
 	
 	// LLCtrlListInterface functions
 	virtual S32  getItemCount() const;
 	// Adds a single column descriptor: ["name" : string, "label" : string, "width" : integer, "relwidth" : integer ]
-	virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM);
+	virtual void addColumn(const LLScrollListColumn::Params& column, EAddPosition pos = ADD_BOTTOM);
+	virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM);	
 	virtual void clearColumns();
 	virtual void setColumnLabel(const std::string& column, const std::string& label);
-
+	virtual bool 	preProcessChildNode(LLXMLNodePtr child);
 	virtual LLScrollListColumn* getColumn(S32 index);
+	virtual LLScrollListColumn* getColumn(const std::string& name);
 	virtual S32 getNumColumns() const { return mColumnsIndexed.size(); }
 
 	// Adds a single element, from an array of:
 	// "columns" => [ "column" => column name, "value" => value, "type" => type, "font" => font, "font-style" => style ], "id" => uuid
 	// Creates missing columns automatically.
-	virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
+	virtual LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
+	virtual LLScrollListItem* addRow(const LLScrollListItem::Params& value, EAddPosition pos = ADD_BOTTOM);
 	// Simple add element. Takes a single array of:
 	// [ "value" => value, "font" => font, "font-style" => style ]
 	virtual void clearRows(); // clears all elements
@@ -421,10 +187,14 @@ public:
 	void 			deleteSelectedItems();
 	void			deselectAllItems(BOOL no_commit_on_change = FALSE);	// by default, go ahead and commit on selection change
 
-	void			highlightNthItem( S32 index );
-	void			setDoubleClickCallback( void (*cb)(void*) ) { mOnDoubleClickCallback = cb; }
-	void			setMaximumSelectCallback( void (*cb)(void*) ) { mOnMaximumSelectCallback = cb; }
-	void			setSortChangedCallback( void (*cb)(void*) ) { mOnSortChangedCallback = cb; }
+	void			clearHighlightedItems();
+	void			mouseOverHighlightNthItem( S32 index );
+	
+	void			setDoubleClickCallback( callback_t cb ) { mOnDoubleClickCallback = cb; }
+	void			setMaximumSelectCallback( callback_t cb) { mOnMaximumSelectCallback = cb; }
+	void			setSortChangedCallback( callback_t cb) 	{ mOnSortChangedCallback = cb; }
+	// Convenience function; *TODO: replace with setter above + boost::bind() in calling code
+	void			setDoubleClickCallback( boost::function<void (void* userdata)> cb, void* userdata) { mOnDoubleClickCallback = boost::bind(cb, userdata); }
 
 	void			swapWithNext(S32 index);
 	void			swapWithPrevious(S32 index);
@@ -435,21 +205,21 @@ public:
 	S32				getItemIndex( LLScrollListItem* item ) const;
 	S32				getItemIndex( const LLUUID& item_id ) const;
 
-	LLScrollListItem* addCommentText( const std::string& comment_text, EAddPosition pos = ADD_BOTTOM);
+	void setCommentText( const std::string& comment_text);
 	LLScrollListItem* addSeparator(EAddPosition pos);
 
 	// "Simple" interface: use this when you're creating a list that contains only unique strings, only
 	// one of which can be selected at a time.
 	virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos = ADD_BOTTOM, const LLSD& id = LLSD());
 
-
 	BOOL			selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE );		// FALSE if item not found
 	BOOL			selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE);
 	BOOL			selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE);
+	LLScrollListItem*  getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 );
 	const std::string	getSelectedItemLabel(S32 column = 0) const;
 	LLSD			getSelectedValue();
 
-	// DEPRECATED: Use LLSD versions of addCommentText() and getSelectedValue().
+	// DEPRECATED: Use LLSD versions of setCommentText() and getSelectedValue().
 	// "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which
 	// has an associated, unique UUID, and only one of which can be selected at a time.
 	LLScrollListItem*	addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE, S32 column_width = 0);
@@ -475,7 +245,8 @@ public:
 	void setBgStripeColor(const LLColor4& c)	{ mBgStripeColor = c; }
 	void setFgSelectedColor(const LLColor4 &c)	{ mFgSelectedColor = c; }
 	void setFgUnselectedColor(const LLColor4 &c){ mFgUnselectedColor = c; }
-	void setHighlightedColor(const LLColor4 &c)	{ mHighlightedColor = c; }
+	void setHoveredColor(const LLColor4 &c)		{ mHoveredColor = c; }
+	void setHighlightedColor(const LLColor4 &c) { mHighlightedColor = c; }
 	void setFgDisableColor(const LLColor4 &c)	{ mFgDisabledColor = c; }
 
 	void setBackgroundVisible(BOOL b)			{ mBackgroundVisible = b; }
@@ -514,6 +285,7 @@ public:
 	/*virtual*/ void	setFocus( BOOL b );
 	/*virtual*/ void	onFocusReceived();
 	/*virtual*/ void	onFocusLost();
+	/*virtual*/ void	onMouseLeave(S32 x, S32 y, MASK mask);
 	/*virtual*/ void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
 	virtual BOOL	isDirty() const;
@@ -528,15 +300,14 @@ public:
 	LLRect			getItemListRect() { return mItemListRect; }
 
 	// Used "internally" by the scroll bar.
-	static void		onScrollChange( S32 new_pos, LLScrollbar* src, void* userdata );
+	void			onScrollChange( S32 new_pos, LLScrollbar* src );
 
 	static void onClickColumn(void *userdata);
 
-	void updateColumns();
+	virtual void updateColumns();
 	void calcColumnWidths();
 	S32 getMaxContentWidth() { return mMaxContentWidth; }
 
-	void setDisplayHeading(BOOL display);
 	void setHeadingHeight(S32 heading_height);
 	void setCollapseEmptyColumns(BOOL collapse);
 
@@ -561,7 +332,7 @@ public:
 	BOOL			getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
 	BOOL			needsSorting();
 
-	S32		selectMultiple( LLDynamicArray<LLUUID> ids );
+	S32		selectMultiple( std::vector<LLUUID> ids );
 	void			sortItems();
 	// sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example)
 	void			sortOnce(S32 column, BOOL ascending);
@@ -604,7 +375,6 @@ private:
 	void			commitIfChanged();
 	BOOL			setSort(S32 column, BOOL ascending);
 
-
 	S32				mCurIndex;			// For get[First/Next]Data
 	S32				mCurSelectedIndex;  // For get[First/Next]Selected
 
@@ -621,7 +391,7 @@ private:
 	BOOL			mSelectionChanged;
 	BOOL			mNeedsScroll;
 	BOOL			mCanSelect;
-	BOOL			mDisplayColumnHeaders;
+	const BOOL		mDisplayColumnHeaders;
 	BOOL			mColumnsDirty;
 
 	item_list		mItemList;
@@ -637,19 +407,20 @@ private:
 	BOOL			mBackgroundVisible;
 	BOOL			mDrawStripes;
 
-	LLColor4		mBgWriteableColor;
-	LLColor4		mBgReadOnlyColor;
-	LLColor4		mBgSelectedColor;
-	LLColor4		mBgStripeColor;
-	LLColor4		mFgSelectedColor;
-	LLColor4		mFgUnselectedColor;
-	LLColor4		mFgDisabledColor;
-	LLColor4		mHighlightedColor;
+	LLUIColor		mBgWriteableColor;
+	LLUIColor		mBgReadOnlyColor;
+	LLUIColor		mBgSelectedColor;
+	LLUIColor		mBgStripeColor;
+	LLUIColor		mFgSelectedColor;
+	LLUIColor		mFgUnselectedColor;
+	LLUIColor		mFgDisabledColor;
+	LLUIColor		mHoveredColor;
+	LLUIColor		mHighlightedColor;
 
 	S32				mBorderThickness;
-	void			(*mOnDoubleClickCallback)(void* userdata);
-	void			(*mOnMaximumSelectCallback)(void* userdata );
-	void			(*mOnSortChangedCallback)(void* userdata);
+	callback_t		mOnDoubleClickCallback;
+	callback_t 		mOnMaximumSelectCallback;
+	callback_t 		mOnSortChangedCallback;
 
 	S32				mHighlightedItem;
 	class LLViewBorder*	mBorder;
@@ -678,7 +449,15 @@ private:
 
 	// HACK:  Did we draw one selected item this frame?
 	BOOL mDrewSelected;
+
+	LLTextBox*		mCommentTextBox;
 }; // end class LLScrollListCtrl
 
+#ifdef LL_WINDOWS
+#ifndef INSTANTIATE_GETCHILD_SCROLLLIST
+#pragma warning (disable : 4231)
+extern template LLScrollListCtrl* LLView::getChild<LLScrollListCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+#endif
+#endif
 
 #endif  // LL_SCROLLLISTCTRL_H
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
new file mode 100644
index 0000000000..2ac6925c78
--- /dev/null
+++ b/indra/llui/llscrolllistitem.cpp
@@ -0,0 +1,157 @@
+/** 
+ * @file llscrolllistitem.cpp
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llscrolllistitem.h"
+
+#include "llrect.h"
+#include "llresmgr.h"		// LLFONT_SANSSERIF_SMALL
+#include "llui.h"
+
+
+//---------------------------------------------------------------------------
+// LLScrollListItem
+//---------------------------------------------------------------------------
+
+LLScrollListItem::LLScrollListItem( const Params& p )
+:	mSelected(FALSE),
+	mHighlighted(FALSE),
+	mEnabled(p.enabled),
+	mUserdata(p.userdata),
+	mItemValue(p.value)
+{
+}
+
+
+LLScrollListItem::~LLScrollListItem()
+{
+	std::for_each(mColumns.begin(), mColumns.end(), DeletePointer());
+}
+
+void LLScrollListItem::addColumn(const LLScrollListCell::Params& p)
+{
+	mColumns.push_back(LLScrollListCell::create(p));
+}
+
+void LLScrollListItem::setNumColumns(S32 columns)
+{
+	S32 prev_columns = mColumns.size();
+	if (columns < prev_columns)
+	{
+		std::for_each(mColumns.begin()+columns, mColumns.end(), DeletePointer());
+	}
+	
+	mColumns.resize(columns);
+
+	for (S32 col = prev_columns; col < columns; ++col)
+	{
+		mColumns[col] = NULL;
+	}
+}
+
+void LLScrollListItem::setColumn( S32 column, LLScrollListCell *cell )
+{
+	if (column < (S32)mColumns.size())
+	{
+		delete mColumns[column];
+		mColumns[column] = cell;
+	}
+	else
+	{
+		llerrs << "LLScrollListItem::setColumn: bad column: " << column << llendl;
+	}
+}
+
+
+S32 LLScrollListItem::getNumColumns() const
+{
+	return mColumns.size();
+}
+
+LLScrollListCell* LLScrollListItem::getColumn(const S32 i) const
+{
+	if (0 <= i && i < (S32)mColumns.size())
+	{
+		return mColumns[i];
+	} 
+	return NULL;
+}
+
+std::string LLScrollListItem::getContentsCSV() const
+{
+	std::string ret;
+
+	S32 count = getNumColumns();
+	for (S32 i=0; i<count; ++i)
+	{
+		ret += getColumn(i)->getValue().asString();
+		if (i < count-1)
+		{
+			ret += ", ";
+		}
+	}
+
+	return ret;
+}
+
+
+void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding)
+{
+	// draw background rect
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	LLRect bg_rect = rect;
+	gl_rect_2d( bg_rect, bg_color );
+
+	S32 cur_x = rect.mLeft;
+	S32 num_cols = getNumColumns();
+	S32 cur_col = 0;
+
+	for (LLScrollListCell* cell = getColumn(0); cur_col < num_cols; cell = getColumn(++cur_col))
+	{
+		// Two ways a cell could be hidden
+		if (cell->getWidth() < 0
+			|| !cell->getVisible()) continue;
+
+		LLUI::pushMatrix();
+		{
+			LLUI::translate((F32) cur_x, (F32) rect.mBottom, 0.0f);
+
+			cell->draw( fg_color, highlight_color );
+		}
+		LLUI::popMatrix();
+		
+		cur_x += cell->getWidth() + column_padding;
+	}
+}
+
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
new file mode 100644
index 0000000000..8d87137c3a
--- /dev/null
+++ b/indra/llui/llscrolllistitem.h
@@ -0,0 +1,129 @@
+/** 
+ * @file llscrolllistitem.h
+ * @brief Scroll lists are composed of rows (items), each of which 
+ * contains columns (cells).
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSCROLLLISTITEM_H
+#define LLSCROLLLISTITEM_H
+
+#include "llfontgl.h"		// LLFontGL::HAlign
+#include "llpointer.h"		// LLPointer<>
+#include "llsd.h"
+#include "lluistring.h"
+#include "v4color.h"
+#include "llinitparam.h"
+#include "llscrolllistcell.h"
+
+#include <vector>
+
+class LLCoordGL;
+class LLCheckBoxCtrl;
+class LLResizeBar;
+class LLScrollListCtrl;
+class LLScrollColumnHeader;
+class LLUIImage;
+
+//---------------------------------------------------------------------------
+// LLScrollListItem
+//---------------------------------------------------------------------------
+class LLScrollListItem
+{
+	friend class LLScrollListCtrl;
+public:
+	struct Params : public LLInitParam::Block<Params>
+	{
+		Optional<bool>		enabled;
+		Optional<void*>		userdata;
+		Optional<LLSD>		value;
+		
+		Deprecated			name; // use for localization tools
+		Deprecated			type; 
+		Deprecated			length; 
+
+		Multiple<LLScrollListCell::Params> cells;
+
+		Params()
+		:	enabled("enabled", true),
+			value("value"),
+			name("name"),
+			type("type"),
+			length("length"),
+			cells("columns")
+		{
+			addSynonym(cells, "column");
+			addSynonym(value, "id");
+		}
+	};
+
+	virtual ~LLScrollListItem();
+
+	void	setSelected( BOOL b )			{ mSelected = b; }
+	BOOL	getSelected() const				{ return mSelected; }
+
+	void	setEnabled( BOOL b )			{ mEnabled = b; }
+	BOOL	getEnabled() const 				{ return mEnabled; }
+
+	void	setHighlighted( BOOL b )		{ mHighlighted = b; }
+	BOOL	getHighlighted() const			{ return mHighlighted; }
+
+	void	setUserdata( void* userdata )	{ mUserdata = userdata; }
+	void*	getUserdata() const 			{ return mUserdata; }
+
+	LLUUID	getUUID() const					{ return mItemValue.asUUID(); }
+	LLSD	getValue() const				{ return mItemValue; }
+
+	void	addColumn( const LLScrollListCell::Params& p );
+
+	void	setNumColumns(S32 columns);
+
+	void	setColumn( S32 column, LLScrollListCell *cell );
+	
+	S32		getNumColumns() const;
+
+	LLScrollListCell *getColumn(const S32 i) const;
+
+	std::string getContentsCSV() const;
+
+	virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding);
+
+protected:
+	LLScrollListItem( const Params& );
+
+private:
+	BOOL	mSelected;
+	BOOL	mHighlighted;
+	BOOL	mEnabled;
+	void*	mUserdata;
+	LLSD	mItemValue;
+	std::vector<LLScrollListCell *> mColumns;
+};
+
+#endif
diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp
new file mode 100644
index 0000000000..1b0f3c9885
--- /dev/null
+++ b/indra/llui/llsdparam.cpp
@@ -0,0 +1,158 @@
+/** 
+ * @file llsdparam.cpp
+ * @brief parameter block abstraction for creating complex objects and 
+ * parsing construction parameters from xml and LLSD
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+// Project includes
+#include "llsdparam.h"
+
+//
+// LLParamSDParser
+//
+LLParamSDParser::LLParamSDParser()
+{
+	using boost::bind;
+
+	registerParserFuncs<S32>(bind(&LLParamSDParser::readTypedValue<S32>, this, _1, &LLSD::asInteger),
+							bind(&LLParamSDParser::writeTypedValue<S32>, this, _1, _2));
+	registerParserFuncs<U32>(bind(&LLParamSDParser::readTypedValue<U32>, this, _1, &LLSD::asInteger),
+							bind(&LLParamSDParser::writeU32Param, this, _1, _2));
+	registerParserFuncs<F32>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asReal),
+							bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2));
+	registerParserFuncs<F64>(bind(&LLParamSDParser::readTypedValue<F64>, this, _1, &LLSD::asReal),
+							bind(&LLParamSDParser::writeTypedValue<F64>, this, _1, _2));
+	registerParserFuncs<bool>(bind(&LLParamSDParser::readTypedValue<F32>, this, _1, &LLSD::asBoolean),
+							bind(&LLParamSDParser::writeTypedValue<F32>, this, _1, _2));
+	registerParserFuncs<std::string>(bind(&LLParamSDParser::readTypedValue<std::string>, this, _1, &LLSD::asString),
+							bind(&LLParamSDParser::writeTypedValue<std::string>, this, _1, _2));
+	registerParserFuncs<LLUUID>(bind(&LLParamSDParser::readTypedValue<LLUUID>, this, _1, &LLSD::asUUID),
+							bind(&LLParamSDParser::writeTypedValue<LLUUID>, this, _1, _2));
+	registerParserFuncs<LLDate>(bind(&LLParamSDParser::readTypedValue<LLDate>, this, _1, &LLSD::asDate),
+							bind(&LLParamSDParser::writeTypedValue<LLDate>, this, _1, _2));
+	registerParserFuncs<LLURI>(bind(&LLParamSDParser::readTypedValue<LLURI>, this, _1, &LLSD::asURI),
+							bind(&LLParamSDParser::writeTypedValue<LLURI>, this, _1, _2));
+	registerParserFuncs<LLSD>(bind(&LLParamSDParser::readSDParam, this, _1),
+							bind(&LLParamSDParser::writeTypedValue<LLSD>, this, _1, _2));
+}
+
+bool LLParamSDParser::readSDParam(void* value_ptr)
+{
+	if (!mCurReadSD) return false;
+	*((LLSD*)value_ptr) = *mCurReadSD;
+	return true;
+}
+
+// special case handling of U32 due to ambiguous LLSD::assign overload
+bool LLParamSDParser::writeU32Param(const void* val_ptr, const parser_t::name_stack_t& name_stack)
+{
+	if (!mWriteSD) return false;
+	
+	LLSD* sd_to_write = getSDWriteNode(name_stack);
+	if (!sd_to_write) return false;
+
+	sd_to_write->assign((S32)*((const U32*)val_ptr));
+	return true;
+}
+
+void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent)
+{
+	mCurReadSD = NULL;
+	mNameStack.clear();
+	setParseSilently(silent);
+
+	// must have named elements at top level to submit for parsing
+	if (sd.isMap())
+	{
+		readSDValues(sd, block);
+	}
+	else
+	{
+		parserWarning("Top level map required for LLSD->Block conversion");
+	}
+}
+
+void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
+{
+	mWriteSD = &sd;
+	block.serializeBlock(*this);
+}
+
+void LLParamSDParser::readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block)
+{
+	if (sd.isMap())
+	{
+		for (LLSD::map_const_iterator it = sd.beginMap();
+			it != sd.endMap();
+			++it)
+		{
+			mNameStack.push_back(make_pair(it->first, newParseGeneration()));
+			readSDValues(it->second, block);
+			mNameStack.pop_back();
+		}
+	}
+	else if (sd.isArray())
+	{
+		for (LLSD::array_const_iterator it = sd.beginArray();
+			it != sd.endArray();
+			++it)
+		{
+			mNameStack.back().second = newParseGeneration();
+			readSDValues(*it, block);
+		}
+	}
+	else
+	{
+		mCurReadSD = &sd;
+		block.submitValue(mNameStack, *this);
+	}
+}
+
+/*virtual*/ std::string LLParamSDParser::getCurrentElementName()
+{
+	std::string full_name = "sd";
+	for (name_stack_t::iterator it = mNameStack.begin();	
+		it != mNameStack.end();
+		++it)
+	{
+		full_name += llformat("[%s]", it->first.c_str());
+	}
+
+	return full_name;
+}
+
+LLSD* LLParamSDParser::getSDWriteNode(const parser_t::name_stack_t& name_stack)
+{
+	//TODO: implement nested LLSD writing
+	return mWriteSD;
+}
+
diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h
new file mode 100644
index 0000000000..12f28f876f
--- /dev/null
+++ b/indra/llui/llsdparam.h
@@ -0,0 +1,107 @@
+/** 
+ * @file llsdparam.h
+ * @brief parameter block abstraction for creating complex objects and 
+ * parsing construction parameters from xml and LLSD
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSDPARAM_H
+#define LL_LLSDPARAM_H
+
+#include "llinitparam.h"
+
+class LLParamSDParser 
+:	public LLInitParam::Parser, 
+	public LLSingleton<LLParamSDParser>
+{
+LOG_CLASS(LLParamSDParser);
+
+typedef LLInitParam::Parser parser_t;
+
+protected:
+	LLParamSDParser();
+	friend class LLSingleton<LLParamSDParser>;
+public:
+	void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);
+	void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block);
+
+	/*virtual*/ std::string getCurrentElementName();
+
+private:
+	void readSDValues(const LLSD& sd, LLInitParam::BaseBlock& block);
+
+	template<typename T>
+	bool readTypedValue(void* val_ptr, boost::function<T(const LLSD&)> parser_func)
+    {
+	    if (!mCurReadSD) return false;
+
+	    *((T*)val_ptr) = parser_func(*mCurReadSD);
+	    return true;
+    }
+
+	template<typename T>
+	bool writeTypedValue(const void* val_ptr, const parser_t::name_stack_t& name_stack)
+	{
+		if (!mWriteSD) return false;
+		
+		LLSD* sd_to_write = getSDWriteNode(name_stack);
+		if (!sd_to_write) return false;
+
+		sd_to_write->assign(*((const T*)val_ptr));
+		return true;
+	}
+
+	LLSD* getSDWriteNode(const parser_t::name_stack_t& name_stack);
+
+	bool readSDParam(void* value_ptr);
+	bool writeU32Param(const void* value_ptr, const parser_t::name_stack_t& name_stack);
+
+	Parser::name_stack_t	mNameStack;
+	const LLSD*				mCurReadSD;
+	LLSD*					mWriteSD;
+};
+
+template<typename T>
+class LLSDParamAdapter : public T
+	{
+	public:
+		LLSDParamAdapter() {}
+		LLSDParamAdapter(const LLSD& sd)
+		{
+			LLParamSDParser::instance().readSD(sd, *this);
+		}
+		
+		LLSDParamAdapter(const T& val)
+		{
+			T::operator=(val);
+		}
+	};
+
+#endif // LL_LLSDPARAM_H
+
diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp
new file mode 100644
index 0000000000..62b204fd56
--- /dev/null
+++ b/indra/llui/llsearcheditor.cpp
@@ -0,0 +1,124 @@
+/** 
+ * @file lllineeditor.cpp
+ * @brief LLLineEditor base class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Text editor widget to let users enter a single line.
+
+#include "linden_common.h"
+ 
+#include "llsearcheditor.h"
+
+static LLRegisterWidget<LLSearchEditor> r2("search_editor");
+
+LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p)
+:	LLUICtrl(p)
+{
+	LLLineEditor::Params line_editor_p(p);
+	line_editor_p.name("search edit box");
+	line_editor_p.rect(getLocalRect());
+	line_editor_p.follows.flags(FOLLOWS_ALL);
+	line_editor_p.text_pad_right(getRect().getHeight());
+	line_editor_p.keystroke_callback(boost::bind(&LLSearchEditor::onSearchEdit, this, _1));
+
+	mSearchEdit = LLUICtrlFactory::create<LLLineEditor>(line_editor_p);
+	addChild(mSearchEdit);
+
+	S32 btn_width = getRect().getHeight(); // button is square, and as tall as search editor
+	LLRect clear_btn_rect(getRect().getWidth() - btn_width, getRect().getHeight(), getRect().getWidth(), 0);
+	LLButton::Params button_params(p.clear_search_button);
+	button_params.name(std::string("clear search"));
+	button_params.rect(clear_btn_rect) ;
+	button_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP);
+	button_params.tab_stop(false);
+	button_params.click_callback.function(boost::bind(&LLSearchEditor::onClearSearch, this, _2));
+
+	mClearSearchButton = LLUICtrlFactory::create<LLButton>(button_params);
+	mSearchEdit->addChild(mClearSearchButton);
+}
+
+//virtual
+void LLSearchEditor::setValue(const LLSD& value )
+{
+	mSearchEdit->setValue(value);
+}
+
+//virtual
+LLSD LLSearchEditor::getValue() const
+{
+	return mSearchEdit->getValue();
+}
+
+//virtual
+BOOL LLSearchEditor::setTextArg( const std::string& key, const LLStringExplicit& text )
+{
+	return mSearchEdit->setTextArg(key, text);
+}
+
+//virtual
+BOOL LLSearchEditor::setLabelArg( const std::string& key, const LLStringExplicit& text )
+{
+	return mSearchEdit->setLabelArg(key, text);
+}
+
+//virtual
+void LLSearchEditor::clear()
+{
+	if (mSearchEdit)
+	{
+		mSearchEdit->clear();
+	}
+}
+
+void LLSearchEditor::draw()
+{
+	mClearSearchButton->setVisible(!mSearchEdit->getWText().empty());
+
+	LLUICtrl::draw();
+}
+
+
+void LLSearchEditor::onSearchEdit(LLLineEditor* caller )
+{
+	if (mSearchCallback)
+	{
+		mSearchCallback(caller->getText());
+	}
+}
+
+void LLSearchEditor::onClearSearch(const LLSD& data)
+{
+	setText(LLStringUtil::null);
+	if (mSearchCallback)
+	{
+		mSearchCallback(LLStringUtil::null);
+	}
+}
+
diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h
new file mode 100644
index 0000000000..d8c5093fbf
--- /dev/null
+++ b/indra/llui/llsearcheditor.h
@@ -0,0 +1,98 @@
+/** 
+ * @file llsearcheditor.h
+ * @brief Text editor widget that represents a search operation
+ *
+ * Features: 
+ *		Text entry of a single line (text, delete, left and right arrow, insert, return).
+ *		Callbacks either on every keystroke or just on the return key.
+ *		Focus (allow multiple text entry widgets)
+ *		Clipboard (cut, copy, and paste)
+ *		Horizontal scrolling to allow strings longer than widget size allows 
+ *		Pre-validation (limit which keys can be used)
+ *		Optional line history so previous entries can be recalled by CTRL UP/DOWN
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSEARCHEDITOR_H
+#define LL_LLSEARCHEDITOR_H
+
+#include "lllineeditor.h"
+#include "llbutton.h"
+
+#include <boost/function.hpp>
+
+/*
+ * @brief A line editor with a button to clear it and a callback to call on every edit event.
+ */
+class LLSearchEditor : public LLUICtrl
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLLineEditor::Params>
+	{
+		Optional<boost::function<void(const std::string&, void*)> > search_callback;
+		
+		Optional<LLButton::Params> clear_search_button;
+
+		Params()
+		: clear_search_button("clear_search_button")
+		{
+			name = "search_editor";
+		}
+	};
+
+protected:
+	LLSearchEditor(const Params&);
+	friend class LLUICtrlFactory;
+public:
+	virtual ~LLSearchEditor() {}
+
+	/*virtual*/ void	draw();
+
+	void setText(const LLStringExplicit &new_text) { mSearchEdit->setText(new_text); }
+
+	typedef boost::function<void (const std::string& search_string)> search_callback_t;
+	void setSearchCallback(search_callback_t cb) { mSearchCallback = cb; }
+
+	// LLUICtrl interface
+	virtual void	setValue(const LLSD& value );
+	virtual LLSD	getValue() const;
+	virtual BOOL	setTextArg( const std::string& key, const LLStringExplicit& text );
+	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
+	virtual void	clear();
+
+private:
+	void onSearchEdit(LLLineEditor* caller );
+	void onClearSearch(const LLSD& data);
+
+	LLLineEditor* mSearchEdit;
+	LLButton* mClearSearchButton;
+	search_callback_t mSearchCallback;
+};
+
+#endif  // LL_LLSEARCHEDITOR_H
diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp
index 4dfc904581..ff2f5d3da0 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -41,53 +41,48 @@
 #include "llkeyboard.h"			// for the MASK constants
 #include "llcontrol.h"
 #include "llimagegl.h"
+#include "lluictrlfactory.h"
 
 static LLRegisterWidget<LLSlider> r1("slider_bar");
+//FIXME: make this into an unregistered template so that code constructed sliders don't
+// have ambigious template lookup problem
 static LLRegisterWidget<LLSlider> r2("volume_slider");
 
+LLSlider::Params::Params()
+:	track_color("track_color"),
+	thumb_outline_color("thumb_outline_color"),
+	thumb_center_color("thumb_center_color"),
+	thumb_image("thumb_image"),
+	track_image("track_image"),
+	track_highlight_image("track_highlight_image"),
+	mouse_down_callback("mouse_down_callback"),
+	mouse_up_callback("mouse_up_callback")
+{
+	follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+}
 
-LLSlider::LLSlider( 
-	const std::string& name,
-	const LLRect& rect,
-	void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
-	void* callback_userdata,
-	F32 initial_value,
-	F32 min_value,
-	F32 max_value,
-	F32 increment,
-	BOOL volume,
-	const std::string& control_name)
-	:
-	LLUICtrl( name, rect, TRUE,	on_commit_callback, callback_userdata, 
-		FOLLOWS_LEFT | FOLLOWS_TOP),
-	mValue( initial_value ),
-	mInitialValue( initial_value ),
-	mMinValue( min_value ),
-	mMaxValue( max_value ),
-	mIncrement( increment ),
-	mVolumeSlider( volume ),
+LLSlider::LLSlider(const LLSlider::Params& p)
+:	LLF32UICtrl(p),
 	mMouseOffset( 0 ),
-	mTrackColor(		LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ),
-	mThumbOutlineColor(	LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ),
-	mThumbCenterColor(	LLUI::sColorsGroup->getColor( "SliderThumbCenterColor" ) ),
-	mMouseDownCallback( NULL ),
-	mMouseUpCallback( NULL )
+	mTrackColor(p.track_color()),
+	mThumbOutlineColor(p.thumb_outline_color()),
+	mThumbCenterColor(p.thumb_center_color()),
+	mThumbImage(p.thumb_image),
+	mTrackImage(p.track_image),
+	mTrackHighlightImage(p.track_highlight_image)
 {
-	mThumbImage = LLUI::sImageProvider->getUIImage("icn_slide-thumb_dark.tga");
-	mTrackImage = LLUI::sImageProvider->getUIImage("icn_slide-groove_dark.tga");
-	mTrackHighlightImage = LLUI::sImageProvider->getUIImage("icn_slide-highlight.tga");
-
-	// properly handle setting the starting thumb rect
-	// do it this way to handle both the operating-on-settings
-	// and standalone ways of using this
-	setControlName(control_name, NULL);
-	setValue(getValueF32());
-
+    mViewModel->setValue(p.initial_value);
 	updateThumbRect();
 	mDragStartThumbRect = mThumbRect;
+	setControlName(p.control_name, NULL);
+	setValue(getValueF32());
+	
+	if (p.mouse_down_callback.isProvided())
+		initCommitCallback(p.mouse_down_callback, mMouseDownSignal);
+	if (p.mouse_up_callback.isProvided())
+		initCommitCallback(p.mouse_up_callback, mMouseUpSignal);
 }
 
-
 void LLSlider::setValue(F32 value, BOOL from_event)
 {
 	value = llclamp( value, mMinValue, mMaxValue );
@@ -98,21 +93,22 @@ void LLSlider::setValue(F32 value, BOOL from_event)
 	value -= fmod(value, mIncrement);
 	value += mMinValue;
 
-	if (!from_event && mValue != value)
+	if (!from_event && getValueF32() != value)
 	{
 		setControlValue(value);
 	}
 
-	mValue = value;
+    LLF32UICtrl::setValue(value);
 	updateThumbRect();
 }
 
 void LLSlider::updateThumbRect()
 {
-	F32 t = (mValue - mMinValue) / (mMaxValue - mMinValue);
+	const S32 DEFAULT_THUMB_SIZE = 16;
+	F32 t = (getValueF32() - mMinValue) / (mMaxValue - mMinValue);
 
-	S32 thumb_width = mThumbImage->getWidth();
-	S32 thumb_height = mThumbImage->getHeight();
+	S32 thumb_width = mThumbImage ? mThumbImage->getWidth() : DEFAULT_THUMB_SIZE;
+	S32 thumb_height = mThumbImage ? mThumbImage->getHeight() : DEFAULT_THUMB_SIZE;
 	S32 left_edge = (thumb_width / 2);
 	S32 right_edge = getRect().getWidth() - (thumb_width / 2);
 
@@ -126,10 +122,10 @@ void LLSlider::updateThumbRect()
 
 void LLSlider::setValueAndCommit(F32 value)
 {
-	F32 old_value = mValue;
+	F32 old_value = getValueF32();
 	setValue(value);
 
-	if (mValue != old_value)
+	if (getValueF32() != old_value)
 	{
 		onCommit();
 	}
@@ -169,10 +165,8 @@ BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask)
 	{
 		gFocusMgr.setMouseCapture( NULL );
 
-		if( mMouseUpCallback )
-		{
-			mMouseUpCallback( this, mCallbackUserData );
-		}
+		mMouseUpSignal( this, getValueF32() );
+
 		handled = TRUE;
 		make_ui_sound("UISndClickRelease");
 	}
@@ -191,10 +185,7 @@ BOOL LLSlider::handleMouseDown(S32 x, S32 y, MASK mask)
 	{
 		setFocus(TRUE);
 	}
-	if( mMouseDownCallback )
-	{
-		mMouseDownCallback( this, mCallbackUserData );
-	}
+	mMouseDownSignal( this, getValueF32() );
 
 	if (MASK_CONTROL & mask) // if CTRL is modifying
 	{
@@ -257,8 +248,8 @@ void LLSlider::draw()
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
 	F32 opacity = getEnabled() ? 1.f : 0.3f;
-	LLColor4 center_color = (mThumbCenterColor % opacity);
-	LLColor4 track_color = (mTrackColor % opacity);
+	LLColor4 center_color = (mThumbCenterColor.get() % opacity);
+	LLColor4 track_color = (mTrackColor.get() % opacity);
 
 	// Track
 	LLRect track_rect(mThumbImage->getWidth() / 2, 
@@ -273,7 +264,7 @@ void LLSlider::draw()
 	if( hasMouseCapture() )
 	{
 		// Show ghost where thumb was before dragging began.
-		mThumbImage->draw(mDragStartThumbRect, mThumbCenterColor % 0.3f);
+		mThumbImage->draw(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f);
 	}
 	if (hasFocus())
 	{
@@ -281,61 +272,7 @@ void LLSlider::draw()
 		mThumbImage->drawBorder(mThumbRect, gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth());
 	}
 	// Fill in the thumb.
-	mThumbImage->draw(mThumbRect, hasMouseCapture() ? mThumbOutlineColor : center_color);
+	mThumbImage->draw(mThumbRect, hasMouseCapture() ? mThumbOutlineColor.get() : center_color);
 
 	LLUICtrl::draw();
 }
-
-// virtual
-LLXMLNodePtr LLSlider::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue());
-	node->createChild("min_val", TRUE)->setFloatValue(getMinValue());
-	node->createChild("max_val", TRUE)->setFloatValue(getMaxValue());
-	node->createChild("increment", TRUE)->setFloatValue(getIncrement());
-	node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider);
-
-	return node;
-}
-
-
-//static
-LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory)
-{
-	std::string name("slider_bar");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	F32 initial_value = 0.f;
-	node->getAttributeF32("initial_val", initial_value);
-
-	F32 min_value = 0.f;
-	node->getAttributeF32("min_val", min_value);
-
-	F32 max_value = 1.f; 
-	node->getAttributeF32("max_val", max_value);
-
-	F32 increment = 0.1f;
-	node->getAttributeF32("increment", increment);
-
-	BOOL volume = node->hasName("volume_slider") ? TRUE : FALSE;
-	node->getAttributeBOOL("volume", volume);
-
-	LLSlider* slider = new LLSlider(name,
-							rect,
-							NULL,
-							NULL,
-							initial_value,
-							min_value,
-							max_value,
-							increment,
-							volume);
-
-	slider->initFromXML(node, parent);
-
-	return slider;
-}
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 154685fac1..39c55afd8c 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -33,47 +33,42 @@
 #ifndef LL_LLSLIDER_H
 #define LL_LLSLIDER_H
 
-#include "lluictrl.h"
+#include "llf32uictrl.h"
 #include "v4color.h"
 
 class LLImageGL;
 
-class LLSlider : public LLUICtrl
+class LLSlider : public LLF32UICtrl
 {
 public:
-	LLSlider( 
-		const std::string& name,
-		const LLRect& rect,
-		void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata),
-		void* callback_userdata,
-		F32 initial_value,
-		F32 min_value,
-		F32 max_value,
-		F32 increment,
-		BOOL volume, //TODO: create a "volume" slider sub-class or just use image art, no?  -MG
-		const std::string& control_name = LLStringUtil::null );
+	struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
+	{
+		Optional<LLUIColor>	track_color,
+							thumb_outline_color,
+							thumb_center_color;
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static  LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
+		Optional<LLUIImage*>	thumb_image,
+								track_image,
+								track_highlight_image;
 
-	void			setValue( F32 value, BOOL from_event = FALSE );
-	F32				getValueF32() const { return mValue; }
+		Optional<CommitCallbackParam>	mouse_down_callback,
+										mouse_up_callback;
 
-	virtual void	setValue(const LLSD& value )	{ setValue((F32)value.asReal(), TRUE); }
-	virtual LLSD	getValue() const		{ return LLSD(getValueF32()); }
 
-	virtual void	setMinValue(LLSD min_value)	{ setMinValue((F32)min_value.asReal()); }
-	virtual void	setMaxValue(LLSD max_value)	{ setMaxValue((F32)max_value.asReal());  }
+		Params();
+	};
+protected:
+	LLSlider(const Params&);
+	friend class LLUICtrlFactory;
+public:
+	void			setValue( F32 value, BOOL from_event = FALSE );
+    // overrides for LLF32UICtrl methods
+	virtual void	setValue(const LLSD& value )	{ setValue((F32)value.asReal(), TRUE); }
+	virtual void	setMinValue(F32 min_value) { LLF32UICtrl::setMinValue(min_value); updateThumbRect(); }
+	virtual void	setMaxValue(F32 max_value) { LLF32UICtrl::setMaxValue(max_value); updateThumbRect(); }
 
-	F32				getInitialValue() const { return mInitialValue; }
-	F32				getMinValue() const		{ return mMinValue; }
-	F32				getMaxValue() const		{ return mMaxValue; }
-	F32				getIncrement() const	{ return mIncrement; }
-	void			setMinValue(F32 min_value) {mMinValue = min_value; updateThumbRect(); }
-	void			setMaxValue(F32 max_value) {mMaxValue = max_value; updateThumbRect(); }
-	void			setIncrement(F32 increment) {mIncrement = increment;}
-	void			setMouseDownCallback( void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseDownCallback = cb; }
-	void			setMouseUpCallback(	void (*cb)(LLUICtrl* ctrl, void* userdata) ) { mMouseUpCallback = cb; }
+	boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ) { return mMouseDownSignal.connect(cb); }
+	boost::signals::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb )   { return mMouseUpSignal.connect(cb); }
 
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
@@ -85,12 +80,6 @@ private:
 	void			setValueAndCommit(F32 value);
 	void			updateThumbRect();
 
-	F32				mValue;
-	F32				mInitialValue;
-	F32				mMinValue;
-	F32				mMaxValue;
-	F32				mIncrement;
-
 	BOOL			mVolumeSlider;
 	S32				mMouseOffset;
 	LLRect			mDragStartThumbRect;
@@ -100,12 +89,12 @@ private:
 	LLUIImage*		mTrackHighlightImage;
 
 	LLRect			mThumbRect;
-	LLColor4		mTrackColor;
-	LLColor4		mThumbOutlineColor;
-	LLColor4		mThumbCenterColor;
+	LLUIColor	mTrackColor;
+	LLUIColor	mThumbOutlineColor;
+	LLUIColor	mThumbCenterColor;
 	
-	void			(*mMouseDownCallback)(LLUICtrl* ctrl, void* userdata);
-	void			(*mMouseUpCallback)(LLUICtrl* ctrl, void* userdata);
+	commit_signal_t	mMouseDownSignal;
+	commit_signal_t	mMouseUpSignal;
 };
 
 #endif  // LL_LLSLIDER_H
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index 31baddd7cc..d5053478a6 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -49,84 +49,103 @@
 #include "llcontrol.h"
 #include "llfocusmgr.h"
 #include "llresmgr.h"
+#include "lluictrlfactory.h"
 
 const U32 MAX_STRING_LENGTH = 10;
 
 static LLRegisterWidget<LLSliderCtrl> r("slider");
- 
-LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, 
-						   const std::string& label,
-						   const LLFontGL* font,
-						   S32 label_width,
-						   S32 text_left,
-						   BOOL show_text,
-						   BOOL can_edit_text,
-						   BOOL volume,
-						   void (*commit_callback)(LLUICtrl*, void*),
-						   void* callback_user_data,
-						   F32 initial_value, F32 min_value, F32 max_value, F32 increment,
-						   const std::string& control_which)
-	: LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data ),
-	  mFont(font),
-	  mShowText( show_text ),
-	  mCanEditText( can_edit_text ),
-	  mVolumeSlider( volume ),
-	  mPrecision( 3 ),
-	  mLabelBox( NULL ),
-	  mLabelWidth( label_width ),
-	  mValue( initial_value ),
-	  mEditor( NULL ),
-	  mTextBox( NULL ),
-	  mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
-	  mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
-	  mSliderMouseUpCallback( NULL ),
-	  mSliderMouseDownCallback( NULL )
+
+LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
+:	LLF32UICtrl(p),
+	mLabelBox( NULL ),
+	mEditor( NULL ),
+	mTextBox( NULL ),
+	mFont(p.font),
+	mShowText(p.show_text),
+	mCanEditText(p.can_edit_text),
+	mPrecision(p.decimal_digits),
+	mTextEnabledColor(p.text_color()),
+	mTextDisabledColor(p.text_disabled_color())
 {
 	S32 top = getRect().getHeight();
 	S32 bottom = 0;
 	S32 left = 0;
 
+	S32 label_width = p.label_width;
+	S32 text_width = p.text_width;
+
 	// Label
-	if( !label.empty() )
+	if( !p.label().empty() )
 	{
-		if (label_width == 0)
+		if (!p.label_width.isProvided())
 		{
-			label_width = font->getWidth(label);
+			label_width = p.font()->getWidth(p.label);
 		}
 		LLRect label_rect( left, top, label_width, bottom );
-		mLabelBox = new LLTextBox( std::string("SliderCtrl Label"), label_rect, label, font );
+		LLTextBox::Params params(p.slider_label);
+		params.rect.setIfNotProvided(label_rect);
+		params.font.setIfNotProvided(p.font);
+		params.text(p.label);
+		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild(mLabelBox);
 	}
 
+	if (p.show_text && !p.text_width.isProvided())
+	{
+		// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
+		if ( p.max_value )
+			text_width = p.font()->getWidth(std::string("0")) * ( static_cast < S32 > ( log10  ( p.max_value ) ) + p.decimal_digits + 1 );
+
+		if ( p.increment < 1.0f )
+			text_width += p.font()->getWidth(std::string("."));	// (mostly) take account of decimal point in value
+
+		if ( p.min_value < 0.0f || p.max_value < 0.0f )
+			text_width += p.font()->getWidth(std::string("-"));	// (mostly) take account of minus sign 
+
+		// padding to make things look nicer
+		text_width += 8;
+	}
+
+
+	S32 text_left = getRect().getWidth() - text_width;
+	static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0);
+
 	S32 slider_right = getRect().getWidth();
-	if( show_text )
+	if( p.show_text )
 	{
-		slider_right = text_left - SLIDERCTRL_SPACING;
+		slider_right = text_left - sliderctrl_spacing;
 	}
 
-	S32 slider_left = label_width ? label_width + SLIDERCTRL_SPACING : 0;
-	LLRect slider_rect( slider_left, top, slider_right, bottom );
-	mSlider = new LLSlider(std::string("slider"),
-						   slider_rect, 
-						   LLSliderCtrl::onSliderCommit, this, 
-						   initial_value, min_value, max_value, increment, volume,
-						   control_which );
+	S32 slider_left = label_width ? label_width + sliderctrl_spacing : 0;
+	LLSlider::Params slider_p(p.slider_bar);
+	slider_p.name("slider_bar");
+	slider_p.rect.setIfNotProvided(LLRect(slider_left,top,slider_right,bottom));
+	slider_p.initial_value.setIfNotProvided(p.initial_value().asReal());
+	slider_p.min_value.setIfNotProvided(p.min_value);
+	slider_p.max_value.setIfNotProvided(p.max_value);
+	slider_p.increment.setIfNotProvided(p.increment);
+
+	slider_p.commit_callback.function(&LLSliderCtrl::onSliderCommit);
+	slider_p.control_name(p.control_name);
+	slider_p.mouse_down_callback( p.mouse_down_callback );
+	slider_p.mouse_up_callback( p.mouse_up_callback );
+	mSlider = LLUICtrlFactory::create<LLSlider> (slider_p);
+
 	addChild( mSlider );
 	
-	if( show_text )
+	if( p.show_text() )
 	{
 		LLRect text_rect( text_left, top, getRect().getWidth(), bottom );
-		if( can_edit_text )
+		if( p.can_edit_text() )
 		{
-			mEditor = new LLLineEditor( std::string("SliderCtrl Editor"), text_rect,
-										LLStringUtil::null, font,
-										MAX_STRING_LENGTH,
-										&LLSliderCtrl::onEditorCommit, NULL, NULL, this,
-										&LLLineEditor::prevalidateFloat );
-			mEditor->setFollowsLeft();
-			mEditor->setFollowsBottom();
+			LLLineEditor::Params line_p(p.value_editor);
+			line_p.rect.setIfNotProvided(text_rect);
+			line_p.font.setIfNotProvided(p.font);
+			line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit);
+			line_p.prevalidate_callback(&LLLineEditor::prevalidateFloat);
+			mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p);
+
 			mEditor->setFocusReceivedCallback( &LLSliderCtrl::onEditorGainFocus, this );
-			mEditor->setIgnoreTab(TRUE);
 			// don't do this, as selecting the entire text is single clicking in some cases
 			// and double clicking in others
 			//mEditor->setSelectAllonFocusReceived(TRUE);
@@ -134,9 +153,10 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect,
 		}
 		else
 		{
-			mTextBox = new LLTextBox( std::string("SliderCtrl Text"), text_rect,	LLStringUtil::null,	font);
-			mTextBox->setFollowsLeft();
-			mTextBox->setFollowsBottom();
+			LLTextBox::Params text_p(p.value_text);
+			text_p.rect.setIfNotProvided(text_rect);
+			text_p.font.setIfNotProvided(p.font);
+			mTextBox = LLUICtrlFactory::create<LLTextBox>(text_p);
 			addChild(mTextBox);
 		}
 	}
@@ -144,7 +164,6 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect,
 	updateText();
 }
 
-
 // static
 void LLSliderCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
 {
@@ -179,7 +198,8 @@ BOOL LLSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit&
 			S32 delta = rect.mRight - prev_right;
 			rect = mSlider->getRect();
 			S32 left = rect.mLeft + delta;
-			left = llclamp(left, 0, rect.mRight-SLIDERCTRL_SPACING);
+			static LLUICachedControl<S32> sliderctrl_spacing ("UISliderctrlSpacing", 0);
+			left = llclamp(left, 0, rect.mRight - sliderctrl_spacing);
 			rect.mLeft = left;
 			mSlider->setRect(rect);
 		}
@@ -224,10 +244,11 @@ void LLSliderCtrl::updateText()
 }
 
 // static
-void LLSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
+void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata )
 {
-	LLSliderCtrl* self = (LLSliderCtrl*) userdata;
-	llassert( caller == self->mEditor );
+	LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent());
+	if (!self)
+		return;
 
 	BOOL success = FALSE;
 	F32 val = self->mValue;
@@ -240,17 +261,9 @@ void LLSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
 		val = (F32) atof( text.c_str() );
 		if( self->mSlider->getMinValue() <= val && val <= self->mSlider->getMaxValue() )
 		{
-			if( self->mValidateCallback )
+			self->setValue( val );  // set the value temporarily so that the callback can retrieve it.
+			if( self->mValidateSignal( self, val ) )
 			{
-				self->setValue( val );  // set the value temporarily so that the callback can retrieve it.
-				if( self->mValidateCallback( self, self->mCallbackUserData ) )
-				{
-					success = TRUE;
-				}
-			}
-			else
-			{
-				self->setValue( val );
 				success = TRUE;
 			}
 		}
@@ -272,26 +285,19 @@ void LLSliderCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
 }
 
 // static
-void LLSliderCtrl::onSliderCommit( LLUICtrl* caller, void *userdata )
+void LLSliderCtrl::onSliderCommit( LLUICtrl* ctrl, const LLSD& userdata )
 {
-	LLSliderCtrl* self = (LLSliderCtrl*) userdata;
-	llassert( caller == self->mSlider );
+	LLSliderCtrl* self = dynamic_cast<LLSliderCtrl*>(ctrl->getParent());
+	if (!self)
+		return;
 
 	BOOL success = FALSE;
 	F32 saved_val = self->mValue;
 	F32 new_val = self->mSlider->getValueF32();
 
-	if( self->mValidateCallback )
+	self->mValue = new_val;  // set the value temporarily so that the callback can retrieve it.
+	if( self->mValidateSignal( self, new_val ) )
 	{
-		self->mValue = new_val;  // set the value temporarily so that the callback can retrieve it.
-		if( self->mValidateCallback( self, self->mCallbackUserData ) )
-		{
-			success = TRUE;
-		}
-	}
-	else
-	{
-		self->mValue = new_val;
 		success = TRUE;
 	}
 
@@ -316,7 +322,7 @@ void LLSliderCtrl::setEnabled(BOOL b)
 
 	if( mLabelBox )
 	{
-		mLabelBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
+		mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
 	}
 
 	mSlider->setEnabled( b );
@@ -328,7 +334,7 @@ void LLSliderCtrl::setEnabled(BOOL b)
 
 	if( mTextBox )
 	{
-		mTextBox->setColor( b ? mTextEnabledColor : mTextDisabledColor );
+		mTextBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
 	}
 }
 
@@ -339,7 +345,7 @@ void LLSliderCtrl::setTentative(BOOL b)
 	{
 		mEditor->setTentative(b);
 	}
-	LLUICtrl::setTentative(b);
+	LLF32UICtrl::setTentative(b);
 }
 
 
@@ -351,8 +357,9 @@ void LLSliderCtrl::onCommit()
 	{
 		mEditor->setTentative(FALSE);
 	}
-
-	LLUICtrl::onCommit();
+	
+	setControlValue(getValueF32());
+	LLF32UICtrl::onCommit();
 }
 
 
@@ -368,37 +375,14 @@ void LLSliderCtrl::setPrecision(S32 precision)
 	updateText();
 }
 
-void LLSliderCtrl::setSliderMouseDownCallback( void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) )
-{
-	mSliderMouseDownCallback = slider_mousedown_callback;
-	mSlider->setMouseDownCallback( LLSliderCtrl::onSliderMouseDown );
-}
-
-// static
-void LLSliderCtrl::onSliderMouseDown(LLUICtrl* caller, void* userdata)
-{
-	LLSliderCtrl* self = (LLSliderCtrl*) userdata;
-	if( self->mSliderMouseDownCallback )
-	{
-		self->mSliderMouseDownCallback( self, self->mCallbackUserData );
-	}
-}
-
-
-void LLSliderCtrl::setSliderMouseUpCallback( void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) )
+boost::signals::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
 {
-	mSliderMouseUpCallback = slider_mouseup_callback;
-	mSlider->setMouseUpCallback( LLSliderCtrl::onSliderMouseUp );
+	return mSlider->setMouseDownCallback( cb );
 }
 
-// static
-void LLSliderCtrl::onSliderMouseUp(LLUICtrl* caller, void* userdata)
+boost::signals::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
 {
-	LLSliderCtrl* self = (LLSliderCtrl*) userdata;
-	if( self->mSliderMouseUpCallback )
-	{
-		self->mSliderMouseUpCallback( self, self->mCallbackUserData );
-	}
+	return mSlider->setMouseUpCallback( cb );
 }
 
 void LLSliderCtrl::onTabInto()
@@ -414,131 +398,4 @@ void LLSliderCtrl::reportInvalidData()
 	make_ui_sound("UISndBadKeystroke");
 }
 
-// virtual
-LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("show_text", TRUE)->setBoolValue(mShowText);
-
-	node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText);
-
-	node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider);
-	
-	node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
-
-	if (mLabelBox)
-	{
-		node->createChild("label", TRUE)->setStringValue(mLabelBox->getText());
-	}
-
-	// TomY TODO: Do we really want to export the transient state of the slider?
-	node->createChild("value", TRUE)->setFloatValue(mValue);
-
-	if (mSlider)
-	{
-		node->createChild("initial_val", TRUE)->setFloatValue(mSlider->getInitialValue());
-		node->createChild("min_val", TRUE)->setFloatValue(mSlider->getMinValue());
-		node->createChild("max_val", TRUE)->setFloatValue(mSlider->getMaxValue());
-		node->createChild("increment", TRUE)->setFloatValue(mSlider->getIncrement());
-	}
-	addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
-	addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
-
-	return node;
-}
-
-LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("slider");
-	node->getAttributeString("name", name);
-
-	std::string label;
-	node->getAttributeString("label", label);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	LLFontGL* font = LLView::selectFont(node);
-
-	// HACK: Font might not be specified.
-	if (!font)
-	{
-		font = LLFontGL::getFontSansSerifSmall();
-	}
-
-	S32 label_width = 0;
-	node->getAttributeS32("label_width", label_width);
 
-	BOOL show_text = TRUE;
-	node->getAttributeBOOL("show_text", show_text);
-
-	BOOL can_edit_text = FALSE;
-	node->getAttributeBOOL("can_edit_text", can_edit_text);
-
-	BOOL volume = FALSE;
-	node->getAttributeBOOL("volume", volume);
-
-	F32 initial_value = 0.f;
-	node->getAttributeF32("initial_val", initial_value);
-
-	F32 min_value = 0.f;
-	node->getAttributeF32("min_val", min_value);
-
-	F32 max_value = 1.f; 
-	node->getAttributeF32("max_val", max_value);
-
-	F32 increment = 0.1f;
-	node->getAttributeF32("increment", increment);
-
-	U32 precision = 3;
-	node->getAttributeU32("decimal_digits", precision);
-
-	S32 text_left = 0;
-	if (show_text)
-	{
-		// calculate the size of the text box (log max_value is number of digits - 1 so plus 1)
-		if ( max_value )
-			text_left = font->getWidth(std::string("0")) * ( static_cast < S32 > ( log10  ( max_value ) ) + precision + 1 );
-
-		if ( increment < 1.0f )
-			text_left += font->getWidth(std::string("."));	// (mostly) take account of decimal point in value
-
-		if ( min_value < 0.0f || max_value < 0.0f )
-			text_left += font->getWidth(std::string("-"));	// (mostly) take account of minus sign 
-
-		// padding to make things look nicer
-		text_left += 8;
-	}
-
-	LLUICtrlCallback callback = NULL;
-
-	if (label.empty())
-	{
-		label.assign(node->getTextContents());
-	}
-
-	LLSliderCtrl* slider = new LLSliderCtrl(name,
-							rect,
-							label,
-							font,
-							label_width,
-							rect.getWidth() - text_left,
-							show_text,
-							can_edit_text,
-							volume,
-							callback,
-							NULL,
-							initial_value, 
-							min_value, 
-							max_value, 
-							increment);
-
-	slider->setPrecision(precision);
-
-	slider->initFromXML(node, parent);
-
-	slider->updateText();
-	
-	return slider;
-}
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index 272dd7ffd3..0bcb1ccc9b 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -38,54 +38,71 @@
 #include "llslider.h"
 #include "lltextbox.h"
 #include "llrect.h"
+#include "lllineeditor.h"
 
-//
-// Constants
-//
-const S32	SLIDERCTRL_SPACING		=  4;				// space between label, slider, and text
-const S32	SLIDERCTRL_HEIGHT		=  16;
 
-
-class LLSliderCtrl : public LLUICtrl
+class LLSliderCtrl : public LLF32UICtrl
 {
 public:
-	LLSliderCtrl(const std::string& name, 
-		const LLRect& rect, 
-		const std::string& label, 
-		const LLFontGL* font,
-		S32 slider_left,
-		S32 text_left,
-		BOOL show_text,
-		BOOL can_edit_text,
-		BOOL volume, //TODO: create a "volume" slider sub-class or just use image art, no?  -MG
-		void (*commit_callback)(LLUICtrl*, void*),
-		void* callback_userdata,
-		F32 initial_value, F32 min_value, F32 max_value, F32 increment,
-		const std::string& control_which = LLStringUtil::null );
-
+	struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
+	{
+		Optional<S32>			label_width;
+		Optional<S32>			text_width;
+		Optional<bool>			show_text;
+		Optional<bool>			can_edit_text;
+		Optional<bool>			is_volume_slider;
+		Optional<S32>			decimal_digits;
+
+		Optional<LLUIColor>		text_color,
+								text_disabled_color;
+
+		Optional<CommitCallbackParam>	mouse_down_callback,
+										mouse_up_callback;
+
+		Optional<LLSlider::Params>		slider_bar;
+		Optional<LLLineEditor::Params>	value_editor;
+		Optional<LLTextBox::Params>		value_text;
+		Optional<LLTextBox::Params>		slider_label;
+
+		Params()
+		:	text_width("text_width"),
+			label_width("label_width"),
+			show_text("show_text"),
+			can_edit_text("can_edit_text"),
+			is_volume_slider("volume"),
+			decimal_digits("decimal_digits", 3),
+			text_color("text_color"),
+			text_disabled_color("text_disabled_color"),
+			slider_bar("slider_bar"),
+			value_editor("value_editor"),
+			value_text("value_text"),
+			slider_label("slider_label"),
+			mouse_down_callback("mouse_down_callback"),
+			mouse_up_callback("mouse_up_callback")
+		{}
+	};
+protected:
+	LLSliderCtrl(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual ~LLSliderCtrl() {} // Children all cleaned up by default view destructor.
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-
-	F32				getValueF32() const { return mSlider->getValueF32(); }
+	/*virtual*/ F32	getValueF32() const { return mSlider->getValueF32(); }
 	void			setValue(F32 v, BOOL from_event = FALSE);
 
-	virtual void	setValue(const LLSD& value)	{ setValue((F32)value.asReal(), TRUE); }
-	virtual LLSD	getValue() const			{ return LLSD(getValueF32()); }
-	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
-
-	virtual void	setMinValue(LLSD min_value)	{ setMinValue((F32)min_value.asReal()); }
-	virtual void	setMaxValue(LLSD max_value)	{ setMaxValue((F32)max_value.asReal()); }
+	/*virtual*/ void	setValue(const LLSD& value)	{ setValue((F32)value.asReal(), TRUE); }
+	/*virtual*/ LLSD	getValue() const			{ return LLSD(getValueF32()); }
+	/*virtual*/ BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
 
 	BOOL			isMouseHeldDown() const { return mSlider->hasMouseCapture(); }
 
-	virtual void    setEnabled( BOOL b );
-	virtual void	clear();
 	virtual void	setPrecision(S32 precision);
-	void			setMinValue(F32 min_value)  { mSlider->setMinValue(min_value); updateText(); }
-	void			setMaxValue(F32 max_value)  { mSlider->setMaxValue(max_value); updateText(); }
-	void			setIncrement(F32 increment) { mSlider->setIncrement(increment);}
+
+	/*virtual*/ void    setEnabled( BOOL b );
+	/*virtual*/ void	clear();
+	/*virtual*/ void	setMinValue(F32 min_value)  { mSlider->setMinValue(min_value); updateText(); }
+	/*virtual*/ void	setMaxValue(F32 max_value)  { mSlider->setMaxValue(max_value); updateText(); }
+	/*virtual*/ void	setIncrement(F32 increment) { mSlider->setIncrement(increment);}
 
 	F32				getMinValue() { return mSlider->getMinValue(); }
 	F32				getMaxValue() { return mSlider->getMaxValue(); }
@@ -94,27 +111,23 @@ public:
 	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
 	void			setDisabledLabelColor(const LLColor4& c)	{ mTextDisabledColor = c; }
 
-	void			setSliderMouseDownCallback(	void (*slider_mousedown_callback)(LLUICtrl* caller, void* userdata) );
-	void			setSliderMouseUpCallback(	void (*slider_mouseup_callback)(LLUICtrl* caller, void* userdata) );
+	boost::signals::connection setSliderMouseDownCallback(	const commit_signal_t::slot_type& cb );
+	boost::signals::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
 
-	virtual void	onTabInto();
+	/*virtual*/ void	onTabInto();
 
-	virtual void	setTentative(BOOL b);			// marks value as tentative
-	virtual void	onCommit();						// mark not tentative, then commit
+	/*virtual*/ void	setTentative(BOOL b);			// marks value as tentative
+	/*virtual*/ void	onCommit();						// mark not tentative, then commit
 
-	virtual void		setControlName(const std::string& control_name, LLView* context)
+	/*virtual*/ void	setControlName(const std::string& control_name, LLView* context)
 	{
-		LLView::setControlName(control_name, context);
+		LLUICtrl::setControlName(control_name, context);
 		mSlider->setControlName(control_name, context);
 	}
 
-	virtual std::string getControlName() const { return mSlider->getControlName(); }
+	static void		onSliderCommit(LLUICtrl* caller, const LLSD& userdata);
 	
-	static void		onSliderCommit(LLUICtrl* caller, void* userdata);
-	static void		onSliderMouseDown(LLUICtrl* caller,void* userdata);
-	static void		onSliderMouseUp(LLUICtrl* caller,void* userdata);
-
-	static void		onEditorCommit(LLUICtrl* caller, void* userdata);
+	static void		onEditorCommit(LLUICtrl* ctrl, const LLSD& userdata);
 	static void		onEditorGainFocus(LLFocusableElement* caller, void *userdata);
 	static void		onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
 
@@ -125,7 +138,6 @@ private:
 	const LLFontGL*	mFont;
 	BOOL			mShowText;
 	BOOL			mCanEditText;
-	BOOL			mVolumeSlider;
 	
 	S32				mPrecision;
 	LLTextBox*		mLabelBox;
@@ -136,11 +148,8 @@ private:
 	class LLLineEditor*	mEditor;
 	LLTextBox*		mTextBox;
 
-	LLColor4		mTextEnabledColor;
-	LLColor4		mTextDisabledColor;
-
-	void			(*mSliderMouseUpCallback)( LLUICtrl* ctrl, void* userdata );
-	void			(*mSliderMouseDownCallback)( LLUICtrl* ctrl, void* userdata );
+	LLUIColor	mTextEnabledColor;
+	LLUIColor	mTextDisabledColor;
 };
 
 #endif  // LL_LLSLIDERCTRL_H
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index c54a2cd140..ac4b528aac 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -49,97 +49,119 @@
 #include "llcontrol.h"
 #include "llfocusmgr.h"
 #include "llresmgr.h"
+#include "lluictrlfactory.h"
 
 const U32 MAX_STRING_LENGTH = 32;
 
 static LLRegisterWidget<LLSpinCtrl> r2("spinner");
- 
-LLSpinCtrl::LLSpinCtrl(	const std::string& name, const LLRect& rect, const std::string& label, const LLFontGL* font,
-	void (*commit_callback)(LLUICtrl*, void*),
-	void* callback_user_data,
-	F32 initial_value, F32 min_value, F32 max_value, F32 increment,
-	const std::string& control_name,
-	S32 label_width)
-	:
-	LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data, FOLLOWS_LEFT | FOLLOWS_TOP ),
-	mValue( initial_value ),
-	mInitialValue( initial_value ),
-	mMaxValue( max_value ),
-	mMinValue( min_value ),
-	mIncrement( increment ),
-	mPrecision( 3 ),
-	mLabelBox( NULL ),
-	mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ),
-	mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ),
-	mbHasBeenSet( FALSE )
+
+LLSpinCtrl::Params::Params()
+:	label_width("label_width"),
+	decimal_digits("decimal_digits"),
+	allow_text_entry("allow_text_entry", true),
+	text_enabled_color("text_enabled_color"),
+	text_disabled_color("text_disabled_color")
+{}
+
+LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
+:	LLF32UICtrl(p),
+	mLabelBox(NULL),
+	mbHasBeenSet( FALSE ),
+	mPrecision(p.decimal_digits),
+	mTextEnabledColor(p.text_enabled_color()),
+	mTextDisabledColor(p.text_disabled_color())
 {
+	static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
+	static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
+	static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
 	S32 top = getRect().getHeight();
-	S32 bottom = top - 2 * SPINCTRL_BTN_HEIGHT;
+	S32 bottom = top - 2 * spinctrl_btn_height;
 	S32 centered_top = top;
 	S32 centered_bottom = bottom;
 	S32 btn_left = 0;
+	// reserve space for spinner
+	S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));
 
 	// Label
-	if( !label.empty() )
+	if( !p.label().empty() )
 	{
 		LLRect label_rect( 0, centered_top, label_width, centered_bottom );
-		mLabelBox = new LLTextBox( std::string("SpinCtrl Label"), label_rect, label, font );
+		LLTextBox::Params params;
+		params.name("SpinCtrl Label");
+		params.rect(label_rect);
+		params.text(p.label);
+		if (p.font.isProvided())
+		{
+			params.font(p.font);
+		}
+		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild(mLabelBox);
 
-		btn_left += label_rect.mRight + SPINCTRL_SPACING;
+		btn_left += label_rect.mRight + spinctrl_spacing;
 	}
 
-	S32 btn_right = btn_left + SPINCTRL_BTN_WIDTH;
+	S32 btn_right = btn_left + spinctrl_btn_width;
 	
 	// Spin buttons
-	LLRect up_rect( btn_left, top, btn_right, top - SPINCTRL_BTN_HEIGHT );
-	std::string out_id = "UIImgBtnSpinUpOutUUID";
-	std::string in_id = "UIImgBtnSpinUpInUUID";
-	mUpBtn = new LLButton(std::string("SpinCtrl Up"), up_rect,
-								   out_id,
-								   in_id,
-								   LLStringUtil::null,
-								   &LLSpinCtrl::onUpBtn, this, LLFontGL::getFontSansSerif() );
-	mUpBtn->setFollowsLeft();
-	mUpBtn->setFollowsBottom();
-	mUpBtn->setHeldDownCallback( &LLSpinCtrl::onUpBtn );
-	mUpBtn->setTabStop(FALSE);
+	LLButton::Params up_button_params;
+	up_button_params.name(std::string("SpinCtrl Up"));
+	up_button_params.rect
+					.left(btn_left)
+					.top(top)
+					.right(btn_right)
+					.height(spinctrl_btn_height);
+	up_button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM);
+	up_button_params.image_unselected.name("spin_up_out_blue.tga");
+	up_button_params.image_selected.name("spin_up_in_blue.tga");
+	up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
+	up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
+	up_button_params.tab_stop(false);
+
+	mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
 	addChild(mUpBtn);
 
-	LLRect down_rect( btn_left, top - SPINCTRL_BTN_HEIGHT, btn_right, bottom );
-	out_id = "UIImgBtnSpinDownOutUUID";
-	in_id = "UIImgBtnSpinDownInUUID";
-	mDownBtn = new LLButton(std::string("SpinCtrl Down"), down_rect,
-							out_id,
-							in_id,
-							LLStringUtil::null,
-							&LLSpinCtrl::onDownBtn, this, LLFontGL::getFontSansSerif() );
-	mDownBtn->setFollowsLeft();
-	mDownBtn->setFollowsBottom();
-	mDownBtn->setHeldDownCallback( &LLSpinCtrl::onDownBtn );
-	mDownBtn->setTabStop(FALSE);
+	LLRect down_rect( btn_left, top - spinctrl_btn_height, btn_right, bottom );
+
+	LLButton::Params down_button_params;
+	down_button_params.name(std::string("SpinCtrl Down"));
+	down_button_params.rect
+					.left(btn_left)
+					.right(btn_right)
+					.bottom(bottom)
+					.height(spinctrl_btn_height);
+	down_button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM);
+	down_button_params.image_unselected.name("spin_down_out_blue.tga");
+	down_button_params.image_selected.name("spin_down_in_blue.tga");
+	down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
+	down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
+	down_button_params.tab_stop(false);
+	mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
 	addChild(mDownBtn);
 
 	LLRect editor_rect( btn_right + 1, centered_top, getRect().getWidth(), centered_bottom );
-	mEditor = new LLLineEditor( std::string("SpinCtrl Editor"), editor_rect, LLStringUtil::null, font,
-								MAX_STRING_LENGTH,
-								&LLSpinCtrl::onEditorCommit, NULL, NULL, this,
-								&LLLineEditor::prevalidateFloat );
-	mEditor->setFollowsLeft();
-	mEditor->setFollowsBottom();
+	LLLineEditor::Params params;
+	params.name("SpinCtrl Editor");
+	params.rect(editor_rect);
+	if (p.font.isProvided())
+	{
+		params.font(p.font);
+	}
+	params.max_length_bytes(MAX_STRING_LENGTH);
+	params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
+	params.prevalidate_callback(&LLLineEditor::prevalidateFloat);
+	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+	mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
 	mEditor->setFocusReceivedCallback( &LLSpinCtrl::onEditorGainFocus, this );
 	//RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
 	// than when it doesn't.  Instead, if you always have to double click to select all the text, 
 	// it's easier to understand
 	//mEditor->setSelectAllonFocusReceived(TRUE);
-	mEditor->setIgnoreTab(TRUE);
 	addChild(mEditor);
 
 	updateEditor();
 	setUseBoundingRect( TRUE );
 }
 
-
 F32 clamp_precision(F32 value, S32 decimal_precision)
 {
 	// pow() isn't perfect
@@ -157,69 +179,50 @@ F32 clamp_precision(F32 value, S32 decimal_precision)
 }
 
 
-// static
-void LLSpinCtrl::onUpBtn( void *userdata )
+void LLSpinCtrl::onUpBtn( const LLSD& data )
 {
-	LLSpinCtrl* self = (LLSpinCtrl*) userdata;
-	if( self->getEnabled() )
+	if( getEnabled() )
 	{
 		// use getValue()/setValue() to force reload from/to control
-		F32 val = (F32)self->getValue().asReal() + self->mIncrement;
-		val = clamp_precision(val, self->mPrecision);
-		val = llmin( val, self->mMaxValue );
+		F32 val = (F32)getValue().asReal() + mIncrement;
+		val = clamp_precision(val, mPrecision);
+		val = llmin( val, mMaxValue );
 		
-		if( self->mValidateCallback )
+		F32 saved_val = (F32)getValue().asReal();
+		setValue(val);
+		if( !mValidateSignal( this, val ) )
 		{
-			F32 saved_val = (F32)self->getValue().asReal();
-			self->setValue(val);
-			if( !self->mValidateCallback( self, self->mCallbackUserData ) )
-			{
-				self->setValue( saved_val );
-				self->reportInvalidData();
-				self->updateEditor();
-				return;
-			}
-		}
-		else
-		{
-			self->setValue(val);
+			setValue( saved_val );
+			reportInvalidData();
+			updateEditor();
+			return;
 		}
 
-		self->updateEditor();
-		self->onCommit();
+		updateEditor();
+		onCommit();
 	}
 }
 
-// static
-void LLSpinCtrl::onDownBtn( void *userdata )
+void LLSpinCtrl::onDownBtn( const LLSD& data )
 {
-	LLSpinCtrl* self = (LLSpinCtrl*) userdata;
-
-	if( self->getEnabled() )
+	if( getEnabled() )
 	{
-		F32 val = (F32)self->getValue().asReal() - self->mIncrement;
-		val = clamp_precision(val, self->mPrecision);
-		val = llmax( val, self->mMinValue );
+		F32 val = (F32)getValue().asReal() - mIncrement;
+		val = clamp_precision(val, mPrecision);
+		val = llmax( val, mMinValue );
 
-		if( self->mValidateCallback )
-		{
-			F32 saved_val = (F32)self->getValue().asReal();
-			self->setValue(val);
-			if( !self->mValidateCallback( self, self->mCallbackUserData ) )
-			{
-				self->setValue( saved_val );
-				self->reportInvalidData();
-				self->updateEditor();
-				return;
-			}
-		}
-		else
+		F32 saved_val = (F32)getValue().asReal();
+		setValue(val);
+		if( !mValidateSignal( this, val ) )
 		{
-			self->setValue(val);
+			setValue( saved_val );
+			reportInvalidData();
+			updateEditor();
+			return;
 		}
 		
-		self->updateEditor();
-		self->onCommit();
+		updateEditor();
+		onCommit();
 	}
 }
 
@@ -235,10 +238,10 @@ void LLSpinCtrl::onEditorGainFocus( LLFocusableElement* caller, void *userdata )
 void LLSpinCtrl::setValue(const LLSD& value )
 {
 	F32 v = (F32)value.asReal();
-	if (mValue != v || !mbHasBeenSet)
+	if (getValueF32() != v || !mbHasBeenSet)
 	{
 		mbHasBeenSet = TRUE;
-		mValue = v;
+        LLF32UICtrl::setValue(value);
 		
 		if (!mEditor->hasFocus())
 		{
@@ -251,10 +254,10 @@ void LLSpinCtrl::setValue(const LLSD& value )
 void LLSpinCtrl::forceSetValue(const LLSD& value )
 {
 	F32 v = (F32)value.asReal();
-	if (mValue != v || !mbHasBeenSet)
+	if (getValueF32() != v || !mbHasBeenSet)
 	{
 		mbHasBeenSet = TRUE;
-		mValue = v;
+        LLF32UICtrl::setValue(value);
 		
 		updateEditor();
 	}
@@ -286,55 +289,43 @@ void LLSpinCtrl::updateEditor()
 	mEditor->setText( text );
 }
 
-void LLSpinCtrl::onEditorCommit( LLUICtrl* caller, void *userdata )
+void LLSpinCtrl::onEditorCommit( const LLSD& data )
 {
 	BOOL success = FALSE;
 	
-	LLSpinCtrl* self = (LLSpinCtrl*) userdata;
-	llassert( caller == self->mEditor );
-
-	std::string text = self->mEditor->getText();
+	std::string text = mEditor->getText();
 	if( LLLineEditor::postvalidateFloat( text ) )
 	{
 		LLLocale locale(LLLocale::USER_LOCALE);
 		F32 val = (F32) atof(text.c_str());
 
-		if (val < self->mMinValue) val = self->mMinValue;
-		if (val > self->mMaxValue) val = self->mMaxValue;
+		if (val < mMinValue) val = mMinValue;
+		if (val > mMaxValue) val = mMaxValue;
 
-		if( self->mValidateCallback )
+		F32 saved_val = getValueF32();
+		setValue(val);
+		if( mValidateSignal( this, val ) )
 		{
-			F32 saved_val = self->mValue;
-			self->mValue = val;
-			if( self->mValidateCallback( self, self->mCallbackUserData ) )
-			{
-				success = TRUE;
-				self->onCommit();
-			}
-			else
-			{
-				self->mValue = saved_val;
-			}
+			success = TRUE;
+			onCommit();
 		}
 		else
 		{
-			self->mValue = val;
-			self->onCommit();
-			success = TRUE;
+			setValue(saved_val);
 		}
 	}
-	self->updateEditor();
+	updateEditor();
 
 	if( !success )
 	{
-		self->reportInvalidData();		
+		reportInvalidData();		
 	}
 }
 
 
 void LLSpinCtrl::forceEditorCommit()
 {
-	onEditorCommit(mEditor, this);
+	onEditorCommit( LLSD() );
 }
 
 
@@ -348,6 +339,10 @@ void LLSpinCtrl::setEnabled(BOOL b)
 {
 	LLView::setEnabled( b );
 	mEditor->setEnabled( b );
+	if( mLabelBox )
+	{
+		mLabelBox->setColor( b ? mTextEnabledColor.get() : mTextDisabledColor.get() );
+	}
 }
 
 
@@ -368,8 +363,8 @@ BOOL LLSpinCtrl::isMouseHeldDown() const
 void LLSpinCtrl::onCommit()
 {
 	setTentative(FALSE);
-	setControlValue(mValue);
-	LLUICtrl::onCommit();
+	setControlValue(getValueF32());
+	LLF32UICtrl::onCommit();
 }
 
 
@@ -414,29 +409,19 @@ void LLSpinCtrl::reportInvalidData()
 	make_ui_sound("UISndBadKeystroke");
 }
 
-void LLSpinCtrl::draw()
-{
-	if( mLabelBox )
-	{
-		mLabelBox->setColor( getEnabled() ? mTextEnabledColor : mTextDisabledColor );
-	}
-	LLUICtrl::draw();
-}
-
-
 BOOL LLSpinCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
 	if( clicks > 0 )
 	{
 		while( clicks-- )
 		{
-			LLSpinCtrl::onDownBtn(this);
+			onDownBtn(getValue());
 		}
 	}
 	else
 	while( clicks++ )
 	{
-		LLSpinCtrl::onUpBtn(this);
+		onUpBtn(getValue());
 	}
 
 	return TRUE;
@@ -456,105 +441,15 @@ BOOL LLSpinCtrl::handleKeyHere(KEY key, MASK mask)
 		}
 		if(key == KEY_UP)
 		{
-			LLSpinCtrl::onUpBtn(this);
+			onUpBtn(getValue());
 			return TRUE;
 		}
 		if(key == KEY_DOWN)
 		{
-			LLSpinCtrl::onDownBtn(this);
+			onDownBtn(getValue());
 			return TRUE;
 		}
 	}
 	return FALSE;
 }
 
-// virtual
-LLXMLNodePtr LLSpinCtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision);
-
-	if (mLabelBox)
-	{
-		node->createChild("label", TRUE)->setStringValue(mLabelBox->getText());
-
-		node->createChild("label_width", TRUE)->setIntValue(mLabelBox->getRect().getWidth());
-	}
-
-	node->createChild("initial_val", TRUE)->setFloatValue(mInitialValue);
-
-	node->createChild("min_val", TRUE)->setFloatValue(mMinValue);
-
-	node->createChild("max_val", TRUE)->setFloatValue(mMaxValue);
-
-	node->createChild("increment", TRUE)->setFloatValue(mIncrement);
-	
-	addColorXML(node, mTextEnabledColor, "text_enabled_color", "LabelTextColor");
-	addColorXML(node, mTextDisabledColor, "text_disabled_color", "LabelDisabledColor");
-
-	return node;
-}
-
-LLView* LLSpinCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("spinner");
-	node->getAttributeString("name", name);
-
-	std::string label;
-	node->getAttributeString("label", label);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	LLFontGL* font = LLView::selectFont(node);
-
-	F32 initial_value = 0.f;
-	node->getAttributeF32("initial_val", initial_value);
-
-	F32 min_value = 0.f;
-	node->getAttributeF32("min_val", min_value);
-
-	F32 max_value = 1.f; 
-	node->getAttributeF32("max_val", max_value);
-
-	F32 increment = 0.1f;
-	node->getAttributeF32("increment", increment);
-
-	U32 precision = 3;
-	node->getAttributeU32("decimal_digits", precision);
-	
-	S32 label_width = llmin(40, rect.getWidth() - 40);
-	node->getAttributeS32("label_width", label_width);
-
-	BOOL allow_text_entry = TRUE;
-	node->getAttributeBOOL("allow_text_entry", allow_text_entry);
-
-	LLUICtrlCallback callback = NULL;
-
-	if(label.empty())
-	{
-		label.assign( node->getValue() );
-	}
-
-	LLSpinCtrl* spinner = new LLSpinCtrl(name,
-							rect,
-							label,
-							font,
-							callback,
-							NULL,
-							initial_value, 
-							min_value, 
-							max_value, 
-							increment,
-							LLStringUtil::null,
-							label_width);
-
-	spinner->setPrecision(precision);
-
-	spinner->initFromXML(node, parent);
-	spinner->setAllowEdit(allow_text_entry);
-
-	return spinner;
-}
-
diff --git a/indra/llui/llspinctrl.h b/indra/llui/llspinctrl.h
index dfd0eb3ac1..eb1a2eb8a7 100644
--- a/indra/llui/llspinctrl.h
+++ b/indra/llui/llspinctrl.h
@@ -35,62 +35,46 @@
 
 
 #include "stdtypes.h"
-#include "lluictrl.h"
+#include "llf32uictrl.h"
 #include "v4color.h"
 #include "llrect.h"
 
-//
-// Constants
-//
-const S32	SPINCTRL_BTN_HEIGHT		=  8;
-const S32	SPINCTRL_BTN_WIDTH		= 16;
-const S32	SPINCTRL_SPACING		=  2;							// space between label right and button left
-const S32	SPINCTRL_HEIGHT			=  2 * SPINCTRL_BTN_HEIGHT;
-const S32	SPINCTRL_DEFAULT_LABEL_WIDTH = 10;
-
 
 class LLSpinCtrl
-: public LLUICtrl
+: public LLF32UICtrl
 {
 public:
-	LLSpinCtrl(const std::string& name, const LLRect& rect,
-		const std::string& label,
-		const LLFontGL* font,
-		void (*commit_callback)(LLUICtrl*, void*),
-		void* callback_userdata,
-		F32 initial_value, F32 min_value, F32 max_value, F32 increment,
-		const std::string& control_name = std::string(),
-		S32 label_width = SPINCTRL_DEFAULT_LABEL_WIDTH );
-
+	struct Params : public LLInitParam::Block<Params, LLF32UICtrl::Params>
+	{
+		Optional<S32> label_width;
+		Optional<U32> decimal_digits;
+		Optional<bool> allow_text_entry;
+
+		Optional<LLUIColor> text_enabled_color;
+		Optional<LLUIColor> text_disabled_color;
+
+		Params();
+	};
+protected:
+	LLSpinCtrl(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual ~LLSpinCtrl() {} // Children all cleaned up by default view destructor.
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
-
 	virtual void    forceSetValue(const LLSD& value ) ;
 	virtual void	setValue(const LLSD& value );
-	virtual LLSD	getValue() const { return mValue; }
-			F32		get() const { return (F32)getValue().asReal(); }
+			F32		get() const { return getValueF32(); }
 			void	set(F32 value) { setValue(value); mInitialValue = value; }
 
-	virtual void	setMinValue(LLSD min_value)	{ setMinValue((F32)min_value.asReal()); }
-	virtual void	setMaxValue(LLSD max_value)	{ setMaxValue((F32)max_value.asReal());  }
-
 	BOOL			isMouseHeldDown() const;
 
 	virtual void    setEnabled( BOOL b );
 	virtual void	setFocus( BOOL b );
 	virtual void	clear();
-	virtual BOOL	isDirty() const { return( mValue != mInitialValue ); }
-	virtual void    resetDirty() { mInitialValue = mValue; }
+	virtual BOOL	isDirty() const { return( getValueF32() != mInitialValue ); }
+	virtual void    resetDirty() { mInitialValue = getValueF32(); }
 
 	virtual void	setPrecision(S32 precision);
-	virtual void	setMinValue(F32 min)			{ mMinValue = min; }
-	virtual void	setMaxValue(F32 max)			{ mMaxValue = max; }
-	virtual void	setIncrement(F32 inc)			{ mIncrement = inc; }
-	virtual F32		getMinValue()			{ return mMinValue ; }
-	virtual F32 	getMaxValue()			{ return mMaxValue ; }
-	virtual F32     getIncrement()          { return mIncrement ; }
 
 	void			setLabel(const LLStringExplicit& label);
 	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
@@ -107,31 +91,23 @@ public:
 	virtual BOOL	handleScrollWheel(S32 x,S32 y,S32 clicks);
 	virtual BOOL	handleKeyHere(KEY key, MASK mask);
 
-	virtual void	draw();
-
-	static void		onEditorCommit(LLUICtrl* caller, void* userdata);
+	void			onEditorCommit(const LLSD& data);
 	static void		onEditorGainFocus(LLFocusableElement* caller, void *userdata);
 	static void		onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata);
 
-	static void		onUpBtn(void *userdata);
-	static void		onDownBtn(void *userdata);
+	void			onUpBtn(const LLSD& data);
+	void			onDownBtn(const LLSD& data);
 
 private:
 	void			updateEditor();
 	void			reportInvalidData();
 
-	F32				mValue;
-	F32				mInitialValue;
-	F32				mMaxValue;
-	F32				mMinValue;
-	F32				mIncrement;
-
 	S32				mPrecision;
 	class LLTextBox*	mLabelBox;
 
 	class LLLineEditor*	mEditor;
-	LLColor4		mTextEnabledColor;
-	LLColor4		mTextDisabledColor;
+	LLUIColor	mTextEnabledColor;
+	LLUIColor	mTextDisabledColor;
 
 	class LLButton*		mUpBtn;
 	class LLButton*		mDownBtn;
diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
new file mode 100644
index 0000000000..b5383c34ea
--- /dev/null
+++ b/indra/llui/llstatbar.cpp
@@ -0,0 +1,295 @@
+/** 
+ * @file llstatbar.cpp
+ * @brief A little map of the world with network information
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+//#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+#include "llstatbar.h"
+
+#include "llmath.h"
+#include "llui.h"
+#include "llgl.h"
+#include "llfontgl.h"
+
+#include "llstat.h"
+#include "lluictrlfactory.h"
+
+static LLRegisterWidget<LLStatBar> r1("stat_bar");
+
+///////////////////////////////////////////////////////////////////////////////////
+
+LLStatBar::LLStatBar(const Params& p)
+	: LLView(p),
+	  mLabel(p.label),
+	  mUnitLabel(p.unit_label),
+	  mMinBar(p.bar_min),
+	  mMaxBar(p.bar_max),
+	  mStatp(LLStat::getStat(p.stat)),
+	  mTickSpacing(p.tick_spacing),
+	  mLabelSpacing(p.label_spacing),
+	  mPrecision(p.precision),
+	  mUpdatesPerSec(p.update_rate),
+	  mPerSec(p.show_per_sec),
+	  mDisplayBar(p.show_bar),
+	  mDisplayHistory(p.show_history),
+	  mDisplayMean(p.show_mean)
+{
+}
+
+BOOL LLStatBar::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (mDisplayBar)
+	{
+		if (mDisplayHistory)
+		{
+			mDisplayBar = FALSE;
+			mDisplayHistory = FALSE;
+		}
+		else
+		{
+			mDisplayHistory = TRUE;
+		}
+	}
+	else
+	{
+		mDisplayBar = TRUE;
+	}
+
+	LLView* parent = getParent();
+	parent->reshape(parent->getRect().getWidth(), parent->getRect().getHeight(), FALSE);
+
+	return FALSE;
+}
+
+void LLStatBar::draw()
+{
+	if (!mStatp)
+	{
+//		llinfos << "No stats for statistics bar!" << llendl;
+		return;
+	}
+
+	// Get the values.
+	F32 current, min, max, mean;
+	if (mPerSec)
+	{
+		current = mStatp->getCurrentPerSec();
+		min = mStatp->getMinPerSec();
+		max = mStatp->getMaxPerSec();
+		mean = mStatp->getMeanPerSec();
+	}
+	else
+	{
+		current = mStatp->getCurrent();
+		min = mStatp->getMin();
+		max = mStatp->getMax();
+		mean = mStatp->getMean();
+	}
+
+
+	if ((mUpdatesPerSec == 0.f) || (mUpdateTimer.getElapsedTimeF32() > 1.f/mUpdatesPerSec) || (mValue == 0.f))
+	{
+		if (mDisplayMean)
+		{
+			mValue = mean;
+		}
+		else
+		{
+			mValue = current;
+		}
+		mUpdateTimer.reset();
+	}
+
+	S32 width = getRect().getWidth() - 40;
+	S32 max_width = width;
+	S32 bar_top = getRect().getHeight() - 15; // 16 pixels from top.
+	S32 bar_height = bar_top - 20;
+	S32 tick_height = 4;
+	S32 tick_width = 1;
+	S32 left, top, right, bottom;
+
+	F32 value_scale = max_width/(mMaxBar - mMinBar);
+
+	LLFontGL::getFontMonospace()->renderUTF8(mLabel, 0, 0, getRect().getHeight(), LLColor4(1.f, 1.f, 1.f, 1.f),
+											 LLFontGL::LEFT, LLFontGL::TOP);
+
+	std::string value_format;
+	std::string value_str;
+	if (!mUnitLabel.empty())
+	{
+		value_format = llformat( "%%.%df%%s", mPrecision);
+		value_str = llformat( value_format.c_str(), mValue, mUnitLabel.c_str());
+	}
+	else
+	{
+		value_format = llformat( "%%.%df", mPrecision);
+		value_str = llformat( value_format.c_str(), mValue);
+	}
+
+	// Draw the value.
+	LLFontGL::getFontMonospace()->renderUTF8(value_str, 0, width, getRect().getHeight(), 
+											 LLColor4(1.f, 1.f, 1.f, 0.5f),
+											 LLFontGL::RIGHT, LLFontGL::TOP);
+
+	value_format = llformat( "%%.%df", mPrecision);
+	if (mDisplayBar)
+	{
+		std::string tick_label;
+
+		// Draw the tick marks.
+		F32 tick_value;
+		top = bar_top;
+		bottom = bar_top - bar_height - tick_height/2;
+
+		LLGLSUIDefault gls_ui;
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+		for (tick_value = mMinBar; tick_value <= mMaxBar; tick_value += mTickSpacing)
+		{
+			left = llfloor((tick_value - mMinBar)*value_scale);
+			right = left + tick_width;
+			gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 1.f, 1.f, 0.1f));
+		}
+
+		// Draw the tick labels (and big ticks).
+		bottom = bar_top - bar_height - tick_height;
+		for (tick_value = mMinBar; tick_value <= mMaxBar; tick_value += mLabelSpacing)
+		{
+			left = llfloor((tick_value - mMinBar)*value_scale);
+			right = left + tick_width;
+			gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 1.f, 1.f, 0.25f));
+
+			tick_label = llformat( value_format.c_str(), tick_value);
+			// draw labels for the tick marks
+			LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, left - 1, bar_top - bar_height - tick_height,
+													 LLColor4(1.f, 1.f, 1.f, 0.5f),
+													 LLFontGL::LEFT, LLFontGL::TOP);
+		}
+
+		// Now, draw the bars
+		top = bar_top;
+		bottom = bar_top - bar_height;
+
+		// draw background bar.
+		left = 0;
+		right = width;
+		gl_rect_2d(left, top, right, bottom, LLColor4(0.f, 0.f, 0.f, 0.25f));
+
+		if (mStatp->getNumValues() == 0)
+		{
+			// No data, don't draw anything...
+			return;
+		}
+		// draw min and max
+		left = (S32) ((min - mMinBar) * value_scale);
+
+		if (left < 0)
+		{
+			left = 0;
+			llwarns << "Min:" << min << llendl;
+		}
+
+		right = (S32) ((max - mMinBar) * value_scale);
+		gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 0.f, 0.f, 0.25f));
+
+		S32 num_values = mStatp->getNumValues() - 1;
+		if (mDisplayHistory)
+		{
+			S32 i;
+			for (i = 0; i < num_values; i++)
+			{
+				if (i == mStatp->getNextBin())
+				{
+					continue;
+				}
+				if (mPerSec)
+				{
+					left = (S32)((mStatp->getPrevPerSec(i) - mMinBar) * value_scale);
+					right = (S32)((mStatp->getPrevPerSec(i) - mMinBar) * value_scale) + 1;
+					gl_rect_2d(left, bottom+i+1, right, bottom+i, LLColor4(1.f, 0.f, 0.f, 1.f));
+				}
+				else
+				{
+					left = (S32)((mStatp->getPrev(i) - mMinBar) * value_scale);
+					right = (S32)((mStatp->getPrev(i) - mMinBar) * value_scale) + 1;
+					gl_rect_2d(left, bottom+i+1, right, bottom+i, LLColor4(1.f, 0.f, 0.f, 1.f));
+				}
+			}
+		}
+		else
+		{
+			// draw current
+			left = (S32) ((current - mMinBar) * value_scale) - 1;
+			right = (S32) ((current - mMinBar) * value_scale) + 1;
+			gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 0.f, 0.f, 1.f));
+		}
+
+		// draw mean bar
+		top = bar_top + 2;
+		bottom = bar_top - bar_height - 2;
+		left = (S32) ((mean - mMinBar) * value_scale) - 1;
+		right = (S32) ((mean - mMinBar) * value_scale) + 1;
+		gl_rect_2d(left, top, right, bottom, LLColor4(0.f, 1.f, 0.f, 1.f));
+	}
+	
+	LLView::draw();
+}
+
+void LLStatBar::setRange(F32 bar_min, F32 bar_max, F32 tick_spacing, F32 label_spacing)
+{
+	mMinBar = bar_min;
+	mMaxBar = bar_max;
+	mTickSpacing = tick_spacing;
+	mLabelSpacing = label_spacing;
+}
+
+LLRect LLStatBar::getRequiredRect()
+{
+	LLRect rect;
+
+	if (mDisplayBar)
+	{
+		if (mDisplayHistory)
+		{
+			rect.mTop = 67;
+		}
+		else
+		{
+			rect.mTop = 40;
+		}
+	}
+	else
+	{
+		rect.mTop = 14;
+	}
+	return rect;
+}
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
new file mode 100644
index 0000000000..7de782a24f
--- /dev/null
+++ b/indra/llui/llstatbar.h
@@ -0,0 +1,108 @@
+/** 
+ * @file llstatbar.h
+ * @brief A little map of the world with network information
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSTATBAR_H
+#define LL_LLSTATBAR_H
+
+#include "llview.h"
+#include "llframetimer.h"
+
+class LLStat;
+
+class LLStatBar : public LLView
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<std::string> label;
+		Optional<std::string> unit_label;
+		Optional<F32> bar_min;
+		Optional<F32> bar_max;
+		Optional<F32> tick_spacing;
+		Optional<F32> label_spacing;
+		Optional<U32> precision;
+		Optional<F32> update_rate;
+		Optional<bool> show_per_sec;
+		Optional<bool> show_bar;
+		Optional<bool> show_history;
+		Optional<bool> show_mean;
+		Optional<std::string> stat;
+		Params()
+			: label("label"),
+			  unit_label("unit_label"),
+			  bar_min("bar_min", 0.0f),
+			  bar_max("bar_max", 50.0f),
+			  tick_spacing("tick_spacing", 10.0f),
+			  label_spacing("label_spacing", 10.0f),
+			  precision("precision", 0),
+			  update_rate("update_rate", 5.0f),
+			  show_per_sec("show_per_sec", TRUE),
+			  show_bar("show_bar", TRUE),
+			  show_history("show_history", FALSE),
+			  show_mean("show_mean", TRUE),
+			  stat("stat")
+		{
+			follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
+		}
+	};
+	LLStatBar(const Params&);
+
+	virtual void draw();
+	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+
+	void setStat(LLStat* stat) { mStatp = stat; }
+	void setRange(F32 bar_min, F32 bar_max, F32 tick_spacing, F32 label_spacing);
+	void getRange(F32& bar_min, F32& bar_max) { bar_min = mMinBar; bar_max = mMaxBar; }
+	
+	/*virtual*/ LLRect getRequiredRect();	// Return the height of this object, given the set options.
+
+private:
+	F32 mMinBar;
+	F32 mMaxBar;
+	F32 mTickSpacing;
+	F32 mLabelSpacing;
+	U32 mPrecision;
+	F32 mUpdatesPerSec;
+	BOOL mPerSec;				// Use the per sec stats.
+	BOOL mDisplayBar;			// Display the bar graph.
+	BOOL mDisplayHistory;
+	BOOL mDisplayMean;			// If true, display mean, if false, display current value
+
+	LLStat* mStatp;
+
+	LLFrameTimer mUpdateTimer;
+	LLUIString mLabel;
+	std::string mUnitLabel;
+	F32 mValue;
+};
+
+#endif
diff --git a/indra/llui/llstatgraph.cpp b/indra/llui/llstatgraph.cpp
new file mode 100644
index 0000000000..3bd2c9f9e7
--- /dev/null
+++ b/indra/llui/llstatgraph.cpp
@@ -0,0 +1,163 @@
+/** 
+ * @file llstatgraph.cpp
+ * @brief Simpler compact stat graph with tooltip
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+//#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+#include "llstatgraph.h"
+#include "llrender.h"
+
+#include "llmath.h"
+#include "llui.h"
+#include "llstat.h"
+#include "llgl.h"
+#include "llglheaders.h"
+//#include "llviewercontrol.h"
+
+///////////////////////////////////////////////////////////////////////////////////
+
+LLStatGraph::LLStatGraph(const LLView::Params& p)
+:	LLView(p)
+{
+	mStatp = NULL;
+	setToolTip(p.name());
+	mNumThresholds = 3;
+	mThresholdColors[0] = LLColor4(0.f, 1.f, 0.f, 1.f);
+	mThresholdColors[1] = LLColor4(1.f, 1.f, 0.f, 1.f);
+	mThresholdColors[2] = LLColor4(1.f, 0.f, 0.f, 1.f);
+	mThresholdColors[3] = LLColor4(1.f, 0.f, 0.f, 1.f);
+	mThresholds[0] = 50.f;
+	mThresholds[1] = 75.f;
+	mThresholds[2] = 100.f;
+	mMin = 0.f;
+	mMax = 125.f;
+	mPerSec = TRUE;
+	mValue = 0.f;
+	mPrecision = 0;
+}
+
+void LLStatGraph::draw()
+{
+	F32 range, frac;
+	range = mMax - mMin;
+	if (mStatp)
+	{
+		if (mPerSec)
+		{
+			mValue = mStatp->getMeanPerSec();
+		}
+		else
+		{
+			mValue = mStatp->getMean();
+		}
+	}
+	frac = (mValue - mMin) / range;
+	frac = llmax(0.f, frac);
+	frac = llmin(1.f, frac);
+
+	if (mUpdateTimer.getElapsedTimeF32() > 0.5f)
+	{
+		std::string format_str;
+		std::string tmp_str;
+		format_str = llformat("%%s%%.%df%%s", mPrecision);
+		tmp_str = llformat(format_str.c_str(), mLabel.c_str(), mValue, mUnits.c_str());
+		setToolTip(tmp_str);
+
+		mUpdateTimer.reset();
+	}
+
+	LLColor4 color;
+
+	S32 i;
+	for (i = 0; i < mNumThresholds - 1; i++)
+	{
+		if (mThresholds[i] > mValue)
+		{
+			break;
+		}
+	}
+
+	//gl_drop_shadow(0,  getRect().getHeight(), getRect().getWidth(), 0,
+	//				gSavedSkinSettings.getColor("ColorDropShadow"), 
+	//				(S32) gSavedSettings.getF32("DropShadowFloater") );
+
+	color = LLUI::sSettingGroups["color"]->getColor( "MenuDefaultBgColor" );
+	gGL.color4fv(color.mV);
+	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, TRUE);
+
+	gGL.color4fv(LLColor4::black.mV);
+	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, FALSE);
+	
+	color = mThresholdColors[i];
+	gGL.color4fv(color.mV);
+	gl_rect_2d(1, llround(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE);
+}
+
+void LLStatGraph::setValue(const LLSD& value)
+{
+	mValue = (F32)value.asReal();
+}
+
+void LLStatGraph::setMin(const F32 min)
+{
+	mMin = min;
+}
+
+void LLStatGraph::setMax(const F32 max)
+{
+	mMax = max;
+}
+
+void LLStatGraph::setStat(LLStat *statp)
+{
+	mStatp = statp;
+}
+
+void LLStatGraph::setLabel(const std::string& label)
+{
+	mLabel = label;
+}
+
+void LLStatGraph::setUnits(const std::string& units)
+{
+	mUnits = units;
+}
+
+void LLStatGraph::setPrecision(const S32 precision)
+{
+	mPrecision = precision;
+}
+
+void LLStatGraph::setThreshold(const S32 i, F32 value)
+{
+	mThresholds[i] = value;
+}
diff --git a/indra/llui/llstatgraph.h b/indra/llui/llstatgraph.h
new file mode 100644
index 0000000000..dd38050b1b
--- /dev/null
+++ b/indra/llui/llstatgraph.h
@@ -0,0 +1,76 @@
+/** 
+ * @file llstatgraph.h
+ * @brief Simpler compact stat graph with tooltip
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSTATGRAPH_H
+#define LL_LLSTATGRAPH_H
+
+#include "llview.h"
+#include "llframetimer.h"
+#include "v4color.h"
+
+class LLStat;
+
+class LLStatGraph : public LLView
+{
+public:
+	LLStatGraph(const LLView::Params&);
+
+	virtual void draw();
+
+	void setLabel(const std::string& label);
+	void setUnits(const std::string& units);
+	void setPrecision(const S32 precision);
+	void setStat(LLStat *statp);
+	void setThreshold(const S32 i, F32 value);
+	void setMin(const F32 min);
+	void setMax(const F32 max);
+
+	/*virtual*/ void setValue(const LLSD& value);
+	
+	LLStat *mStatp;
+	BOOL mPerSec;
+private:
+	F32 mValue;
+
+	F32 mMin;
+	F32 mMax;
+	LLFrameTimer mUpdateTimer;
+	std::string mLabel;
+	std::string mUnits;
+	S32 mPrecision; // Num of digits of precision after dot
+
+	S32 mNumThresholds;
+	F32 mThresholds[4];
+	LLColor4 mThresholdColors[4];
+};
+
+#endif  // LL_LLSTATGRAPH_H
diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp
new file mode 100644
index 0000000000..e16f2c450e
--- /dev/null
+++ b/indra/llui/llstatview.cpp
@@ -0,0 +1,66 @@
+/** 
+ * @file llstatview.cpp
+ * @brief Container for all statistics info.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llstatview.h"
+
+#include "llerror.h"
+#include "llstatbar.h"
+#include "llfontgl.h"
+#include "llgl.h"
+#include "llui.h"
+
+#include "llstatbar.h"
+
+LLStatView::LLStatView(const LLStatView::Params& p)
+:	LLContainerView(p),
+	mSetting(p.setting)
+{
+	BOOL isopen = getDisplayChildren();
+	if (mSetting.length() > 0)
+	{
+		isopen = LLUI::sSettingGroups["config"]->getBOOL(mSetting);
+	}
+	setDisplayChildren(isopen);
+}
+
+LLStatView::~LLStatView()
+{
+	// Children all cleaned up by default view destructor.
+	if (mSetting.length() > 0)
+	{
+		BOOL isopen = getDisplayChildren();
+		LLUI::sSettingGroups["config"]->setBOOL(mSetting, isopen);
+	}
+}
+
diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h
new file mode 100644
index 0000000000..0197c7ceb3
--- /dev/null
+++ b/indra/llui/llstatview.h
@@ -0,0 +1,63 @@
+/** 
+ * @file llstatview.h
+ * @brief Container for all statistics info.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSTATVIEW_H
+#define LL_LLSTATVIEW_H
+
+#include "llstatbar.h"
+#include "llcontainerview.h"
+#include <vector>
+
+class LLStatBar;
+
+class LLStatView : public LLContainerView
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLContainerView::Params>
+	{
+		Optional<std::string> setting;
+		Params() 
+		:	setting("setting")
+		{
+			follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
+		}
+	};
+	~LLStatView();
+
+protected:
+	LLStatView(const Params&);
+	friend class LLUICtrlFactory;
+
+protected:
+	std::string mSetting;
+};
+#endif // LL_STATVIEW_
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index a716cbbaec..432d54dfee 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -33,10 +33,11 @@
 #include "linden_common.h"
 
 #include "llstyle.h"
+
+#include "llfontgl.h"
 #include "llstring.h"
 #include "llui.h"
 
-//#include "llviewerimagelist.h"
 
 LLStyle::LLStyle()
 {
@@ -110,7 +111,13 @@ LLStyle &LLStyle::operator=(const LLStyle &rhs)
 	return *this;
 }
 
+//virtual
+const std::string& LLStyle::getFontString() const
+{
+	return mFontName;
+}
 
+//virtual
 void LLStyle::setFontName(const std::string& fontname)
 {
 	mFontName = fontname;
@@ -118,26 +125,35 @@ void LLStyle::setFontName(const std::string& fontname)
 	std::string fontname_lc = fontname;
 	LLStringUtil::toLower(fontname_lc);
 	
-	mFontID = LLFONT_OCRA; // default
-	
+	// cache the font pointer for speed when rendering text
 	if ((fontname_lc == "sansserif") || (fontname_lc == "sans-serif"))
 	{
-		mFontID = LLFONT_SANSSERIF;
+		mFont = LLFontGL::getFontSansSerif();
 	}
 	else if ((fontname_lc == "serif"))
 	{
-		mFontID = LLFONT_SMALL;
+		// *TODO: Do we have a real serif font?
+		mFont = LLFontGL::getFontMonospace();
 	}
 	else if ((fontname_lc == "sansserifbig"))
 	{
-		mFontID = LLFONT_SANSSERIF_BIG;
+		mFont = LLFontGL::getFontSansSerifBig();
 	}
 	else if (fontname_lc ==  "small")
 	{
-		mFontID = LLFONT_SANSSERIF_SMALL;
+		mFont = LLFontGL::getFontSansSerifSmall();
+	}
+	else
+	{
+		mFont = LLFontGL::getFontMonospace();
 	}
 }
 
+//virtual
+LLFontGL* LLStyle::getFont() const
+{
+	return mFont;
+}
 
 void LLStyle::setLinkHREF(const std::string& href)
 {
@@ -166,7 +182,7 @@ LLUIImagePtr LLStyle::getImage() const
 
 void LLStyle::setImage(const LLUUID& src)
 {
-	mImagep = LLUI::sImageProvider->getUIImageByID(src);
+	mImagep = LLUI::getUIImageByID(src);
 }
 
 
diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h
index 3ad379cdd9..890abc7d67 100644
--- a/indra/llui/llstyle.h
+++ b/indra/llui/llstyle.h
@@ -34,10 +34,11 @@
 #define LL_LLSTYLE_H
 
 #include "v4color.h"
-#include "llresmgr.h"
 #include "llfont.h"
 #include "llui.h"
 
+class LLFontGL;
+
 class LLStyle : public LLRefCount
 {
 public:
@@ -55,9 +56,9 @@ public:
 	virtual BOOL isVisible() const;
 	virtual void setVisible(BOOL is_visible);
 
-	virtual const std::string& getFontString() const { return mFontName; }
+	virtual const std::string& getFontString() const;
 	virtual void setFontName(const std::string& fontname);
-	virtual LLFONT_ID getFontID() const { return mFontID; }
+	virtual LLFontGL* getFont() const;
 
 	virtual const std::string& getLinkHREF() const { return mLink; }
 	virtual void setLinkHREF(const std::string& href);
@@ -107,7 +108,7 @@ private:
 	BOOL		mVisible;
 	LLColor4	mColor;
 	std::string	mFontName;
-	LLFONT_ID   mFontID;
+	LLFontGL*   mFont;		// cached for performance
 	std::string	mLink;
 	LLUIImagePtr mImagep;
 	BOOL		mIsEmbeddedItem;
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index f4169488d4..5b24131c90 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -35,73 +35,127 @@
 #include "llfocusmgr.h"
 #include "llbutton.h"
 #include "llrect.h"
-#include "llresmgr.h"
 #include "llresizehandle.h"
 #include "lltextbox.h"
 #include "llcriticaldamp.h"
 #include "lluictrlfactory.h"
-#include "lltabcontainervertical.h"
 #include "llrender.h"
+#include "llfloater.h"
+
+//----------------------------------------------------------------------------
+
+// Implementation Notes:
+//  - Each tab points to a LLPanel (see LLTabTuple below)
+//  - When a tab is selected, the validation callback
+//    (LLUICtrl::mValidateSignal) is called
+//  -  If the validation callback returns true (or none is provided),
+//     the tab is changed and the commit callback
+//     (LLUICtrl::mCommitSignal) is called
+//  - Callbacks pass the LLTabContainer as the control,
+//    and the NAME of the selected PANEL as the LLSD data
+
+//----------------------------------------------------------------------------
 
 const F32 SCROLL_STEP_TIME = 0.4f;
 const F32 SCROLL_DELAY_TIME = 0.5f;
-const S32 TAB_PADDING = 15;
-const S32 TABCNTR_TAB_MIN_WIDTH = 60;
-const S32 TABCNTR_VERT_TAB_MIN_WIDTH = 100;
-const S32 TABCNTR_TAB_MAX_WIDTH = 150;
-const S32 TABCNTR_TAB_PARTIAL_WIDTH = 12;	// When tabs are parially obscured, how much can you still see.
-const S32 TABCNTR_TAB_HEIGHT = 16;
-const S32 TABCNTR_ARROW_BTN_SIZE = 16;
-const S32 TABCNTR_BUTTON_PANEL_OVERLAP = 1;  // how many pixels the tab buttons and tab panels overlap.
-const S32 TABCNTR_TAB_H_PAD = 4;
-
-const S32 TABCNTR_CLOSE_BTN_SIZE = 16;
-const S32 TABCNTR_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTR_CLOSE_BTN_SIZE;
-
-const S32 TABCNTRV_CLOSE_BTN_SIZE = 16;
-const S32 TABCNTRV_HEADER_HEIGHT = LLPANEL_BORDER_WIDTH + TABCNTRV_CLOSE_BTN_SIZE;
-//const S32 TABCNTRV_TAB_WIDTH = 100;
-const S32 TABCNTRV_ARROW_BTN_SIZE = 16;
-const S32 TABCNTRV_PAD = 0;
-
-static LLRegisterWidget<LLTabContainer> r("tab_container");
-
-LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabPosition pos,
-							   BOOL bordered, BOOL is_vertical )
-	: 
-	LLPanel(name, rect, bordered),
+
+void LLTabContainer::TabPositions::declareValues()
+{
+	declare("top", LLTabContainer::TOP);
+	declare("bottom", LLTabContainer::BOTTOM);
+	declare("left", LLTabContainer::LEFT);
+}
+
+//----------------------------------------------------------------------------
+
+// Structure used to map tab buttons to and from tab panels
+class LLTabTuple
+{
+public:
+	LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL)
+		:
+		mTabContainer(c),
+		mTabPanel(p),
+		mButton(b),
+		mOldState(FALSE),
+		mPlaceholderText(placeholder),
+		mPadding(0)
+	{}
+
+	LLTabContainer*  mTabContainer;
+	LLPanel*		 mTabPanel;
+	LLButton*		 mButton;
+	BOOL			 mOldState;
+	LLTextBox*		 mPlaceholderText;
+	S32				 mPadding;
+};
+
+//----------------------------------------------------------------------------
+
+struct LLPlaceHolderPanel : public LLPanel
+{
+	// create dummy param block to register with "placeholder" nane
+	struct Params : public LLPanel::Params{};
+	LLPlaceHolderPanel(const Params& p) : LLPanel(p)
+	{}
+};
+static LLRegisterWidget<LLPlaceHolderPanel> r1("placeholder");
+static LLRegisterWidget<LLTabContainer> r2("tab_container");
+
+LLTabContainer::Params::Params()
+:	tab_width("tab_width"),
+	tab_position("tab_position"),
+	tab_min_width("tab_min_width"),
+	tab_max_width("tab_max_width"),
+	hide_tabs("hide_tabs", false)
+{
+	name(std::string("tab_container"));
+	mouse_opaque = false;
+}
+
+LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
+:	LLPanel(p),
 	mCurrentTabIdx(-1),
-	mNextTabIdx(-1),
-	mTabsHidden(FALSE),
+	mTabsHidden(p.hide_tabs),
 	mScrolled(FALSE),
 	mScrollPos(0),
 	mScrollPosPixels(0),
 	mMaxScrollPos(0),
-	mCloseCallback( NULL ),
-	mCallbackUserdata( NULL ),
 	mTitleBox(NULL),
 	mTopBorderHeight(LLPANEL_BORDER_WIDTH),
-	mTabPosition(pos),
 	mLockedTabCount(0),
-	mMinTabWidth(TABCNTR_TAB_MIN_WIDTH),
-	mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH),
+	mMinTabWidth(0),
+	mMaxTabWidth(p.tab_max_width),
 	mPrevArrowBtn(NULL),
 	mNextArrowBtn(NULL),
-	mIsVertical(is_vertical),
+	mIsVertical( p.tab_position == LEFT ),
 	// Horizontal Specific
 	mJumpPrevArrowBtn(NULL),
 	mJumpNextArrowBtn(NULL),
-	mRightTabBtnOffset(0),
-	mTotalTabWidth(0)
-{ 
-	//RN: HACK to support default min width for legacy vertical tab containers
-	if (mIsVertical)
+	mRightTabBtnOffset(p.tab_padding_right),
+	mTotalTabWidth(0),
+	mTabPosition(p.tab_position)
+{
+	static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
+
+	mDragAndDropDelayTimer.stop();
+
+	if (p.tab_width.isProvided())
+	{
+		mMinTabWidth = p.tab_width;
+	}
+	else if (!mIsVertical)
 	{
-		mMinTabWidth = TABCNTR_VERT_TAB_MIN_WIDTH;
+		mMinTabWidth = p.tab_min_width;
 	}
-	setMouseOpaque(FALSE);
+	else
+	{
+		// *HACK: support default min width for legacy vertical
+		// tab containers
+		mMinTabWidth = tabcntr_vert_tab_min_width;
+	}
+
 	initButtons( );
-	mDragAndDropDelayTimer.stop();
 }
 
 LLTabContainer::~LLTabContainer()
@@ -150,16 +204,45 @@ LLView* LLTabContainer::getChildView(const std::string& name, BOOL recurse, BOOL
 	return LLView::getChildView(name, recurse, create_if_missing);
 }
 
+bool LLTabContainer::addChild(LLView* view, S32 tab_group)
+{
+	LLPanel* panelp = dynamic_cast<LLPanel*>(view);
+
+	if (panelp)
+	{
+		panelp->setSaveToXML(TRUE);
+
+		addTabPanel(TabPanelParams().panel(panelp).label(panelp->getLabel()).is_placeholder(dynamic_cast<LLPlaceHolderPanel*>(view) != NULL));
+		return true;
+	}
+	else
+	{
+		return LLUICtrl::addChild(view, tab_group);
+	}
+}
+
+BOOL LLTabContainer::postBuild()
+{
+	selectFirstTab();
+
+	return TRUE;
+}
+
 // virtual
 void LLTabContainer::draw()
 {
+	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
+	static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
+	static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0);
+	static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
+	static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0);
 	S32 target_pixel_scroll = 0;
 	S32 cur_scroll_pos = getScrollPos();
 	if (cur_scroll_pos > 0)
 	{
+		S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
 		if (!mIsVertical)
 		{
-			S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
 			for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
 			{
 				if (cur_scroll_pos == 0)
@@ -171,26 +254,10 @@ void LLTabContainer::draw()
 			}
 
 			// Show part of the tab to the left of what is fully visible
-			target_pixel_scroll -= TABCNTR_TAB_PARTIAL_WIDTH;
+			target_pixel_scroll -= tabcntr_tab_partial_width;
 			// clamp so that rightmost tab never leaves right side of screen
 			target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll);
 		}
-		else
-		{
-			S32 available_height_with_arrows = getRect().getHeight() - getTopBorderHeight() - (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + TABCNTR_ARROW_BTN_SIZE + 1);
-			for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
-			{
-				if (cur_scroll_pos==0)
-				{
-					break;
-				}
-				target_pixel_scroll += (*iter)->mButton->getRect().getHeight();
-				cur_scroll_pos--;
-			}
-			S32 total_tab_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount() + TABCNTRV_PAD;
-			// clamp so that the bottom tab never leaves bottom of panel
-			target_pixel_scroll = llmin(total_tab_height - available_height_with_arrows, target_pixel_scroll);
-		}
 	}
 
 	setScrollPosPixels((S32)lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f)));
@@ -207,13 +274,13 @@ void LLTabContainer::draw()
 	S32 left = 0, top = 0;
 	if (mIsVertical)
 	{
-		top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? TABCNTRV_ARROW_BTN_SIZE : 0);
+		top = getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1 - (has_scroll_arrows ? tabcntrv_arrow_btn_size : 0);
 		top += getScrollPosPixels();
 	}
 	else
 	{
 		// Set the leftmost position of the tab buttons.
-		left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD);
+		left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (tabcntr_arrow_btn_size * 2) : tabcntr_tab_h_pad);
 		left -= getScrollPosPixels();
 	}
 	
@@ -243,8 +310,8 @@ void LLTabContainer::draw()
 			// ...but clip them.
 			if (mIsVertical)
 			{
-				clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*TABCNTRV_PAD;
-				clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*TABCNTRV_PAD;
+				clip_rect.mBottom = mNextArrowBtn->getRect().mTop + 3*tabcntrv_pad;
+				clip_rect.mTop = mPrevArrowBtn->getRect().mBottom - 3*tabcntrv_pad;
 			}
 			else
 			{
@@ -262,7 +329,7 @@ void LLTabContainer::draw()
 
 			tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0,
 									   top ? top - tuple->mButton->getRect().mTop : 0 );
-			if (top) top -= BTN_HEIGHT + TABCNTRV_PAD;
+			if (top) top -= BTN_HEIGHT + tabcntrv_pad;
 			if (left) left += tuple->mButton->getRect().getWidth();
 
 			if (!mIsVertical)
@@ -316,6 +383,7 @@ void LLTabContainer::draw()
 // virtual
 BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 {
+	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
 	BOOL handled = FALSE;
 	BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
 
@@ -359,9 +427,9 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 		if (mIsVertical)
 		{
 			tab_rect = LLRect(firsttuple->mButton->getRect().mLeft,
-							  has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop,
+							  has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop,
 							  firsttuple->mButton->getRect().mRight,
-							  has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom );
+							  has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom );
 		}
 		else
 		{
@@ -483,6 +551,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 // virtual
 BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect )
 {
+	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
 	BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect );
 	if (!handled && getTabCount() > 0) 
 	{
@@ -493,9 +562,9 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* stic
 		if (mIsVertical)
 		{
 			clip = LLRect(firsttuple->mButton->getRect().mLeft,
-						  has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - TABCNTRV_PAD : mPrevArrowBtn->getRect().mTop,
+						  has_scroll_arrows ? mPrevArrowBtn->getRect().mBottom - tabcntrv_pad : mPrevArrowBtn->getRect().mTop,
 						  firsttuple->mButton->getRect().mRight,
-						  has_scroll_arrows ? mNextArrowBtn->getRect().mTop + TABCNTRV_PAD : mNextArrowBtn->getRect().mBottom );
+						  has_scroll_arrows ? mNextArrowBtn->getRect().mTop + tabcntrv_pad : mNextArrowBtn->getRect().mBottom );
 		}
 		else
 		{
@@ -616,14 +685,6 @@ BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask)
 	return handled;
 }
 
-// virtual
-LLXMLNodePtr LLTabContainer::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLPanel::getXML();
-	node->createChild("tab_position", TRUE)->setStringValue((getTabPosition() == TOP ? "top" : "bottom"));
-	return node;
-}
-
 // virtual
 BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,	BOOL drop,	EDragAndDropType type, void* cargo_data, EAcceptance *accept, std::string	&tooltip)
 {
@@ -676,21 +737,33 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,	BOOL drop,	EDrag
 	return LLView::handleDragAndDrop(x,	y, mask, drop, type, cargo_data,  accept, tooltip);
 }
 
-void LLTabContainer::addTabPanel(LLPanel* child, 
-								 const std::string& label, 
-								 BOOL select, 
-								 void (*on_tab_clicked)(void*, bool), 
-								 void* userdata,
-								 S32 indent,
-								 BOOL placeholder,
-								 eInsertionPoint insertion_point)
+void LLTabContainer::addTabPanel(LLPanel* panelp)
+{
+	addTabPanel(TabPanelParams().panel(panelp));
+}
+
+void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 {
+	LLPanel* child = panel.panel();
+	const std::string& label = panel.label.isProvided() 
+			? panel.label() 
+			: panel.panel()->getLabel();
+	BOOL select = panel.select_tab(); 
+	S32 indent = panel.indent();
+	BOOL placeholder = panel.is_placeholder;
+	eInsertionPoint insertion_point = panel.insert_at();
+
+	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
+	static LLUICachedControl<S32> tabcntr_button_panel_overlap ("UITabCntrButtonPanelOverlap", 0);
+	static LLUICachedControl<S32> tabcntr_tab_height ("UITabCntrTabHeight", 0);
+	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
 	if (child->getParent() == this)
 	{
 		// already a child of mine
 		return;
 	}
-	const LLFontGL* font = LLResMgr::getInstance()->getRes( mIsVertical ? LLFONT_SANSSERIF : LLFONT_SANSSERIF_SMALL );
+	const LLFontGL* font =
+		(mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall());
 
 	// Store the original label for possible xml export.
 	child->setLabel(label);
@@ -700,7 +773,7 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 	S32 button_width = mMinTabWidth;
 	if (!mIsVertical)
 	{
-		button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING, mMinTabWidth, mMaxTabWidth);
+		button_width = llclamp(font->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);
 	}
 	
 	// Tab panel
@@ -708,20 +781,20 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 	S32 tab_panel_bottom;
 	if( getTabPosition() == LLTabContainer::TOP )
 	{
-		S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT;
-		tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP);	
+		S32 tab_height = mIsVertical ? BTN_HEIGHT : tabcntr_tab_height;
+		tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - tabcntr_button_panel_overlap);	
 		tab_panel_bottom = LLPANEL_BORDER_WIDTH;
 	}
 	else
 	{
 		tab_panel_top = getRect().getHeight() - getTopBorderHeight();
-		tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP);  // Run to the edge, covering up the border
+		tab_panel_bottom = (tabcntr_tab_height - tabcntr_button_panel_overlap);  // Run to the edge, covering up the border
 	}
 	
 	LLRect tab_panel_rect;
 	if (mIsVertical)
 	{
-		tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD, 
+		tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + tabcntrv_pad, 
 								getRect().getHeight() - LLPANEL_BORDER_WIDTH,
 								getRect().getWidth() - LLPANEL_BORDER_WIDTH,
 								LLPANEL_BORDER_WIDTH);
@@ -750,20 +823,20 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 
 	if (mIsVertical)
 	{
-		btn_rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2,	// JC - Fudge factor
-								   (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * getTabCount()),
+		btn_rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2,	// JC - Fudge factor
+								   (getRect().getHeight() - getTopBorderHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * getTabCount()),
 								   mMinTabWidth,
 								   BTN_HEIGHT);
 	}
 	else if( getTabPosition() == LLTabContainer::TOP )
 	{
-		btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
+		btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, tabcntr_tab_height );
 		tab_img = "tab_top_blue.tga";
 		tab_selected_img = "tab_top_selected_blue.tga";
 	}
 	else
 	{
-		btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, TABCNTR_TAB_HEIGHT );
+		btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, tabcntr_tab_height );
 		tab_img = "tab_bottom_blue.tga";
 		tab_selected_img = "tab_bottom_selected_blue.tga";
 	}
@@ -774,31 +847,38 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 	if (placeholder)
 	{
 		btn_rect.translate(0, -LLBUTTON_V_PAD-2);
-		textbox = new LLTextBox(trimmed_label, btn_rect, trimmed_label, font);
+		LLTextBox::Params params;
+		params.name(trimmed_label);
+		params.rect(btn_rect);
+		params.text(trimmed_label);
+		params.font(font);
+		textbox = LLUICtrlFactory::create<LLTextBox> (params);
 		
-		btn = new LLButton(LLStringUtil::null, LLRect(0,0,0,0));
+		LLButton::Params p;
+		p.name("");
+		btn = LLUICtrlFactory::create<LLButton>(p);
 	}
 	else
 	{
 		if (mIsVertical)
 		{
-			btn = new LLButton(std::string("vert tab button"),
-							   btn_rect,
-							   LLStringUtil::null,
-							   LLStringUtil::null, 
-							   LLStringUtil::null, 
-							   &LLTabContainer::onTabBtn, NULL,
-							   font,
-							   trimmed_label, trimmed_label);
-			btn->setImages(std::string("tab_left.tga"), std::string("tab_left_selected.tga"));
-			btn->setScaleImage(TRUE);
-			btn->setHAlign(LLFontGL::LEFT);
-			btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
-			btn->setTabStop(FALSE);
+			LLButton::Params p;
+			p.name(std::string("vert tab button"));
+			p.rect(btn_rect);
+			p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
+			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
+			p.font(font);
+			p.label(trimmed_label);
+			p.image_unselected.name("tab_left.tga");
+			p.image_selected.name("tab_left_selected.tga");
+			p.scale_image(true);
+			p.font_halign = LLFontGL::LEFT;
+			p.tab_stop(false);
 			if (indent)
 			{
-				btn->setLeftHPad(indent);
+				p.pad_left(indent);
 			}
+			btn = LLUICtrlFactory::create<LLButton>(p);
 		}
 		else
 		{
@@ -806,39 +886,44 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 			tooltip += "\nAlt-Left arrow for previous tab";
 			tooltip += "\nAlt-Right arrow for next tab";
 
-			btn = new LLButton(std::string(child->getName()) + " tab",
-							   btn_rect, 
-							   LLStringUtil::null, LLStringUtil::null, LLStringUtil::null,
-							   &LLTabContainer::onTabBtn, NULL, // set userdata below
-							   font,
-							   trimmed_label, trimmed_label );
-			btn->setVisible( FALSE );
-			btn->setToolTip( tooltip );
-			btn->setScaleImage(TRUE);
-			btn->setImages(tab_img, tab_selected_img);
-
+			LLButton::Params p;
+			p.name(std::string(child->getName()) + " tab");
+			p.rect(btn_rect);
+			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child));
+			p.font(font);
+			p.label(trimmed_label);
+			p.visible(false);
+			p.tool_tip(tooltip);
+			p.scale_image(true);
+			p.image_unselected.name(tab_img);
+			p.image_selected.name(tab_selected_img);
+			p.tab_stop(false);
 			// Try to squeeze in a bit more text
-			btn->setLeftHPad( 4 );
-			btn->setRightHPad( 2 );
-			btn->setHAlign(LLFontGL::LEFT);
-			btn->setTabStop(FALSE);
+			p.pad_left(4);
+			p.pad_right(2);
+			p.font_halign = LLFontGL::LEFT;
+			p.follows.flags = FOLLOWS_LEFT;
+			p.follows.flags = FOLLOWS_LEFT;
+	
 			if (indent)
 			{
-				btn->setLeftHPad(indent);
+				p.pad_left(indent);
 			}
 
 			if( getTabPosition() == TOP )
 			{
-				btn->setFollowsTop();
+				p.follows.flags = p.follows.flags() | FOLLOWS_TOP;
 			}
 			else
 			{
-				btn->setFollowsBottom();
+				p.follows.flags = p.follows.flags() | FOLLOWS_BOTTOM;
 			}
+
+			btn = LLUICtrlFactory::create<LLButton>(p);
 		}
 	}
 	
-	LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, textbox );
+	LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox );
 	insertTuple( tuple, insertion_point );
 
 	if (textbox)
@@ -849,12 +934,11 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 	if (btn)
 	{
 		btn->setSaveToXML(false);
-		btn->setCallbackUserData( tuple );
 		addChild( btn, 0 );
 	}
 	if (child)
 	{
-		addChild(child, 1);
+		LLUICtrl::addChild(child, 1);
 	}
 	
 	if( select )
@@ -867,11 +951,12 @@ void LLTabContainer::addTabPanel(LLPanel* child,
 
 void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label)
 {
-	addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE);
+	addTabPanel(TabPanelParams().panel(child).label(label).is_placeholder(true));
 }
 
 void LLTabContainer::removeTabPanel(LLPanel* child)
 {
+	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
 	if (mIsVertical)
 	{
 		// Fix-up button sizes
@@ -880,8 +965,8 @@ void LLTabContainer::removeTabPanel(LLPanel* child)
 		{
 			LLTabTuple* tuple = *iter;
 			LLRect rect;
-			rect.setLeftTopAndSize(TABCNTRV_PAD + LLPANEL_BORDER_WIDTH + 2,	// JC - Fudge factor
-								   (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + TABCNTRV_PAD) * (tab_count)),
+			rect.setLeftTopAndSize(tabcntrv_pad + LLPANEL_BORDER_WIDTH + 2,	// JC - Fudge factor
+								   (getRect().getHeight() - LLPANEL_BORDER_WIDTH - 1) - ((BTN_HEIGHT + tabcntrv_pad) * (tab_count)),
 								   mMinTabWidth,
 								   BTN_HEIGHT);
 			if (tuple->mPlaceholderText)
@@ -1044,7 +1129,7 @@ S32 LLTabContainer::getPanelIndexByTitle(const std::string& title)
 	return -1;
 }
 
-LLPanel *LLTabContainer::getPanelByName(const std::string& name)
+LLPanel* LLTabContainer::getPanelByName(const std::string& name)
 {
 	for (S32 index = 0 ; index < (S32)mTabList.size(); index++)
 	{
@@ -1138,42 +1223,36 @@ BOOL LLTabContainer::selectTabPanel(LLPanel* child)
 
 BOOL LLTabContainer::selectTab(S32 which)
 {
-	if (which >= getTabCount()) return FALSE;
-	if (which < 0) return FALSE;
-
-	//if( gFocusMgr.childHasKeyboardFocus( this ) )
-	//{
-	//	gFocusMgr.setKeyboardFocus( NULL );
-	//}
+	if (which >= getTabCount() || which < 0)
+		return FALSE;
 
 	LLTabTuple* selected_tuple = getTab(which);
 	if (!selected_tuple)
 	{
 		return FALSE;
 	}
+	
+	LLSD cbdata;
+	if (selected_tuple->mTabPanel)
+		cbdata = selected_tuple->mTabPanel->getName();
 
-	if (!selected_tuple->mPrecommitChangeCallback)
+	BOOL res = FALSE;
+	if( mValidateSignal( this, cbdata ) )
 	{
-		return setTab(which);
+		res = setTab(which);
+		if (res)
+		{
+			mCommitSignal(this, cbdata);
+		}
 	}
-
-	mNextTabIdx = which;
-	selected_tuple->mPrecommitChangeCallback(selected_tuple->mUserData, false);
-	return TRUE;
+	
+	return res;
 }
 
+// private
 BOOL LLTabContainer::setTab(S32 which)
 {
-	if (which == -1)
-	{
-		if (mNextTabIdx == -1)
-		{
-			return FALSE;
-		}
-		which = mNextTabIdx;
-		mNextTabIdx = -1;
-	}
-
+	static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
 	LLTabTuple* selected_tuple = getTab(which);
 	if (!selected_tuple)
 	{
@@ -1196,7 +1275,7 @@ BOOL LLTabContainer::setTab(S32 which)
 			// RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
 			tuple->mButton->setTabStop( is_selected );
 			
-			if( is_selected && (mIsVertical || (getMaxScrollPos() > 0)))
+			if (is_selected)
 			{
 				// Make sure selected tab is within scroll region
 				if (mIsVertical)
@@ -1212,7 +1291,7 @@ BOOL LLTabContainer::setTab(S32 which)
 						is_visible = FALSE;
 					}
 				}
-				else
+				else if (getMaxScrollPos() > 0)
 				{
 					if( i < getScrollPos() )
 					{
@@ -1220,7 +1299,7 @@ BOOL LLTabContainer::setTab(S32 which)
 					}
 					else
 					{
-						S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
+						S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
 						S32 running_tab_width = tuple->mButton->getRect().getWidth();
 						S32 j = i - 1;
 						S32 min_scroll_pos = i;
@@ -1243,13 +1322,13 @@ BOOL LLTabContainer::setTab(S32 which)
 					}
 					is_visible = TRUE;
 				}
+				else
+				{
+					is_visible = TRUE;
+				}
 			}
 			i++;
 		}
-		if( selected_tuple->mOnChangeCallback )
-		{
-			selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false );
-		}
 	}
 	if (mIsVertical && getCurrentPanelIndex() >= 0)
 	{
@@ -1295,6 +1374,7 @@ void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state )
 
 void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color)
 {
+	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
 	LLTabTuple* tuple = getTabByPanel(child);
 	if( tuple )
 	{
@@ -1302,7 +1382,7 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L
 
 		if (!mIsVertical)
 		{
-			const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
+			const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
 			// remove current width from total tab strip width
 			mTotalTabWidth -= tuple->mButton->getRect().getWidth();
 
@@ -1313,7 +1393,7 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L
 			tuple->mPadding = image_overlay_width;
 
 			tuple->mButton->setRightHPad(6);
-			tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), 
+			tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), 
 									tuple->mButton->getRect().getHeight());
 			// add back in button width to total tab strip width
 			mTotalTabWidth += tuple->mButton->getRect().getWidth();
@@ -1352,33 +1432,6 @@ S32 LLTabContainer::getTopBorderHeight() const
 	return mTopBorderHeight;
 }
 
-void LLTabContainer::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool))
-{
-	LLTabTuple* tuplep = getTabByPanel(tab);
-	if (tuplep)
-	{
-		tuplep->mOnChangeCallback = on_tab_clicked;
-	}
-}
-
-void LLTabContainer::setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool))
-{
-	LLTabTuple* tuplep = getTabByPanel(tab);
-	if (tuplep)
-	{
-		tuplep->mPrecommitChangeCallback = on_precommit;
-	}
-}
-
-void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata)
-{
-	LLTabTuple* tuplep = getTabByPanel(tab);
-	if (tuplep)
-	{
-		tuplep->mUserData = userdata;
-	}
-}
-
 void LLTabContainer::setRightTabBtnOffset(S32 offset)
 {
 	mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 );
@@ -1388,13 +1441,15 @@ void LLTabContainer::setRightTabBtnOffset(S32 offset)
 
 void LLTabContainer::setPanelTitle(S32 index, const std::string& title)
 {
+	static LLUICachedControl<S32> tab_padding ("UITabPadding", 0);
+
 	if (index >= 0 && index < getTabCount())
 	{
 		LLTabTuple* tuple = getTab(index);
 		LLButton* tab_button = tuple->mButton;
-		const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL );
+		const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
 		mTotalTabWidth -= tab_button->getRect().getWidth();
-		tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
+		tab_button->reshape(llclamp(fontp->getWidth(title) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight());
 		mTotalTabWidth += tab_button->getRect().getWidth();
 		tab_button->setLabelSelected(title);
 		tab_button->setLabelUnselected(title);
@@ -1403,184 +1458,62 @@ void LLTabContainer::setPanelTitle(S32 index, const std::string& title)
 }
 
 
-// static 
-void LLTabContainer::onTabBtn( void* userdata )
+void LLTabContainer::onTabBtn( const LLSD& data, LLPanel* panel )
 {
-	LLTabTuple* tuple = (LLTabTuple*) userdata;
-	LLTabContainer* self = tuple->mTabContainer;
-	self->selectTabPanel( tuple->mTabPanel );
+	LLTabTuple* tuple = getTabByPanel(panel);
+	selectTabPanel( panel );
 
 	tuple->mTabPanel->setFocus(TRUE);
 }
 
-// static 
-void LLTabContainer::onCloseBtn( void* userdata )
-{
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	if( self->mCloseCallback )
-	{
-		self->mCloseCallback( self->mCallbackUserdata );
-	}
-}
-
-// static 
-void LLTabContainer::onNextBtn( void* userdata )
+void LLTabContainer::onNextBtn( const LLSD& data )
 {
-	// Scroll tabs to the left
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	if (!self->mScrolled)
+	if (!mScrolled)
 	{
-		self->scrollNext();
+		scrollNext();
 	}
-	self->mScrolled = FALSE;
+	mScrolled = FALSE;
 }
 
-// static 
-void LLTabContainer::onNextBtnHeld( void* userdata )
+void LLTabContainer::onNextBtnHeld( const LLSD& data )
 {
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
+	if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
 	{
-		self->mScrollTimer.reset();
-		self->scrollNext();
-		self->mScrolled = TRUE;
+		mScrollTimer.reset();
+		scrollNext();
+		mScrolled = TRUE;
 	}
 }
 
-// static 
-void LLTabContainer::onPrevBtn( void* userdata )
+void LLTabContainer::onPrevBtn( const LLSD& data )
 {
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	if (!self->mScrolled)
+	if (!mScrolled)
 	{
-		self->scrollPrev();
+		scrollPrev();
 	}
-	self->mScrolled = FALSE;
+	mScrolled = FALSE;
 }
 
-// static 
-void LLTabContainer::onJumpFirstBtn( void* userdata )
+void LLTabContainer::onJumpFirstBtn( const LLSD& data )
 {
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	self->mScrollPos = 0;
+	mScrollPos = 0;
 }
 
-// static 
-void LLTabContainer::onJumpLastBtn( void* userdata )
+void LLTabContainer::onJumpLastBtn( const LLSD& data )
 {
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	self->mScrollPos = self->mMaxScrollPos;
+	mScrollPos = mMaxScrollPos;
 }
 
-// static 
-void LLTabContainer::onPrevBtnHeld( void* userdata )
+void LLTabContainer::onPrevBtnHeld( const LLSD& data )
 {
-	LLTabContainer* self = (LLTabContainer*) userdata;
-	if (self->mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
+	if (mScrollTimer.getElapsedTimeF32() > SCROLL_STEP_TIME)
 	{
-		self->mScrollTimer.reset();
-		self->scrollPrev();
-		self->mScrolled = TRUE;
+		mScrollTimer.reset();
+		scrollPrev();
+		mScrolled = TRUE;
 	}
 }
 
-// static
-LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("tab_container");
-	node->getAttributeString("name", name);
-
-	// Figure out if we are creating a vertical or horizontal tab container.
-	bool is_vertical = false;
-	LLTabContainer::TabPosition tab_position = LLTabContainer::TOP;
-	if (node->hasAttribute("tab_position"))
-	{
-		std::string tab_position_string;
-		node->getAttributeString("tab_position", tab_position_string);
-		LLStringUtil::toLower(tab_position_string);
-
-		if ("top" == tab_position_string)
-		{
-			tab_position = LLTabContainer::TOP;
-			is_vertical = false;
-		}
-		else if ("bottom" == tab_position_string)
-		{
-			tab_position = LLTabContainer::BOTTOM;
-			is_vertical = false;
-		}
-		else if ("left" == tab_position_string)
-		{
-			is_vertical = true;
-		}
-	}
-	BOOL border = FALSE;
-	node->getAttributeBOOL("border", border);
-
-	LLTabContainer*	tab_container = new LLTabContainer(name, LLRect::null, tab_position, border, is_vertical);
-	
-	S32 tab_min_width = tab_container->mMinTabWidth;
-	if (node->hasAttribute("tab_width"))
-	{
-		node->getAttributeS32("tab_width", tab_min_width);
-	}
-	else if( node->hasAttribute("tab_min_width"))
-	{
-		node->getAttributeS32("tab_min_width", tab_min_width);
-	}
-
-	S32	tab_max_width = tab_container->mMaxTabWidth;
-	if (node->hasAttribute("tab_max_width"))
-	{
-		node->getAttributeS32("tab_max_width", tab_max_width);
-	}
-
-	tab_container->setMinTabWidth(tab_min_width); 
-	tab_container->setMaxTabWidth(tab_max_width); 
-	
-	BOOL hidden(tab_container->getTabsHidden());
-	node->getAttributeBOOL("hide_tabs", hidden);
-	tab_container->setTabsHidden(hidden);
-
-	tab_container->setPanelParameters(node, parent);
-
-	if (LLFloater::getFloaterHost())
-	{
-		LLFloater::getFloaterHost()->setTabContainer(tab_container);
-	}
-
-	//parent->addChild(tab_container);
-
-	// Add all tab panels.
-	LLXMLNodePtr child;
-	for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
-	{
-		LLView *control = factory->createCtrlWidget(tab_container, child);
-		if (control && control->isPanel())
-		{
-			LLPanel* panelp = (LLPanel*)control;
-			std::string label;
-			child->getAttributeString("label", label);
-			if (label.empty())
-			{
-				label = panelp->getLabel();
-			}
-			BOOL placeholder = FALSE;
-			child->getAttributeBOOL("placeholder", placeholder);
-			tab_container->addTabPanel(panelp, label, false,
-									   NULL, NULL, 0, placeholder);
-		}
-	}
-
-	tab_container->selectFirstTab();
-
-	tab_container->postBuild();
-
-	tab_container->initButtons(); // now that we have the correct rect
-	
-	return tab_container;
-}
-
 // private
 
 void LLTabContainer::initButtons()
@@ -1591,99 +1524,105 @@ void LLTabContainer::initButtons()
 		return; // Don't have a rect yet or already got called
 	}
 	
-	std::string out_id;
-	std::string in_id;
-
 	if (mIsVertical)
 	{
+		static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
 		// Left and right scroll arrows (for when there are too many tabs to show all at once).
 		S32 btn_top = getRect().getHeight();
-		S32 btn_top_lower = getRect().mBottom+TABCNTRV_ARROW_BTN_SIZE;
+		S32 btn_top_lower = getRect().mBottom+tabcntrv_arrow_btn_size;
 
 		LLRect up_arrow_btn_rect;
-		up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
+		up_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
 
 		LLRect down_arrow_btn_rect;
-		down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, TABCNTRV_ARROW_BTN_SIZE, TABCNTRV_ARROW_BTN_SIZE );
-
-		out_id = "UIImgBtnScrollUpOutUUID";
-		in_id = "UIImgBtnScrollUpInUUID";
-		mPrevArrowBtn = new LLButton(std::string("Up Arrow"), up_arrow_btn_rect,
-									 out_id, in_id, LLStringUtil::null,
-									 &onPrevBtn, this, NULL );
-		mPrevArrowBtn->setFollowsTop();
-		mPrevArrowBtn->setFollowsLeft();
-
-		out_id = "UIImgBtnScrollDownOutUUID";
-		in_id = "UIImgBtnScrollDownInUUID";
-		mNextArrowBtn = new LLButton(std::string("Down Arrow"), down_arrow_btn_rect,
-									 out_id, in_id, LLStringUtil::null,
-									 &onNextBtn, this, NULL );
-		mNextArrowBtn->setFollowsBottom();
-		mNextArrowBtn->setFollowsLeft();
+		down_arrow_btn_rect.setLeftTopAndSize( mMinTabWidth/2 , btn_top_lower, tabcntrv_arrow_btn_size, tabcntrv_arrow_btn_size );
+
+		LLButton::Params prev_btn_params;
+		prev_btn_params.name(std::string("Up Arrow"));
+		prev_btn_params.rect(up_arrow_btn_rect);
+		prev_btn_params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);
+		prev_btn_params.image_unselected.name("scrollbutton_up_out_blue.tga");
+		prev_btn_params.image_selected.name("scrollbutton_up_in_blue.tga");
+		prev_btn_params.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
+		mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(prev_btn_params);
+
+		LLButton::Params next_btn_params;
+		next_btn_params.name(std::string("Down Arrow"));
+		next_btn_params.rect(down_arrow_btn_rect);
+		next_btn_params.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT);
+		next_btn_params.image_unselected.name("scrollbutton_down_out_blue.tga");
+		next_btn_params.image_selected.name("scrollbutton_down_in_blue.tga");
+		next_btn_params.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
+		mNextArrowBtn = LLUICtrlFactory::create<LLButton>(next_btn_params);
 	}
 	else // Horizontal
 	{
+		static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
 		S32 arrow_fudge = 1;		//  match new art better 
 
-		// tabs on bottom reserve room for resize handle (just in case)
-		if (getTabPosition() == BOTTOM)
-		{
-			mRightTabBtnOffset = RESIZE_HANDLE_WIDTH;
-		}
-
 		// Left and right scroll arrows (for when there are too many tabs to show all at once).
-		S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : TABCNTR_ARROW_BTN_SIZE + 1;
+		S32 btn_top = (getTabPosition() == TOP ) ? getRect().getHeight() - getTopBorderHeight() : tabcntr_arrow_btn_size + 1;
 
 		LLRect left_arrow_btn_rect;
-		left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+TABCNTR_ARROW_BTN_SIZE, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
+		left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+tabcntr_arrow_btn_size, btn_top + arrow_fudge, tabcntr_arrow_btn_size, tabcntr_arrow_btn_size );
 
 		LLRect jump_left_arrow_btn_rect;
-		jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
+		jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, tabcntr_arrow_btn_size, tabcntr_arrow_btn_size );
 
-		S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1;
+		S32 right_pad = tabcntr_arrow_btn_size + LLPANEL_BORDER_WIDTH + 1;
 
 		LLRect right_arrow_btn_rect;
-		right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - TABCNTR_ARROW_BTN_SIZE,
+		right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad - tabcntr_arrow_btn_size,
 												btn_top + arrow_fudge,
-												TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
+												tabcntr_arrow_btn_size, tabcntr_arrow_btn_size );
 
 
 		LLRect jump_right_arrow_btn_rect;
 		jump_right_arrow_btn_rect.setLeftTopAndSize( getRect().getWidth() - mRightTabBtnOffset - right_pad,
 													 btn_top + arrow_fudge,
-													 TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
-
-		out_id = "UIImgBtnJumpLeftOutUUID";
-		in_id = "UIImgBtnJumpLeftInUUID";
-		mJumpPrevArrowBtn = new LLButton(std::string("Jump Left Arrow"), jump_left_arrow_btn_rect,
-										 out_id, in_id, LLStringUtil::null,
-										 &LLTabContainer::onJumpFirstBtn, this, LLFontGL::getFontSansSerif() );
-		mJumpPrevArrowBtn->setFollowsLeft();
-
-		out_id = "UIImgBtnScrollLeftOutUUID";
-		in_id = "UIImgBtnScrollLeftInUUID";
-		mPrevArrowBtn = new LLButton(std::string("Left Arrow"), left_arrow_btn_rect,
-									 out_id, in_id, LLStringUtil::null,
-									 &LLTabContainer::onPrevBtn, this, LLFontGL::getFontSansSerif() );
-		mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
-		mPrevArrowBtn->setFollowsLeft();
-	
-		out_id = "UIImgBtnJumpRightOutUUID";
-		in_id = "UIImgBtnJumpRightInUUID";
-		mJumpNextArrowBtn = new LLButton(std::string("Jump Right Arrow"), jump_right_arrow_btn_rect,
-										 out_id, in_id, LLStringUtil::null,
-										 &LLTabContainer::onJumpLastBtn, this,
-										 LLFontGL::getFontSansSerif());
-		mJumpNextArrowBtn->setFollowsRight();
-
-		out_id = "UIImgBtnScrollRightOutUUID";
-		in_id = "UIImgBtnScrollRightInUUID";
-		mNextArrowBtn = new LLButton(std::string("Right Arrow"), right_arrow_btn_rect,
-									 out_id, in_id, LLStringUtil::null,
-									 &LLTabContainer::onNextBtn, this,
-									 LLFontGL::getFontSansSerif());
-		mNextArrowBtn->setFollowsRight();
+													 tabcntr_arrow_btn_size, tabcntr_arrow_btn_size );
+
+		LLButton::Params p;
+		p.name(std::string("Jump Left Arrow"));
+		p.image_unselected.name("jump_left_out.tga");
+		p.image_selected.name("jump_left_in.tga");
+		p.click_callback.function(boost::bind(&LLTabContainer::onJumpFirstBtn, this, _2));
+		p.rect(jump_left_arrow_btn_rect);
+		p.follows.flags(FOLLOWS_LEFT);
+		
+		mJumpPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);
+
+		p = LLButton::Params();
+		p.name(std::string("Left Arrow"));
+		p.rect(left_arrow_btn_rect);
+		p.follows.flags(FOLLOWS_LEFT);
+		p.image_unselected.name("scrollbutton_left_out_blue.tga");
+		p.image_selected.name("scrollbutton_left_in_blue.tga");
+		p.click_callback.function(boost::bind(&LLTabContainer::onPrevBtn, this, _2));
+		p.mouse_held_callback.function(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2));
+		
+		mPrevArrowBtn = LLUICtrlFactory::create<LLButton>(p);
+
+		p = LLButton::Params();
+		p.name(std::string("Jump Right Arrow"));
+		p.rect(jump_right_arrow_btn_rect);
+		p.follows.flags(FOLLOWS_RIGHT);
+		p.image_unselected.name("jump_right_out.tga");
+		p.image_selected.name("jump_right_in.tga");
+		p.click_callback.function(boost::bind(&LLTabContainer::onJumpLastBtn, this, _2));
+
+		mJumpNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
+
+		p = LLButton::Params();
+		p.name(std::string("Right Arrow"));
+		p.rect(right_arrow_btn_rect);
+		p.follows.flags(FOLLOWS_RIGHT);
+		p.image_unselected.name("scrollbutton_right_out_blue.tga");
+		p.image_selected.name("scrollbutton_right_in_blue.tga");
+		p.click_callback.function(boost::bind(&LLTabContainer::onNextBtn, this, _2));
+		p.mouse_held_callback.function(boost::bind(&LLTabContainer::onNextBtnHeld, this, _2));
+
+		mNextArrowBtn = LLUICtrlFactory::create<LLButton>(p);
 
 		if( getTabPosition() == TOP )
 		{
@@ -1701,12 +1640,10 @@ void LLTabContainer::initButtons()
 		}
 	}
 
-	mPrevArrowBtn->setHeldDownCallback(onPrevBtnHeld);
 	mPrevArrowBtn->setSaveToXML(false);
 	mPrevArrowBtn->setTabStop(FALSE);
 	addChild(mPrevArrowBtn);
 
-	mNextArrowBtn->setHeldDownCallback(onNextBtnHeld);
 	mNextArrowBtn->setSaveToXML(false);
 	mNextArrowBtn->setTabStop(FALSE);
 	addChild(mNextArrowBtn);
@@ -1729,7 +1666,17 @@ void LLTabContainer::initButtons()
 	setDefaultTabGroup(1);
 }
 
-LLTabContainer::LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
+//this is a work around for the current LLPanel::initFromParams hack
+//so that it doesn't overwrite the default tab group.
+//will be removed when LLPanel is fixed soon.
+void LLTabContainer::initFromParams(const LLPanel::Params& p)
+{
+	LLPanel::initFromParams(p);
+
+	setDefaultTabGroup(1);
+}
+
+LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child)
 {
 	for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
 	{
@@ -1775,14 +1722,16 @@ void LLTabContainer::insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_p
 
 void LLTabContainer::updateMaxScrollPos()
 {
+	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
 	BOOL no_scroll = TRUE;
 	if (mIsVertical)
 	{
-		S32 tab_total_height = (BTN_HEIGHT + TABCNTRV_PAD) * getTabCount();
+		S32 tab_total_height = (BTN_HEIGHT + tabcntrv_pad) * getTabCount();
 		S32 available_height = getRect().getHeight() - getTopBorderHeight();
 		if( tab_total_height > available_height )
 		{
-			S32 available_height_with_arrows = getRect().getHeight() - 2*(TABCNTRV_ARROW_BTN_SIZE + 3*TABCNTRV_PAD);
+			static LLUICachedControl<S32> tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0);
+			S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad);
 			S32 additional_needed = tab_total_height - available_height_with_arrows;
 			setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) );
 			no_scroll = FALSE;
@@ -1790,16 +1739,19 @@ void LLTabContainer::updateMaxScrollPos()
 	}
 	else
 	{
+		static LLUICachedControl<S32> tabcntr_tab_h_pad ("UITabCntrTabHPad", 0);
+		static LLUICachedControl<S32> tabcntr_arrow_btn_size ("UITabCntrArrowBtnSize", 0);
+		static LLUICachedControl<S32> tabcntr_tab_partial_width ("UITabCntrTabPartialWidth", 0);
 		S32 tab_space = 0;
 		S32 available_space = 0;
 		tab_space = mTotalTabWidth;
-		available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_TAB_H_PAD);
+		available_space = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_tab_h_pad);
 
 		if( tab_space > available_space )
 		{
-			S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
+			S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size  + tabcntr_arrow_btn_size + 1);
 			// subtract off reserved portion on left
-			available_width_with_arrows -= TABCNTR_TAB_PARTIAL_WIDTH;
+			available_width_with_arrows -= tabcntr_tab_partial_width;
 
 			S32 running_tab_width = 0;
 			setMaxScrollPos(getTabCount());
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 8117cdee9b..7ed1a0f4bf 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -37,7 +37,7 @@
 #include "lltextbox.h"
 #include "llframetimer.h"
 
-extern const S32 TABCNTR_HEADER_HEIGHT;
+class LLTabTuple;
 
 class LLTabContainer : public LLPanel
 {
@@ -56,8 +56,31 @@ public:
 		RIGHT_OF_CURRENT
 	} eInsertionPoint;
 
-	LLTabContainer( const std::string& name, const LLRect& rect, TabPosition pos,
-					BOOL bordered, BOOL is_vertical);
+	struct TabPositions : public LLInitParam::TypeValuesHelper<LLTabContainer::TabPosition, TabPositions>
+	{
+		static void declareValues();
+	};
+
+	struct Params
+	:	public LLInitParam::Block<Params, LLPanel::Params>
+	{
+		Optional<TabPosition, TabPositions>	tab_position;
+		Optional<S32>						tab_width,
+											tab_min_width,
+											tab_max_width;
+		Optional<bool>						hide_tabs;
+		Optional<S32>						tab_padding_right;
+
+		Params();
+	};
+
+protected:
+	LLTabContainer(const Params&);
+	friend class LLUICtrlFactory;
+
+public:
+	//LLTabContainer( const std::string& name, const LLRect& rect, TabPosition pos,
+	//				BOOL bordered, BOOL is_vertical);
 
 	/*virtual*/ ~LLTabContainer();
 
@@ -74,17 +97,30 @@ public:
 	/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,	BOOL drop,
 									   EDragAndDropType type, void* cargo_data,
 									   EAcceptance* accept, std::string& tooltip);
-	/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
 	/*virtual*/ LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
+	/*virtual*/ void initFromParams(const LLPanel::Params& p);
+	/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
+	/*virtual*/ BOOL postBuild();
+
+	struct TabPanelParams : public LLInitParam::Block<TabPanelParams>
+	{
+		Mandatory<LLPanel*>			panel;
+		
+		Optional<std::string>		label;
+		Optional<bool>				select_tab,
+									is_placeholder;
+		Optional<S32>				indent;
+		Optional<eInsertionPoint>	insert_at;
+		Optional<void*>				user_data;
+
+		TabPanelParams()
+		:	panel("panel", NULL),
+			insert_at("insert_at", END)
+		{}
+	};
 
-	void 		addTabPanel(LLPanel* child, 
-							const std::string& label, 
-							BOOL select = FALSE,  
-							void (*on_tab_clicked)(void*, bool) = NULL, 
-							void* userdata = NULL,
-							S32 indent = 0,
-							BOOL placeholder = FALSE,
-							eInsertionPoint insertion_point = END);
+	void		addTabPanel(LLPanel* panel);
+	void		addTabPanel(const TabPanelParams& panel);
 	void 		addPlaceholder(LLPanel* child, const std::string& label);
 	void 		removeTabPanel( LLPanel* child );
 	void 		lockTabs(S32 num_tabs = 0);
@@ -108,7 +144,6 @@ public:
 	BOOL 		selectTabPanel( LLPanel* child );
 	BOOL 		selectTab(S32 which);
 	BOOL 		selectTabByName(const std::string& title);
-	BOOL		setTab(S32 which);
 
 	BOOL        getTabPanelFlashing(LLPanel* child);
 	void		setTabPanelFlashing(LLPanel* child, BOOL state);
@@ -119,10 +154,6 @@ public:
 	void		setTopBorderHeight(S32 height);
 	S32			getTopBorderHeight() const;
 	
-	void 		setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*,bool));
-	void		setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool));
-	void 		setTabUserData(LLPanel* tab, void* userdata);
-
 	void 		setRightTabBtnOffset( S32 offset );
 	void 		setPanelTitle(S32 index, const std::string& title);
 
@@ -134,51 +165,20 @@ public:
 
 	void		startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); }
 	
-	static void	onCloseBtn(void* userdata);
-	static void	onTabBtn(void* userdata);
-	static void	onNextBtn(void* userdata);
-	static void	onNextBtnHeld(void* userdata);
-	static void	onPrevBtn(void* userdata);
-	static void	onPrevBtnHeld(void* userdata);
-	static void onJumpFirstBtn( void* userdata );
-	static void onJumpLastBtn( void* userdata );
-
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
+	void onTabBtn( const LLSD& data, LLPanel* panel );
+	void onNextBtn(const LLSD& data);
+	void onNextBtnHeld(const LLSD& data);
+	void onPrevBtn(const LLSD& data);
+	void onPrevBtnHeld(const LLSD& data);
+	void onJumpFirstBtn( const LLSD& data );
+	void onJumpLastBtn( const LLSD& data );
 
 private:
-	// Structure used to map tab buttons to and from tab panels
-	struct LLTabTuple
-	{
-		LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b,
-					void (*cb)(void*,bool), void* userdata, LLTextBox* placeholder = NULL, 
-					void (*pcb)(void*,bool) = NULL)
-			:
-			mTabContainer(c),
-			mTabPanel(p),
-			mButton(b),
-			mOnChangeCallback( cb ),
-			mPrecommitChangeCallback( pcb ),
-			mUserData( userdata ),
-			mOldState(FALSE),
-			mPlaceholderText(placeholder),
-			mPadding(0)
-			{}
-
-		LLTabContainer*  mTabContainer;
-		LLPanel*		 mTabPanel;
-		LLButton*		 mButton;
-		void			 (*mOnChangeCallback)(void*, bool);
-		void			 (*mPrecommitChangeCallback)(void*,bool);		// Precommit callback gets called before tab is changed and 
-																		// can prevent it from being changed. onChangeCallback is called
-																		// immediately after tab is actually changed - Nyx
-		void*			 mUserData;
-		BOOL			 mOldState;
-		LLTextBox*		 mPlaceholderText;
-		S32				 mPadding;
-	};
 
 	void initButtons();
 	
+	BOOL		setTab(S32 which);
+
 	LLTabTuple* getTab(S32 index) 		{ return mTabList[index]; }
 	LLTabTuple* getTabByPanel(LLPanel* child);
 	void insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point);
@@ -207,7 +207,6 @@ private:
 	tuple_list_t					mTabList;
 	
 	S32								mCurrentTabIdx;
-	S32								mNextTabIdx;
 	BOOL							mTabsHidden;
 
 	BOOL							mScrolled;
@@ -216,9 +215,6 @@ private:
 	S32								mScrollPosPixels;
 	S32								mMaxScrollPos;
 
-	void							(*mCloseCallback)(void*);
-	void*							mCallbackUserdata;
-
 	LLTextBox*						mTitleBox;
 
 	S32								mTopBorderHeight;
@@ -242,5 +238,4 @@ private:
 	LLFrameTimer					mDragAndDropDelayTimer;
 };
 
-
 #endif  // LL_TABCONTAINER_H
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 89893bcf8d..95990bbfc2 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -30,65 +30,66 @@
  * $/LicenseInfo$
  */
 
+#define INSTANTIATE_GETCHILD_TEXTBOX
+
 #include "linden_common.h"
 #include "lltextbox.h"
 #include "lluictrlfactory.h"
 #include "llfocusmgr.h"
 #include "llwindow.h"
 
-static LLRegisterWidget<LLTextBox> r("text");
-
-LLTextBox::LLTextBox(const std::string& name, const LLRect& rect, const std::string& text,
-					 const LLFontGL* font, BOOL mouse_opaque)
-:	LLUICtrl(name, rect, mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP ),
-	mFontGL(font ? font : LLFontGL::getFontSansSerifSmall())
-{
-	initDefaults();
-	setText( text );
-	setTabStop(FALSE);
-}
-
-LLTextBox::LLTextBox(const std::string& name, const std::string& text, F32 max_width,
-					 const LLFontGL* font, BOOL mouse_opaque) :
-	LLUICtrl(name, LLRect(0, 0, 1, 1), mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),	
-	mFontGL(font ? font : LLFontGL::getFontSansSerifSmall())
-{
-	initDefaults();
-	setWrappedText(text, max_width);
-	reshapeToFitText();
-	setTabStop(FALSE);
-}
+template LLTextBox* LLView::getChild<LLTextBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
 
-LLTextBox::LLTextBox(const std::string& name_and_label, const LLRect& rect) :
-	LLUICtrl(name_and_label, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP),	
-	mFontGL(LLFontGL::getFontSansSerifSmall())
-{
-	initDefaults();
-	setText( name_and_label );
-	setTabStop(FALSE);
-}
+static LLRegisterWidget<LLTextBox> r("text");
 
-void LLTextBox::initDefaults()
+LLTextBox::Params::Params()
+:	text_color("text_color"),
+	length("length"),
+	type("type"),
+	highlight_on_hover("hover", false),
+	border_visible("border_visible", false),
+	border_drop_shadow_visible("border_drop_shadow_visible", false),
+	bg_visible("bg_visible", false),
+	use_ellipses("use_ellipses"),
+	word_wrap("word_wrap", false),
+	drop_shadow_visible("drop_shadow_visible"),
+	hover_color("hover_color"),
+	disabled_color("disabled_color"),
+	background_color("background_color"),
+	border_color("border_color"),
+	v_pad("v_pad", 0),
+	h_pad("h_pad", 0),
+	line_spacing("line_spacing", 0),
+	text("text"),
+	font_shadow("font_shadow", LLFontGL::NO_SHADOW)
+{}
+
+LLTextBox::LLTextBox(const LLTextBox::Params& p)
+:	LLUICtrl(p),
+    mFontGL(p.font),
+	mHoverActive( p.highlight_on_hover ),
+	mHasHover( FALSE ),
+	mBackgroundVisible( p.bg_visible ),
+	mBorderVisible( p.border_visible ),
+	mShadowType( p.font_shadow ),
+	mBorderDropShadowVisible( p.border_drop_shadow_visible ),
+	mUseEllipses( p.use_ellipses ),
+	mHPad(p.h_pad),
+	mVPad(p.v_pad),
+	mVAlign( LLFontGL::TOP ),
+	mClickedCallback(NULL),
+	mTextColor(p.text_color()),
+	mDisabledColor(p.disabled_color()),
+	mBackgroundColor(p.background_color()),
+	mBorderColor(p.border_color()),
+	mHoverColor(p.hover_color()),
+	mHAlign(p.font_halign),
+	mLineSpacing(p.line_spacing),
+	mWordWrap( p.word_wrap ),
+	mDidWordWrap(FALSE),
+	mFontStyle(LLFontGL::getStyleFromString(p.font.style))
 {
-	mTextColor = LLUI::sColorsGroup->getColor("LabelTextColor");
-	mDisabledColor = LLUI::sColorsGroup->getColor("LabelDisabledColor");
-	mBackgroundColor = LLUI::sColorsGroup->getColor("DefaultBackgroundColor");
-	mBorderColor = LLUI::sColorsGroup->getColor("DefaultHighlightLight");
-	mHoverColor = LLUI::sColorsGroup->getColor( "LabelSelectedColor" );
-	mHoverActive = FALSE;
-	mHasHover = FALSE;
-	mBackgroundVisible = FALSE;
-	mBorderVisible = FALSE;
-	mFontStyle = LLFontGL::DROP_SHADOW_SOFT;
-	mBorderDropShadowVisible = FALSE;
-	mUseEllipses = FALSE;
-	mLineSpacing = 0;
-	mHPad = 0;
-	mVPad = 0;
-	mHAlign = LLFontGL::LEFT;
-	mVAlign = LLFontGL::TOP;
-	mClickedCallback = NULL;
-	mCallbackUserData = NULL;
+	setText( p.text() );
 }
 
 BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
@@ -113,7 +114,6 @@ BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
 	return handled;
 }
 
-
 BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask)
 {
 	BOOL	handled = FALSE;
@@ -139,7 +139,7 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask)
 		// If mouseup in the widget, it's been clicked
 		if (mClickedCallback)
 		{
-			(*mClickedCallback)( mCallbackUserData );
+			mClickedCallback();
 		}
 	}
 
@@ -160,8 +160,15 @@ BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
 
 void LLTextBox::setText(const LLStringExplicit& text)
 {
-	mText.assign(text);
-	setLineLengths();
+	if(mWordWrap && !mDidWordWrap)
+	{
+		setWrappedText(text);
+	}
+	else
+	{
+		mText.assign(text);
+		setLineLengths();
+	}
 }
 
 void LLTextBox::setLineLengths()
@@ -193,7 +200,7 @@ void LLTextBox::setLineLengths()
 
 void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width)
 {
-	if (max_width < 0.0)
+	if (max_width < 0.0f)
 	{
 		max_width = (F32)getRect().getWidth();
 	}
@@ -203,7 +210,8 @@ void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width)
 
 	LLWString::size_type  cur = 0;;
 	LLWString::size_type  len = wtext.size();
-
+	F32 line_height =  mFontGL->getLineHeight();
+	S32 line_num = 1;
 	while (cur < len)
 	{
 		LLWString::size_type end = wtext.find('\n', cur);
@@ -221,6 +229,8 @@ void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width)
 
 			final_wtext.append(wtext, cur, useLen);
 			cur += useLen;
+			// not enough room to add any more characters
+			if (useLen == 0) break;
 		}
 
 		if (cur < len)
@@ -229,12 +239,22 @@ void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width)
 			{
 				cur += 1;
 			}
-			final_wtext += '\n';
+			line_num +=1;
+			// Don't wrap the last line if the text is going to spill off
+			// the bottom of the rectangle.  Assume we prefer to run off
+			// the right edge.
+			// *TODO: Is this the right behavior?
+			if((line_num-1)*line_height <= (F32)getRect().getHeight())
+			{
+				final_wtext += '\n';
+			}
 		}
 	}
-
+	
+	mDidWordWrap = TRUE;
 	std::string final_text = wstring_to_utf8str(final_wtext);
 	setText(final_text);
+
 }
 
 S32 LLTextBox::getTextPixelWidth()
@@ -272,6 +292,11 @@ S32 LLTextBox::getTextPixelHeight()
 	return (S32)(num_lines * mFontGL->getLineHeight());
 }
 
+void LLTextBox::setValue(const LLSD& value )
+{ 
+	mDidWordWrap = FALSE;
+	setText(value.asString());
+}
 
 BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text )
 {
@@ -289,8 +314,8 @@ void LLTextBox::draw()
 
 	if( mBorderDropShadowVisible )
 	{
-		static LLColor4 color_drop_shadow = LLUI::sColorsGroup->getColor("ColorDropShadow");
-		static S32 drop_shadow_tooltip = LLUI::sConfigGroup->getS32("DropShadowTooltip");
+		static LLUICachedControl<LLColor4> color_drop_shadow ("ColorDropShadow", *(new LLColor4));
+		static LLUICachedControl<S32> drop_shadow_tooltip ("DropShadowTooltip", 0);
 		gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
 			color_drop_shadow, drop_shadow_tooltip);
 	}
@@ -298,7 +323,7 @@ void LLTextBox::draw()
 	if (mBackgroundVisible)
 	{
 		LLRect r( 0, getRect().getHeight(), getRect().getWidth(), 0 );
-		gl_rect_2d( r, mBackgroundColor );
+		gl_rect_2d( r, mBackgroundColor.get() );
 	}
 
 	S32 text_x = 0;
@@ -321,16 +346,16 @@ void LLTextBox::draw()
 	{
 		if(mHasHover)
 		{
-			drawText( text_x, text_y, mHoverColor );
+			drawText( text_x, text_y, mHoverColor.get() );
 		}
 		else
 		{
-			drawText( text_x, text_y, mTextColor );
+			drawText( text_x, text_y, mTextColor.get() );
 		}				
 	}
 	else
 	{
-		drawText( text_x, text_y, mDisabledColor );
+		drawText( text_x, text_y, mDisabledColor.get() );
 	}
 
 	if (sDebugRects)
@@ -338,6 +363,13 @@ void LLTextBox::draw()
 		drawDebugRect();
 	}
 
+	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
+	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
+	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
+	//{
+	//	drawDebugRect();
+	//}
+
 	mHasHover = FALSE; // This is reset every frame.
 }
 
@@ -355,6 +387,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
 		mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color,
 						mHAlign, mVAlign, 
 						mFontStyle,
+						mShadowType,
 						S32_MAX, getRect().getWidth(), NULL, TRUE, mUseEllipses);
 	}
 	else
@@ -367,6 +400,7 @@ void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color )
 			mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color,
 							mHAlign, mVAlign,
 							mFontStyle,
+							mShadowType,
 							line_length, getRect().getWidth(), NULL, TRUE, mUseEllipses );
 			cur_pos += line_length + 1;
 			y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing;
@@ -380,86 +414,3 @@ void LLTextBox::reshapeToFitText()
 	S32 height = getTextPixelHeight();
 	reshape( width + 2 * mHPad, height + 2 * mVPad );
 }
-
-// virtual
-LLXMLNodePtr LLTextBox::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	// Attributes
-	node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mFontGL));
-	node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign));
-	addColorXML(node, mTextColor, "text_color", "LabelTextColor");
-	addColorXML(node, mDisabledColor, "disabled_color", "LabelDisabledColor");
-	addColorXML(node, mBackgroundColor, "bg_color", "DefaultBackgroundColor");
-	addColorXML(node, mBorderColor, "border_color", "DefaultHighlightLight");
-	node->createChild("bg_visible", TRUE)->setBoolValue(mBackgroundVisible);
-	node->createChild("border_visible", TRUE)->setBoolValue(mBorderVisible);
-	node->createChild("border_drop_shadow_visible", TRUE)->setBoolValue(mBorderDropShadowVisible);
-	node->createChild("h_pad", TRUE)->setIntValue(mHPad);
-	node->createChild("v_pad", TRUE)->setIntValue(mVPad);
-
-	// Contents
-	node->setStringValue(mText);
-
-	return node;
-}
-
-// static
-LLView* LLTextBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("text_box");
-	node->getAttributeString("name", name);
-	LLFontGL* font = LLView::selectFont(node);
-
-	std::string text = node->getTextContents();
-
-	LLTextBox* text_box = new LLTextBox(name,
-		LLRect(),
-		text,
-		font,
-		FALSE);
-		
-
-	LLFontGL::HAlign halign = LLView::selectFontHAlign(node);
-	text_box->setHAlign(halign);
-
-	text_box->initFromXML(node, parent);
-
-	node->getAttributeS32("line_spacing", text_box->mLineSpacing);
-
-	std::string font_style;
-	if (node->getAttributeString("font-style", font_style))
-	{
-		text_box->mFontStyle = LLFontGL::getStyleFromString(font_style);
-	}
-	
-	BOOL mouse_opaque = text_box->getMouseOpaque();
-	if (node->getAttributeBOOL("mouse_opaque", mouse_opaque))
-	{
-		text_box->setMouseOpaque(mouse_opaque);
-	}	
-
-	if(node->hasAttribute("text_color"))
-	{
-		LLColor4 color;
-		LLUICtrlFactory::getAttributeColor(node, "text_color", color);
-		text_box->setColor(color);
-	}
-
-	if(node->hasAttribute("hover_color"))
-	{
-		LLColor4 color;
-		LLUICtrlFactory::getAttributeColor(node, "hover_color", color);
-		text_box->setHoverColor(color);
-		text_box->setHoverActive(true);
-	}
-
-	BOOL hover_active = FALSE;
-	if(node->getAttributeBOOL("hover", hover_active))
-	{
-		text_box->setHoverActive(hover_active);
-	}
-
-	return text_box;
-}
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index 07a6aa3622..aae538a221 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -43,27 +43,46 @@ class LLTextBox
 :	public LLUICtrl
 {
 public:
-	// By default, follows top and left and is mouse-opaque.
-	// If no text, text = name.
-	// If no font, uses default system font.
-	LLTextBox(const std::string& name, const LLRect& rect, const std::string& text,
-			  const LLFontGL* font = NULL, BOOL mouse_opaque = TRUE );
+	
+	// *TODO: Add callback to Params
+	typedef boost::function<void (void)> callback_t;
+	
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<std::string> text;
 
-	// Construct a textbox which handles word wrapping for us.
-	LLTextBox(const std::string& name, const std::string& text, F32 max_width = 200,
-			  const LLFontGL* font = NULL, BOOL mouse_opaque = TRUE );
+		Optional<bool>		highlight_on_hover,
+							border_visible,
+							border_drop_shadow_visible,
+							bg_visible,
+							use_ellipses,
+							word_wrap;
 
-	// "Simple" constructors for text boxes that have the same name and label *TO BE DEPRECATED*
-	LLTextBox(const std::string& name_and_label, const LLRect& rect);
+		Optional<LLFontGL::ShadowType>	font_shadow;
 
-	// Consolidate common member initialization
-	// 20+ initializers times 3+ constructors is unmaintainable.
-	void initDefaults(); 
+		Deprecated			drop_shadow_visible,
+							type,
+							length;
 
-	virtual ~LLTextBox() {}
+		Optional<LLUIColor>	text_color,
+							hover_color,
+							disabled_color,
+							background_color,
+							border_color;
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
+		Optional<S32>		v_pad,
+							h_pad,
+							line_spacing;
+
+		Params();
+	};
+
+protected:
+	LLTextBox(const Params&);
+	friend class LLUICtrlFactory;
+
+public:
+	virtual ~LLTextBox() {}
 
 	virtual void	draw();
 	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
@@ -81,18 +100,17 @@ public:
 	void			setHoverActive( BOOL active )			{ mHoverActive = active; }
 
 	void			setText( const LLStringExplicit& text );
-	void			setWrappedText(const LLStringExplicit& text, F32 max_width = -1.0); // -1 means use existing control width
+	void			setWrappedText(const LLStringExplicit& text, F32 max_width = -1.f); // -1 means use existing control width
 	void			setUseEllipses( BOOL use_ellipses )		{ mUseEllipses = use_ellipses; }
 	
 	void			setBackgroundVisible(BOOL visible)		{ mBackgroundVisible = visible; }
 	void			setBorderVisible(BOOL visible)			{ mBorderVisible = visible; }
-	void			setFontStyle(U8 style)					{ mFontStyle = style; }
 	void			setBorderDropshadowVisible(BOOL visible){ mBorderDropShadowVisible = visible; }
 	void			setHPad(S32 pixels)						{ mHPad = pixels; }
 	void			setVPad(S32 pixels)						{ mVPad = pixels; }
 	void			setRightAlign()							{ mHAlign = LLFontGL::RIGHT; }
 	void			setHAlign( LLFontGL::HAlign align )		{ mHAlign = align; }
-	void			setClickedCallback( void (*cb)(void *data), void* data = NULL ){ mClickedCallback = cb; mCallbackUserData = data; }		// mouse down and up within button
+	void			setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); }		// mouse down and up within button
 
 	const LLFontGL* getFont() const							{ return mFontGL; }
 
@@ -102,7 +120,7 @@ public:
 	S32				getTextPixelWidth();
 	S32				getTextPixelHeight();
 
-	virtual void	setValue(const LLSD& value )			{ setText(value.asString()); }
+	virtual void	setValue(const LLSD& value );		
 	virtual LLSD	getValue() const						{ return LLSD(getText()); }
 	virtual BOOL	setTextArg( const std::string& key, const LLStringExplicit& text );
 
@@ -112,18 +130,21 @@ private:
 
 	LLUIString		mText;
 	const LLFontGL*	mFontGL;
-	LLColor4		mTextColor;
-	LLColor4		mDisabledColor;
-	LLColor4		mBackgroundColor;
-	LLColor4		mBorderColor;
-	LLColor4		mHoverColor;
+	LLUIColor	mTextColor;
+	LLUIColor	mDisabledColor;
+	LLUIColor	mBackgroundColor;
+	LLUIColor	mBorderColor;
+	LLUIColor	mHoverColor;
 
 	BOOL			mHoverActive;	
 	BOOL			mHasHover;
 	BOOL			mBackgroundVisible;
 	BOOL			mBorderVisible;
+	BOOL			mWordWrap;
+	BOOL            mDidWordWrap;
 	
 	U8				mFontStyle; // style bit flags for font
+	LLFontGL::ShadowType mShadowType;
 	BOOL			mBorderDropShadowVisible;
 	BOOL			mUseEllipses;
 
@@ -135,8 +156,14 @@ private:
 	LLFontGL::VAlign mVAlign;
 
 	std::vector<S32> mLineLengthList;
-	void			(*mClickedCallback)(void* data );
-	void*			mCallbackUserData;
+	callback_t		mClickedCallback;
 };
 
+#ifdef LL_WINDOWS
+#ifndef INSTANTIATE_GETCHILD_TEXTBOX
+#pragma warning (disable : 4231)
+extern template LLTextBox* LLView::getChild<LLTextBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+#endif
+#endif
+
 #endif
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 5e54c7a307..44d98e75c8 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -65,30 +65,15 @@
 //
 static LLRegisterWidget<LLTextEditor> r("simple_text_editor");
 
-BOOL gDebugTextEditorTips = FALSE;
-
 //
 // Constants
 //
-const S32	UI_TEXTEDITOR_BUFFER_BLOCK_SIZE = 512;
-const S32	UI_TEXTEDITOR_BORDER = 1;
-const S32	UI_TEXTEDITOR_H_PAD = 4;
-const S32	UI_TEXTEDITOR_V_PAD_TOP = 4;
 const S32	UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32;
 const S32	UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4;
 const F32	CURSOR_FLASH_DELAY = 1.0f;  // in seconds
 const S32	CURSOR_THICKNESS = 2;
 const S32	SPACES_PER_TAB = 4;
 
-const F32	PREEDIT_MARKER_BRIGHTNESS = 0.4f;
-const S32	PREEDIT_MARKER_GAP = 1;
-const S32	PREEDIT_MARKER_POSITION = 2;
-const S32	PREEDIT_MARKER_THICKNESS = 1;
-const F32	PREEDIT_STANDOUT_BRIGHTNESS = 0.6f;
-const S32	PREEDIT_STANDOUT_GAP = 1;
-const S32	PREEDIT_STANDOUT_POSITION = 2;
-const S32	PREEDIT_STANDOUT_THICKNESS = 2;
-
 
 LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
 void (* LLTextEditor::mURLcallback)(const std::string&)   = NULL;
@@ -243,18 +228,9 @@ private:
 
 
 ///////////////////////////////////////////////////////////////////
-
-LLTextEditor::LLTextEditor(	
-	const std::string& name, 
-	const LLRect& rect, 
-	S32 max_length,						// In bytes
-	const std::string &default_text, 
-	const LLFontGL* font,
-	BOOL allow_embedded_items)
-	:	
-	LLUICtrl( name, rect, TRUE, NULL, NULL, FOLLOWS_TOP | FOLLOWS_LEFT ),
-	mTextIsUpToDate(TRUE),
-	mMaxTextByteLength( max_length ),
+LLTextEditor::LLTextEditor(const LLTextEditor::Params& p)
+	:	LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
+	mMaxTextByteLength( p.max_text_length ),
 	mBaseDocIsPristine(TRUE),
 	mPristineCmd( NULL ),
 	mLastCmd( NULL ),
@@ -265,45 +241,40 @@ LLTextEditor::LLTextEditor(
 	mScrolledToBottom( TRUE ),
 	mOnScrollEndCallback( NULL ),
 	mOnScrollEndData( NULL ),
-	mCursorColor(		LLUI::sColorsGroup->getColor( "TextCursorColor" ) ),
-	mFgColor(			LLUI::sColorsGroup->getColor( "TextFgColor" ) ),
-	mDefaultColor(		LLUI::sColorsGroup->getColor( "TextDefaultColor" ) ),
-	mReadOnlyFgColor(	LLUI::sColorsGroup->getColor( "TextFgReadOnlyColor" ) ),
-	mWriteableBgColor(	LLUI::sColorsGroup->getColor( "TextBgWriteableColor" ) ),
-	mReadOnlyBgColor(	LLUI::sColorsGroup->getColor( "TextBgReadOnlyColor" ) ),
-	mFocusBgColor(		LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ),
-	mReadOnly(FALSE),
-	mWordWrap( FALSE ),
+	mCursorColor(		p.cursor_color() ),
+	mFgColor(			p.text_color() ),
+	mDefaultColor(		p.default_color() ),
+	mReadOnlyFgColor(	p.text_readonly_color() ),
+	mWriteableBgColor(	p.bg_writeable_color() ),
+	mReadOnlyBgColor(	p.bg_readonly_color() ),
+	mFocusBgColor(		p.bg_focus_color() ),
+	mReadOnly(p.read_only),
+	mWordWrap( p.word_wrap ),
 	mShowLineNumbers ( FALSE ),
-	mTabsToNextField( TRUE ),
 	mCommitOnFocusLost( FALSE ),
 	mHideScrollbarForShortDocs( FALSE ),
-	mTakesNonScrollClicks( TRUE ),
-	mTrackBottom( FALSE ),
-	mAllowEmbeddedItems( allow_embedded_items ),
+	mTakesNonScrollClicks( p.takes_non_scroll_clicks ),
+	mTrackBottom( p.track_bottom ),
+	mAllowEmbeddedItems( p.allow_embedded_items ),
 	mAcceptCallingCardNames(FALSE),
 	mHandleEditKeysDirectly( FALSE ),
 	mMouseDownX(0),
 	mMouseDownY(0),
 	mLastSelectionX(-1),
-	mLastSelectionY(-1),
 	mReflowNeeded(FALSE),
-	mScrollNeeded(FALSE)
+	mScrollNeeded(FALSE),
+	mLastSelectionY(-1),
+	mTabsToNextField(p.ignore_tab),
+	mGLFont(p.font),
+	mGLFontStyle(LLFontGL::getStyleFromString(p.font.style))
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+
 	mSourceID.generate();
 
 	// reset desired x cursor position
 	mDesiredXPixel = -1;
 
-	if (font)
-	{
-		mGLFont = font;
-	}
-	else
-	{
-		mGLFont = LLFontGL::getFontSansSerif();
-	}
-
 	updateTextRect();
 
 	S32 line_height = llround( mGLFont->getLineHeight() );
@@ -312,36 +283,57 @@ LLTextEditor::LLTextEditor(
 	// Init the scrollbar
 	LLRect scroll_rect;
 	scroll_rect.setOriginAndSize( 
-		getRect().getWidth() - SCROLLBAR_SIZE,
+		getRect().getWidth() - scrollbar_size,
 		1,
-		SCROLLBAR_SIZE,
+		scrollbar_size,
 		getRect().getHeight() - 1);
 	S32 lines_in_doc = getLineCount();
-	mScrollbar = new LLScrollbar( std::string("Scrollbar"), scroll_rect,
-		LLScrollbar::VERTICAL,
-		lines_in_doc,						
-		0,						
-		page_size,
-		NULL, this );
-	mScrollbar->setFollowsRight();
-	mScrollbar->setFollowsTop();
-	mScrollbar->setFollowsBottom();
-	mScrollbar->setEnabled( TRUE );
-	mScrollbar->setVisible( TRUE );
+	LLScrollbar::Params sbparams;
+	sbparams.name("Scrollbar");
+	sbparams.rect(scroll_rect);
+	sbparams.orientation(LLScrollbar::VERTICAL);
+	sbparams.doc_size(lines_in_doc);
+	sbparams.doc_pos(0);
+	sbparams.page_size(page_size);
+	sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
+	mScrollbar = LLUICtrlFactory::create<LLScrollbar> (sbparams);
 	mScrollbar->setOnScrollEndCallback(mOnScrollEndCallback, mOnScrollEndData);
 	addChild(mScrollbar);
 
-	mBorder = new LLViewBorder( std::string("text ed border"), LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER );
+	static LLUICachedControl<S32> text_editor_border ("UITextEditorBorder", 0);
+	LLViewBorder::Params params;
+	params.name("text ed border");
+	params.rect(getLocalRect());
+	params.bevel_type(LLViewBorder::BEVEL_IN);
+	params.border_thickness(text_editor_border);
+	mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
 	addChild( mBorder );
+	mBorder->setVisible(!p.hide_border);
 
-	appendText(default_text, FALSE, FALSE);
-	
-	resetDirty();		// Update saved text state
+	appendText(p.default_text, FALSE, FALSE);
+
+	setHideScrollbarForShortDocs(p.hide_scrollbar);
 
 	mParseHTML=FALSE;
 	mHTML.clear();
 }
 
+void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
+{
+	resetDirty();		// Update saved text state
+	LLUICtrl::initFromParams(p);
+	// HACK: work around enabled == readonly design bug -- RN
+	// setEnabled will modify our read only status, so do this after
+	// LLUICtrl::initFromParams
+	if (p.read_only.isProvided())
+	{
+		mReadOnly = p.read_only;
+		updateSegments();
+		updateAllowingLanguageInput();
+	}
+	// HACK:  text editors always need to be enabled so that we can scroll
+	LLView::setEnabled(true);
+}
 
 LLTextEditor::~LLTextEditor()
 {
@@ -360,6 +352,11 @@ LLTextEditor::~LLTextEditor()
 	std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());
 }
 
+LLTextViewModel* LLTextEditor::getViewModel() const
+{
+	return (LLTextViewModel*)mViewModel.get();
+}
+
 void LLTextEditor::setTrackColor( const LLColor4& color )
 { 
 	mScrollbar->setTrackColor(color); 
@@ -370,16 +367,6 @@ void LLTextEditor::setThumbColor( const LLColor4& color )
 	mScrollbar->setThumbColor(color); 
 }
 
-void LLTextEditor::setHighlightColor( const LLColor4& color ) 
-{ 
-	mScrollbar->setHighlightColor(color); 
-}
-
-void LLTextEditor::setShadowColor( const LLColor4& color ) 
-{ 
-	mScrollbar->setShadowColor(color); 
-}
-
 void LLTextEditor::updateLineStartList(S32 startpos)
 {
 	updateSegments();
@@ -400,7 +387,8 @@ void LLTextEditor::updateLineStartList(S32 startpos)
 		seg_offset = iter->mOffset;
 		mLineStartList.erase(iter, mLineStartList.end());
 	}
-	
+
+    LLWString text(getWText());
 	while( seg_idx < seg_num )
 	{
 		mLineStartList.push_back(line_info(seg_idx,seg_offset));
@@ -412,7 +400,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
 			LLTextSegment* segment = mSegments[seg_idx];
 			S32 start_idx = segment->getStart() + seg_offset;
 			S32 end_idx = start_idx;
-			while (end_idx < segment->getEnd() && mWText[end_idx] != '\n')
+			while (end_idx < segment->getEnd() && text[end_idx] != '\n')
 			{
 				end_idx++;
 			}
@@ -433,7 +421,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
 			}
 			else
 			{ 
-				const llwchar* str = mWText.c_str() + start_idx;
+				const llwchar* str = text.c_str() + start_idx;
 				S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width,
 													  end_idx - start_idx, mWordWrap, mAllowEmbeddedItems );
 				if( 0 == drawn && line_width == start_x)
@@ -447,7 +435,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
 				if (end_idx < segment->getEnd())
 				{
 					line_ended = TRUE;
-					if (mWText[end_idx] == '\n')
+					if (text[end_idx] == '\n')
 					{
 						seg_offset++; // skip newline
 					}
@@ -490,17 +478,17 @@ BOOL LLTextEditor::truncate()
 	BOOL did_truncate = FALSE;
 
 	// First rough check - if we're less than 1/4th the size, we're OK
-	if (mWText.size() >= (size_t) (mMaxTextByteLength / 4))
+	if (getLength() >= S32(mMaxTextByteLength / 4))
 	{	
 		// Have to check actual byte size
-		S32 utf8_byte_size = wstring_utf8_length( mWText );
+        LLWString text(getWText());
+		S32 utf8_byte_size = wstring_utf8_length(text);
 		if ( utf8_byte_size > mMaxTextByteLength )
 		{
 			// Truncate safely in UTF-8
-			std::string temp_utf8_text = wstring_to_utf8str( mWText );
+			std::string temp_utf8_text = wstring_to_utf8str(text);
 			temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
-			mWText = utf8str_to_wstring( temp_utf8_text );
-			mTextIsUpToDate = FALSE;
+			getViewModel()->setDisplay(utf8str_to_wstring( temp_utf8_text ));
 			did_truncate = TRUE;
 		}
 	}
@@ -511,10 +499,7 @@ BOOL LLTextEditor::truncate()
 void LLTextEditor::setText(const LLStringExplicit &utf8str)
 {
 	// LLStringUtil::removeCRLF(utf8str);
-	mUTF8Text = utf8str_removeCRLF(utf8str);
-	// mUTF8Text = utf8str;
-	mWText = utf8str_to_wstring(mUTF8Text);
-	mTextIsUpToDate = TRUE;
+	mViewModel->setValue(utf8str_removeCRLF(utf8str));
 
 	truncate();
 	blockUndo();
@@ -529,9 +514,7 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str)
 
 void LLTextEditor::setWText(const LLWString &wtext)
 {
-	mWText = wtext;
-	mUTF8Text.clear();
-	mTextIsUpToDate = FALSE;
+	getViewModel()->setDisplay(wtext);
 
 	truncate();
 	blockUndo();
@@ -550,24 +533,13 @@ void LLTextEditor::setValue(const LLSD& value)
 	setText(value.asString());
 }
 
-const std::string& LLTextEditor::getText() const
+std::string LLTextEditor::getText() const
 {
-	if (!mTextIsUpToDate)
+	if (mAllowEmbeddedItems)
 	{
-		if (mAllowEmbeddedItems)
-		{
-			llwarns << "getText() called on text with embedded items (not supported)" << llendl;
-		}
-		mUTF8Text = wstring_to_utf8str(mWText);
-		mTextIsUpToDate = TRUE;
+		llwarns << "getText() called on text with embedded items (not supported)" << llendl;
 	}
-	return mUTF8Text;
-}
-
-// virtual
-LLSD LLTextEditor::getValue() const
-{
-	return LLSD(getText());
+	return mViewModel->getValue().asString();
 }
 
 void LLTextEditor::setWordWrap(BOOL b)
@@ -709,7 +681,7 @@ void LLTextEditor::setCursorAtLocalPos( S32 local_x, S32 local_y, BOOL round )
 
 S32 LLTextEditor::prevWordPos(S32 cursorPos) const
 {
-	const LLWString& wtext = mWText;
+	LLWString wtext(getWText());
 	while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') )
 	{
 		cursorPos--;
@@ -723,7 +695,7 @@ S32 LLTextEditor::prevWordPos(S32 cursorPos) const
 
 S32 LLTextEditor::nextWordPos(S32 cursorPos) const
 {
-	const LLWString& wtext = mWText;
+	LLWString wtext(getWText());
 	while( (cursorPos < getLength()) && isPartOfWord( wtext[cursorPos] ) )
 	{
 		cursorPos++;
@@ -849,12 +821,13 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou
 	{
 		S32 line_len = line_end - line_start;
 		S32 pos;
+        LLWString text(getWText());
 
 		if (mAllowEmbeddedItems)
 		{
 			// Figure out which character we're nearest to.
 			bindEmbeddedChars(mGLFont);
-			pos = mGLFont->charFromPixelOffset(mWText.c_str(), line_start,
+			pos = mGLFont->charFromPixelOffset(text.c_str(), line_start,
 											   (F32)(local_x - mTextRect.mLeft),
 											   (F32)(mTextRect.getWidth()),
 											   line_len,
@@ -863,7 +836,7 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou
 		}
 		else
 		{
-			pos = mGLFont->charFromPixelOffset(mWText.c_str(), line_start,
+			pos = mGLFont->charFromPixelOffset(text.c_str(), line_start,
 											   (F32)(local_x - mTextRect.mLeft),
 											   (F32)mTextRect.getWidth(),
 											   line_len,
@@ -876,14 +849,15 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou
 
 void LLTextEditor::setCursor(S32 row, S32 column)
 {
-	const llwchar* doc = mWText.c_str();
+    LLWString text(getWText());
+	const llwchar* doc = text.c_str();
 	const char CR = 10;
 	while(row--)
 	{
 		while (CR != *doc++);
 	}
 	doc += column;
-	setCursorPos(doc - mWText.c_str());
+	setCursorPos(doc - text.c_str());
 }
 
 void LLTextEditor::setCursorPos(S32 offset)
@@ -935,7 +909,7 @@ BOOL LLTextEditor::selectionContainsLineBreaks()
 		S32 left = llmin(mSelectionStart, mSelectionEnd);
 		S32 right = left + llabs(mSelectionStart - mSelectionEnd);
 
-		const LLWString &wtext = mWText;
+		LLWString wtext = getWText();
 		for( S32 i = left; i < right; i++ )
 		{
 			if (wtext[i] == '\n')
@@ -972,7 +946,7 @@ S32 LLTextEditor::indentLine( S32 pos, S32 spaces )
 		// Unindent
 		for(S32 i=0; i < -spaces; i++)
 		{
-			const LLWString &wtext = mWText;
+			LLWString wtext = getWText();
 			if (wtext[pos] == ' ')
 			{
 				delta_spaces += remove( pos, 1, FALSE );
@@ -987,7 +961,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
 {
 	if( hasSelection() )
 	{
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		S32 left = llmin( mSelectionStart, mSelectionEnd );
 		S32 right = left + llabs( mSelectionStart - mSelectionEnd );
 		BOOL cursor_on_right = (mSelectionEnd > mSelectionStart);
@@ -1217,6 +1191,7 @@ BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
 
 BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
 {
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	BOOL handled = FALSE;
 
 	mHoverSegment = NULL;
@@ -1291,7 +1266,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
 		if( !handled )
 		{
 			lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;		
-			if (!mScrollbar->getVisible() || x < getRect().getWidth() - SCROLLBAR_SIZE)
+			if (!mScrollbar->getVisible() || x < getRect().getWidth() - scrollbar_size)
 			{
 				getWindow()->setCursor(UI_CURSOR_IBEAM);
 			}
@@ -1374,7 +1349,7 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 		setCursorAtLocalPos( x, y, FALSE );
 		deselect();
 
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		
 		if( isPartOfWord( text[mCursorPos] ) )
 		{
@@ -1471,12 +1446,12 @@ S32 LLTextEditor::remove(const S32 pos, const S32 length, const BOOL group_with_
 
 S32 LLTextEditor::append(const LLWString &wstr, const BOOL group_with_next_op)
 {
-	return insert(mWText.length(), wstr, group_with_next_op);
+	return insert(getLength(), wstr, group_with_next_op);
 }
 
 S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
 {
-	if ((S32)mWText.length() == pos)
+	if ((S32)getLength() == pos)
 	{
 		return addChar(pos, wc);
 	}
@@ -1498,7 +1473,7 @@ void LLTextEditor::removeCharOrTab()
 	{
 		S32 chars_to_remove = 1;
 
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		if (text[mCursorPos - 1] == ' ')
 		{
 			// Try to remove a "tab"
@@ -1563,7 +1538,7 @@ void LLTextEditor::removeChar()
 // Add a single character to the text
 S32 LLTextEditor::addChar(S32 pos, llwchar wc)
 {
-	if ( (wstring_utf8_length( mWText ) + wchar_utf8_length( wc ))  >= mMaxTextByteLength)
+	if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc ))  >= mMaxTextByteLength)
 	{
 		make_ui_sound("UISndBadKeystroke");
 		return 0;
@@ -1865,7 +1840,7 @@ void LLTextEditor::cut()
 	}
 	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
 	S32 length = llabs( mSelectionStart - mSelectionEnd );
-	gClipboard.copyFromSubstring( mWText, left_pos, length, mSourceID );
+	gClipboard.copyFromSubstring( getWText(), left_pos, length, mSourceID );
 	deleteSelection( FALSE );
 
 	needsReflow();
@@ -1885,7 +1860,7 @@ void LLTextEditor::copy()
 	}
 	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
 	S32 length = llabs( mSelectionStart - mSelectionEnd );
-	gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID);
+	gClipboard.copyFromSubstring(getWText(), left_pos, length, mSourceID);
 }
 
 BOOL LLTextEditor::canPaste() const
@@ -1986,7 +1961,7 @@ void LLTextEditor::copyPrimary()
 	}
 	S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
 	S32 length = llabs( mSelectionStart - mSelectionEnd );
-	gClipboard.copyFromPrimarySubstring(mWText, left_pos, length, mSourceID);
+	gClipboard.copyFromPrimarySubstring(getWText(), left_pos, length, mSourceID);
 }
 
 BOOL LLTextEditor::canPastePrimary() const
@@ -2237,7 +2212,7 @@ void LLTextEditor::unindentLineBeforeCloseBrace()
 {
 	if( mCursorPos >= 1 )
 	{
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		if( ' ' == text[ mCursorPos - 1 ] )
 		{
 			removeCharOrTab();
@@ -2401,7 +2376,7 @@ void LLTextEditor::doDelete()
 	{	
 		S32 i;
 		S32 chars_to_remove = 1;
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) )
 		{
 			// Try to remove a full tab's worth of spaces
@@ -2565,10 +2540,10 @@ void LLTextEditor::drawBackground()
 	S32 right = getRect().getWidth();
 	S32 bottom = 0;
 
-	LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor
-		: gFocusMgr.getKeyboardFocus() == this ? mFocusBgColor : mWriteableBgColor;
+	LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor.get()
+		: gFocusMgr.getKeyboardFocus() == this ? mFocusBgColor.get() : mWriteableBgColor.get();
 	if( mShowLineNumbers ) {
-		gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor ); // line number area always read-only
+		gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor.get() ); // line number area always read-only
 		gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, right, bottom, bg_color); // body text area to the right of line numbers
 		gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
 	} else {
@@ -2584,7 +2559,7 @@ void LLTextEditor::drawSelectionBackground()
 	// Draw selection even if we don't have keyboard focus for search/replace
 	if( hasSelection() )
 	{
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		const S32 text_len = getLength();
 		std::queue<S32> line_endings;
 
@@ -2683,7 +2658,7 @@ void LLTextEditor::drawSelectionBackground()
 		if( selection_visible )
 		{
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-			const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor;
+			const LLColor4& color = mReadOnly ? mReadOnlyBgColor.get() : mWriteableBgColor.get();
 			F32 alpha = hasFocus() ? 1.f : 0.5f;
 			gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
 			S32 margin_offset = mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
@@ -2735,7 +2710,7 @@ void LLTextEditor::drawCursor()
 	if( gFocusMgr.getKeyboardFocus() == this
 		&& gShowTextEditCursor && !mReadOnly)
 	{
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		const S32 text_len = getLength();
 
 		// Skip through the lines we aren't drawing.
@@ -2819,7 +2794,7 @@ void LLTextEditor::drawCursor()
 				
 				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-				gGL.color4fv( mCursorColor.mV );
+				gGL.color4fv( mCursorColor.get().mV );
 				
 				gl_rect_2d(llfloor(cursor_left), llfloor(cursor_top),
 					llfloor(cursor_right), llfloor(cursor_bottom));
@@ -2834,21 +2809,22 @@ void LLTextEditor::drawCursor()
 					}
 					else if (mReadOnly)
 					{
-						text_color = mReadOnlyFgColor;
+						text_color = mReadOnlyFgColor.get();
 					}
 					else
 					{
-						text_color = mFgColor;
+						text_color = mFgColor.get();
 					}
 					mGLFont->render(text, mCursorPos, next_char_left, cursor_bottom + line_height, 
 						LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], 1.f),
 						LLFontGL::LEFT, LLFontGL::TOP,
 						LLFontGL::NORMAL,
+						LLFontGL::NO_SHADOW,
 						1);
 				}
 
 				// Make sure the IME is in the right place
-				LLRect screen_pos = getScreenRect();
+				LLRect screen_pos = calcScreenRect();
 				LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_left), screen_pos.mBottom + llfloor(cursor_top) );
 
 				ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]);
@@ -2861,12 +2837,22 @@ void LLTextEditor::drawCursor()
 
 void LLTextEditor::drawPreeditMarker()
 {
+	static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0);
+	static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0);
+	static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0);
+	static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0);
+	static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0);
+	static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0);
+	static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0);
+	static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0);
+
 	if (!hasPreeditString())
 	{
 		return;
 	}
 
-	const llwchar *text = mWText.c_str();
+    const LLWString textString(getWText());
+	const llwchar *text = textString.c_str();
 	const S32 text_len = getLength();
 	const S32 num_lines = getLineCount();
 
@@ -2929,19 +2915,19 @@ void LLTextEditor::drawPreeditMarker()
 
 				if (mPreeditStandouts[i])
 				{
-					gl_rect_2d(preedit_left + PREEDIT_STANDOUT_GAP,
-							line_y + PREEDIT_STANDOUT_POSITION,
-							preedit_right - PREEDIT_STANDOUT_GAP - 1,
-							line_y + PREEDIT_STANDOUT_POSITION - PREEDIT_STANDOUT_THICKNESS,
-							(mCursorColor * PREEDIT_STANDOUT_BRIGHTNESS + mWriteableBgColor * (1 - PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f));
+					gl_rect_2d(preedit_left + preedit_standout_gap,
+							line_y + preedit_standout_position,
+							preedit_right - preedit_standout_gap - 1,
+							line_y + preedit_standout_position - preedit_standout_thickness,
+							(mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f));
 				}
 				else
 				{
-					gl_rect_2d(preedit_left + PREEDIT_MARKER_GAP,
-							line_y + PREEDIT_MARKER_POSITION,
-							preedit_right - PREEDIT_MARKER_GAP - 1,
-							line_y + PREEDIT_MARKER_POSITION - PREEDIT_MARKER_THICKNESS,
-							(mCursorColor * PREEDIT_MARKER_BRIGHTNESS + mWriteableBgColor * (1 - PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f));
+					gl_rect_2d(preedit_left + preedit_marker_gap,
+							line_y + preedit_marker_position,
+							preedit_right - preedit_marker_gap - 1,
+							line_y + preedit_marker_position - preedit_marker_thickness,
+							(mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f));
 				}
 			}
 		}
@@ -2956,9 +2942,12 @@ void LLTextEditor::drawPreeditMarker()
 
 void LLTextEditor::drawText()
 {
-	const LLWString &text = mWText;
+	LLWString text = getWText();
 	const S32 text_len = getLength();
-	if( text_len <= 0 ) return;
+	if( text_len <= 0 )
+	{
+		return;
+	}
 	S32 selection_left = -1;
 	S32 selection_right = -1;
 	// Draw selection even if we don't have keyboard focus for search/replace
@@ -2970,26 +2959,14 @@ void LLTextEditor::drawText()
 
 	LLGLSUIDefault gls_ui;
 
-	// There are several concepts that are important for understanding the following drawing code.
-	// The document is logically a sequence of characters (stored in a LLWString).
-	// Variables below with "start" or "end" in their names refer to positions or offsets into it.
-	// Next there are two kinds of "line" variables to understand. Newline characters in the
-	// character sequence represent logical lines. These are what get numbered and so variables
-	// representing this kind of line have "num" in their names.
-	// The others represent line fragments or displayed lines which the scrollbar deals with.
-	// When the "show line numbers" property is turned on, we draw line numbers to the left of the 
-	// beginning of each logical line and not in front of wrapped "continuation" display lines. -MG
-
-	S32 cur_line = mScrollbar->getDocPos(); // scrollbar counts each wrap as a new line.
+	S32 cur_line = mScrollbar->getDocPos();
 	S32 num_lines = getLineCount();
-	if (cur_line >= num_lines) return;
-	S32 line_start = getLineStart(cur_line);
-	S32 prev_start = getLineStart(cur_line-1);
-	S32 cur_line_num  = getLineForPosition(line_start); // doesn't count wraps. i.e. only counts newlines.
-	S32 prev_line_num = getLineForPosition(prev_start);
-	BOOL cur_line_is_continuation = cur_line_num > 0 && cur_line_num == prev_line_num;
-	BOOL line_wraps = FALSE;
+	if (cur_line >= num_lines)
+	{
+		return;
+	}
 	
+	S32 line_start = getLineStart(cur_line);
 	LLTextSegment t(line_start);
 	segment_list_t::iterator seg_iter;
 	seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &t, LLTextSegment::compare());
@@ -3008,36 +2985,12 @@ void LLTextEditor::drawText()
 			next_start = getLineStart(cur_line + 1);
 			line_end = next_start;
 		}
-		line_wraps = text[line_end-1] != '\n';
-		if ( ! line_wraps )
+		if ( text[line_end-1] == '\n' )
 		{
-			--line_end; // don't attempt to draw the newline char.
+			--line_end;
 		}
 		
-		F32 text_start = (F32)mTextRect.mLeft;
-		F32 text_x = text_start + (mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0);
-		
-		// draw the line numbers
-		if( mShowLineNumbers && !cur_line_is_continuation) 
-		{
-			const LLFontGL *num_font = LLFontGL::getFontMonospace();
-			F32 y_top = text_y + ((F32)llround(num_font->getLineHeight()) / 2);
-			const LLWString ltext = utf8str_to_wstring(llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num ));
-			BOOL is_cur_line = getCurrentLine() == cur_line_num;
-			const U8 style = is_cur_line ? LLFontGL::BOLD : LLFontGL::NORMAL;
-			const LLColor4 fg_color = is_cur_line ? mCursorColor : mReadOnlyFgColor;
-			num_font->render( 
-				ltext, // string to draw
-				0, // begin offset
-				3., // x
-				y_top, // y
-				fg_color, 
-				LLFontGL::LEFT, // horizontal alignment
-				LLFontGL::VCENTER, // vertical alignment
-				style, 
-				S32_MAX, // max chars
-				UI_TEXTEDITOR_LINE_NUMBER_MARGIN); // max pixels
-		}
+		F32 text_x = (F32)mTextRect.mLeft;
 
 		S32 seg_start = line_start;
 		while( seg_start < line_end )
@@ -3082,31 +3035,20 @@ void LLTextEditor::drawText()
 
 				drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x );
 
-				if( text_x == text_start && mShowLineNumbers ) 
-				{
-					text_x += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
-				}
-
 				// Note: text_x is incremented by drawClippedSegment()
 				seg_start += clipped_len;
 			}
 		}
 
-		// move down one line
-		text_y -= (F32)line_height;
-
-		if( line_wraps )
-		{
-			cur_line_num--;
-		}
-		cur_line_is_continuation = line_wraps; // so as to not not number the continuation lines
+			// move down one line
+			text_y -= (F32)line_height;
 
 		line_start = next_start;
 		cur_line++;
-		cur_line_num++;
 	}
 }
 
+
 // Draws a single text segment, reversing the color for selection if needed.
 void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32 seg_end, F32 x, F32 y, S32 selection_left, S32 selection_right, const LLStyleSP& style, F32* right_x )
 {
@@ -3121,7 +3063,7 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32
 
 	if ( style->getFontString()[0] )
 	{
-		font = LLResMgr::getInstance()->getRes(style->getFontID());
+		font = style->getFont();
 	}
 
 	U8 font_flags = LLFontGL::NORMAL;
@@ -3141,13 +3083,15 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32
 
 	if (style->getIsEmbeddedItem())
 	{
+		static LLUICachedControl<LLColor4> text_embedded_item_readonly_color ("TextEmbeddedItemReadOnlyColor", *(new LLColor4));
+		static LLUICachedControl<LLColor4> text_embedded_item_color ("TextEmbeddedItemColor", *(new LLColor4));
 		if (mReadOnly)
 		{
-			color = LLUI::sColorsGroup->getColor("TextEmbeddedItemReadOnlyColor");
+			color = text_embedded_item_readonly_color;
 		}
 		else
 		{
-			color = LLUI::sColorsGroup->getColor("TextEmbeddedItemColor");
+			color = text_embedded_item_color;
 		}
 	}
 
@@ -3159,7 +3103,7 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32
 		S32 start = seg_start;
 		S32 end = llmin( selection_left, seg_end );
 		S32 length =  end - start;
-		font->render(text, start, x, y_top, color, LLFontGL::LEFT, LLFontGL::TOP, font_flags, length, S32_MAX, right_x, mAllowEmbeddedItems);
+		font->render(text, start, x, y_top, color, LLFontGL::LEFT, LLFontGL::TOP, mGLFontStyle, LLFontGL::NO_SHADOW, length, S32_MAX, right_x, mAllowEmbeddedItems);
 	}
 	x = *right_x;
 	
@@ -3172,7 +3116,7 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32
 
 		font->render(text, start, x, y_top,
 					 LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ),
-					 LLFontGL::LEFT, LLFontGL::TOP, font_flags, length, S32_MAX, right_x, mAllowEmbeddedItems);
+					 LLFontGL::LEFT, LLFontGL::TOP, mGLFontStyle, LLFontGL::NO_SHADOW, length, S32_MAX, right_x, mAllowEmbeddedItems);
 	}
 	x = *right_x;
 	if( selection_right < seg_end )
@@ -3181,7 +3125,7 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32
 		S32 start = llmax( selection_right, seg_start );
 		S32 end = seg_end;
 		S32 length = end - start;
-		font->render(text, start, x, y_top, color, LLFontGL::LEFT, LLFontGL::TOP, font_flags, length, S32_MAX, right_x, mAllowEmbeddedItems);
+		font->render(text, start, x, y_top, color, LLFontGL::LEFT, LLFontGL::TOP, mGLFontStyle, LLFontGL::NO_SHADOW, length, S32_MAX, right_x, mAllowEmbeddedItems);
 	}
  }
 
@@ -3203,17 +3147,18 @@ void LLTextEditor::draw()
 	}
 
 	{
-		LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? SCROLLBAR_SIZE : 0), 0));
+		static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+		LLLocalClipRect clip(LLRect(0, getRect().getHeight(), getRect().getWidth() - (mScrollbar->getVisible() ? scrollbar_size : 0), 0));
 
-			bindEmbeddedChars(mGLFont);
+		bindEmbeddedChars( mGLFont );
 
-			drawBackground();
-			drawSelectionBackground();
-			drawPreeditMarker();
-			drawText();
-			drawCursor();
+		drawBackground();
+		drawSelectionBackground();
+		drawPreeditMarker();
+		drawText();
+		drawCursor();
 
-			unbindEmbeddedChars(mGLFont);
+		unbindEmbeddedChars( mGLFont );
 
 		//RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret
 		// when in readonly mode
@@ -3346,7 +3291,8 @@ void LLTextEditor::changeLine( S32 delta )
 	// if remembered position was reset (thus -1), calculate new one here
 	if( desired_x_pixel == -1 )
 	{
-		desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems );
+        LLWString text(getWText());
+		desired_x_pixel = mGLFont->getWidth(text.c_str(), line_start, offset, mAllowEmbeddedItems );
 	}
 
 	S32 new_line = 0;
@@ -3376,7 +3322,8 @@ void LLTextEditor::changeLine( S32 delta )
 	S32 new_line_len = new_line_end - new_line_start;
 
 	S32 new_offset;
-	new_offset = mGLFont->charFromPixelOffset(mWText.c_str(), new_line_start,
+    LLWString text(getWText());
+	new_offset = mGLFont->charFromPixelOffset(text.c_str(), new_line_start,
 											  (F32)desired_x_pixel,
 											  (F32)mTextRect.getWidth(),
 											  new_line_len,
@@ -3424,7 +3371,7 @@ void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* co
 	}
 	else
 	{
-		const LLWString &text = mWText;
+		LLWString text = getWText();
 		S32 line_count = 0;
 		S32 line_start = 0;
 		S32 i;
@@ -3561,7 +3508,7 @@ void LLTextEditor::autoIndent()
 	S32 space_count = 0;
 	S32 i;
 
-	const LLWString &text = mWText;
+	LLWString text = getWText();
 	while( ' ' == text[line_start] )
 	{
 		space_count++;
@@ -3813,17 +3760,18 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars)
 
 S32 LLTextEditor::insertStringNoUndo(const S32 pos, const LLWString &wstr)
 {
-	S32 old_len = mWText.length();		// length() returns character length
+    LLWString text(getWText());
+	S32 old_len = text.length();		// length() returns character length
 	S32 insert_len = wstr.length();
 
-	mWText.insert(pos, wstr);
-	mTextIsUpToDate = FALSE;
+	text.insert(pos, wstr);
+    getViewModel()->setDisplay(text);
 
 	if ( truncate() )
 	{
 		// The user's not getting everything he's hoping for
 		make_ui_sound("UISndBadKeystroke");
-		insert_len = mWText.length() - old_len;
+		insert_len = getLength() - old_len;
 	}
 
 	return insert_len;
@@ -3831,19 +3779,21 @@ S32 LLTextEditor::insertStringNoUndo(const S32 pos, const LLWString &wstr)
 
 S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length)
 {
-	mWText.erase(pos, length);
-	mTextIsUpToDate = FALSE;
+    LLWString text(getWText());
+	text.erase(pos, length);
+    getViewModel()->setDisplay(text);
 	return -length;	// This will be wrong if someone calls removeStringNoUndo with an excessive length
 }
 
 S32 LLTextEditor::overwriteCharNoUndo(S32 pos, llwchar wc)
 {
-	if (pos > (S32)mWText.length())
+	if (pos > (S32)getLength())
 	{
 		return 0;
 	}
-	mWText[pos] = wc;
-	mTextIsUpToDate = FALSE;
+    LLWString text(getWText());
+	text[pos] = wc;
+    getViewModel()->setDisplay(text);
 	return 1;
 }
 
@@ -3912,11 +3862,16 @@ BOOL LLTextEditor::tryToRevertToPristineState()
 
 void LLTextEditor::updateTextRect()
 {
+	static LLUICachedControl<S32> texteditor_border ("UITextEditorBorder", 0);
+	static LLUICachedControl<S32> texteditor_h_pad ("UITextEditorHPad", 0);
+	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
+	static LLUICachedControl<S32> texteditor_vpad_top ("UITextEditorVPadTop", 0);
+
 	mTextRect.setOriginAndSize( 
-		UI_TEXTEDITOR_BORDER + UI_TEXTEDITOR_H_PAD,
-		UI_TEXTEDITOR_BORDER, 
-		getRect().getWidth() - SCROLLBAR_SIZE - 2 * (UI_TEXTEDITOR_BORDER + UI_TEXTEDITOR_H_PAD),
-		getRect().getHeight() - 2 * UI_TEXTEDITOR_BORDER - UI_TEXTEDITOR_V_PAD_TOP );
+		texteditor_border + texteditor_h_pad,
+		texteditor_border, 
+		getRect().getWidth() - scrollbar_size - 2 * (texteditor_border + texteditor_h_pad),
+		getRect().getHeight() - 2 * texteditor_border - texteditor_vpad_top );
 }
 
 void LLTextEditor::loadKeywords(const std::string& filename,
@@ -3933,7 +3888,7 @@ void LLTextEditor::loadKeywords(const std::string& filename,
 			mKeywords.addToken(LLKeywordToken::WORD, name, color, tooltips[i] );
 		}
 
-		mKeywords.findSegments( &mSegments, mWText, mDefaultColor );
+		mKeywords.findSegments( &mSegments, getWText(), mDefaultColor.get() );
 
 		llassert( mSegments.front()->getStart() == 0 );
 		llassert( mSegments.back()->getEnd() == getLength() );
@@ -3945,7 +3900,7 @@ void LLTextEditor::updateSegments()
 	if (mKeywords.isLoaded())
 	{
 		// HACK:  No non-ascii keywords for now
-		mKeywords.findSegments(&mSegments, mWText, mDefaultColor);
+		mKeywords.findSegments(&mSegments, getWText(), mDefaultColor.get());
 	}
 	else if (mAllowEmbeddedItems)
 	{
@@ -3960,8 +3915,8 @@ void LLTextEditor::updateSegments()
 	}
 	if (mSegments.empty())
 	{
-		LLColor4& text_color = ( mReadOnly ? mReadOnlyFgColor : mFgColor );
-		LLTextSegment* default_segment = new LLTextSegment( text_color, 0, mWText.length() );
+		LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get() );
+		LLTextSegment* default_segment = new LLTextSegment( text_color, 0, getLength() );
 		default_segment->setIsDefault(TRUE);
 		mSegments.push_back(default_segment);
 	}
@@ -3971,7 +3926,7 @@ void LLTextEditor::updateSegments()
 // *NOTE: Using this will invalidate references to mSegments from mLineStartList.
 void LLTextEditor::pruneSegments()
 {
-	S32 len = mWText.length();
+	S32 len = getLength();
 	// Find and update the first valid segment
 	segment_list_t::iterator iter = mSegments.end();
 	while(iter != mSegments.begin())
@@ -4008,7 +3963,7 @@ void LLTextEditor::findEmbeddedItemSegments()
 	mSegments.clear();
 
 	BOOL found_embedded_items = FALSE;
-	const LLWString &text = mWText;
+	LLWString text = getWText();
 	S32 idx = 0;
 	while( text[idx] )
 	{
@@ -4029,7 +3984,7 @@ void LLTextEditor::findEmbeddedItemSegments()
 
 	BOOL in_text = FALSE;
 
-	LLColor4& text_color = ( mReadOnly ? mReadOnlyFgColor : mFgColor  );
+	LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get()  );
 
 	if( idx > 0 )
 	{
@@ -4222,7 +4177,7 @@ BOOL LLTextEditor::exportBuffer(std::string &buffer )
 	outstream << "Linden text version 1\n";
 	outstream << "{\n";
 
-	outstream << llformat("Text length %d\n", mWText.length() );
+	outstream << llformat("Text length %d\n", getLength() );
 	outstream << getText();
 	outstream << "}\n";
 
@@ -4297,103 +4252,6 @@ void LLTextSegment::dump() const
 
 }
 
-// virtual
-LLXMLNodePtr LLTextEditor::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLUICtrl::getXML();
-
-	// Attributes
-
-	node->createChild("max_length", TRUE)->setIntValue(getMaxLength());
-	node->createChild("embedded_items", TRUE)->setBoolValue(mAllowEmbeddedItems);
-	node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont));
-	node->createChild("word_wrap", TRUE)->setBoolValue(mWordWrap);
-	node->createChild("hide_scrollbar", TRUE)->setBoolValue(mHideScrollbarForShortDocs);
-
-	addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor");
-	addColorXML(node, mFgColor, "text_color", "TextFgColor");
-	addColorXML(node, mDefaultColor, "text_default_color", "TextDefaultColor");
-	addColorXML(node, mReadOnlyFgColor, "text_readonly_color", "TextFgReadOnlyColor");
-	addColorXML(node, mReadOnlyBgColor, "bg_readonly_color", "TextBgReadOnlyColor");
-	addColorXML(node, mWriteableBgColor, "bg_writeable_color", "TextBgWriteableColor");
-	addColorXML(node, mFocusBgColor, "bg_focus_color", "TextBgFocusColor");
-
-	// Contents
- 	node->setStringValue(getText());
-
-	return node;
-}
-
-// static
-LLView* LLTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("text_editor");
-	node->getAttributeString("name", name);
-
-	LLRect rect;
-	createRect(node, rect, parent, LLRect());
-
-	U32 max_text_length = 255;
-	node->getAttributeU32("max_length", max_text_length);
-
-	BOOL allow_embedded_items;
-	node->getAttributeBOOL("embedded_items", allow_embedded_items);
-
-	LLFontGL* font = LLView::selectFont(node);
-
-	std::string text = node->getTextContents().substr(0, max_text_length - 1);
-
-	LLTextEditor* text_editor = new LLTextEditor(name, 
-								rect,
-								max_text_length,
-								text,
-								font,
-								allow_embedded_items);
-
-	text_editor->setTextEditorParameters(node);
-
-	BOOL hide_scrollbar = FALSE;
-	node->getAttributeBOOL("hide_scrollbar",hide_scrollbar);
-	text_editor->setHideScrollbarForShortDocs(hide_scrollbar);
-
-	text_editor->initFromXML(node, parent);
-
-	return text_editor;
-}
-
-void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
-{
-	BOOL word_wrap = FALSE;
-	node->getAttributeBOOL("word_wrap", word_wrap);
-	setWordWrap(word_wrap);
-
-	node->getAttributeBOOL("show_line_numbers", mShowLineNumbers);
-
-	node->getAttributeBOOL("track_bottom", mTrackBottom);
-
-	LLColor4 color;
-	if (LLUICtrlFactory::getAttributeColor(node,"cursor_color", color)) 
-	{
-		setCursorColor(color);
-	}
-	if(LLUICtrlFactory::getAttributeColor(node,"text_color", color))
-	{
-		setFgColor(color);
-	}
-	if(LLUICtrlFactory::getAttributeColor(node,"text_readonly_color", color))
-	{
-		setReadOnlyFgColor(color);
-	}
-	if(LLUICtrlFactory::getAttributeColor(node,"bg_readonly_color", color))
-	{
-		setReadOnlyBgColor(color);
-	}
-	if(LLUICtrlFactory::getAttributeColor(node,"bg_writeable_color", color))
-	{
-		setWriteableBgColor(color);
-	}
-}
-
 ///////////////////////////////////////////////////////////////////
 // Refactoring note: We may eventually want to replace this with boost::regex or 
 // boost::tokenizer capabilities since we've already fixed at least two JIRAs
@@ -4559,13 +4417,19 @@ BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const
 
 void LLTextEditor::updateAllowingLanguageInput()
 {
+	LLWindow* window = getWindow();
+	if (!window)
+	{
+		// test app, no window available
+		return;	
+	}
 	if (hasFocus() && !mReadOnly)
 	{
-		getWindow()->allowLanguageTextInput(this, TRUE);
+		window->allowLanguageTextInput(this, TRUE);
 	}
 	else
 	{
-		getWindow()->allowLanguageTextInput(this, FALSE);
+		window->allowLanguageTextInput(this, FALSE);
 	}
 }
 
@@ -4694,7 +4558,8 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
 		current_line++;
 	}
 
-	const llwchar * const text = mWText.c_str();
+    const LLWString textString(getWText());
+	const llwchar * const text = textString.c_str();
 	const S32 line_height = llround(mGLFont->getLineHeight());
 
 	if (coord)
@@ -4772,7 +4637,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length)
 	{
 		llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl;
 	}
-	mPreeditWString = LLWString( mWText, position, length );
+	mPreeditWString = LLWString( getWText(), position, length );
 	if (length > 0)
 	{
 		mPreeditPositions.resize(2);
@@ -4800,3 +4665,8 @@ S32 LLTextEditor::getPreeditFontSize() const
 {
 	return llround(mGLFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
 }
+
+LLWString       LLTextEditor::getWText() const
+{
+    return getViewModel()->getDisplay();
+}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 9291e1c436..efedb30f47 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -43,18 +43,79 @@
 #include "llstyle.h"
 #include "lleditmenuhandler.h"
 #include "lldarray.h"
+#include "llviewborder.h" // for params
 
 #include "llpreeditor.h"
+#include "llcontrol.h"
 
 class LLFontGL;
 class LLScrollbar;
-class LLViewBorder;
 class LLKeywordToken;
 class LLTextCmd;
 class LLUICtrlFactory;
 
 class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 {
+public:
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<std::string>	default_text;
+		Optional<S32>			max_text_length;
+
+		Optional<bool>			read_only,
+								allow_embedded_items,
+								hide_scrollbar,
+								word_wrap,
+								ignore_tab,
+								hide_border,
+								track_bottom,
+								takes_non_scroll_clicks;
+
+		//colors
+		Optional<LLUIColor>		cursor_color,
+								default_color,
+								text_color,
+								text_readonly_color,
+								bg_readonly_color,
+								bg_writeable_color,
+								bg_focus_color;
+
+		Optional<LLViewBorder::Params> border;
+
+		Deprecated				type,
+								length,
+								is_unicode;
+
+
+		Params()
+		:	max_text_length("max_length", 255),
+			read_only("read_only", false),
+			allow_embedded_items("embedded_items", false),
+			hide_scrollbar("hide_scrollbar", false),
+			hide_border("hide_border", false),
+			word_wrap("word_wrap", false),
+			ignore_tab("ignore_tab", true),
+			track_bottom("track_bottom", false),
+			takes_non_scroll_clicks("takes_non_scroll_clicks", true),
+			cursor_color("cursor_color"),
+			default_color("default_color"),
+			text_color("text_color"),
+			text_readonly_color("text_readonly_color"),
+			bg_readonly_color("bg_readonly_color"),
+			bg_writeable_color("bg_writeable_color"),
+			bg_focus_color("bg_focus_color"),
+			length("length"),
+			type("type"),
+			is_unicode("is_unicode")
+		{}
+			
+			
+	};
+
+	void initFromParams(const Params&);
+protected:
+	LLTextEditor(const Params&);
+	friend class LLUICtrlFactory;
 public:
 	//
 	// Constants
@@ -63,18 +124,8 @@ public:
 	static const llwchar LAST_EMBEDDED_CHAR =  0x10ffff;
 	static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1;
 
-	LLTextEditor(const std::string& name,
-				 const LLRect& rect,
-				 S32 max_length,
-				 const std::string &default_text, 
-				 const LLFontGL* glfont = NULL,
-				 BOOL allow_embedded_items = FALSE);
-
 	virtual ~LLTextEditor();
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
-	void    setTextEditorParameters(LLXMLNodePtr node);
 	void	setParseHTML(BOOL parsing) {mParseHTML=parsing;}
 	void	setParseHighlights(BOOL parsing) {mParseHighlights=parsing;}
 
@@ -195,8 +246,6 @@ public:
 	void 			setReadOnlyBgColor( const LLColor4& c )		{ mReadOnlyBgColor = c; }
 	void			setTrackColor( const LLColor4& color );
 	void			setThumbColor( const LLColor4& color );
-	void			setHighlightColor( const LLColor4& color );
-	void			setShadowColor( const LLColor4& color );
 
 	// Hacky methods to make it into a word-wrapping, potentially scrolling,
 	// read-only text box.
@@ -235,9 +284,8 @@ public:
 
 	// new methods
 	void 			setValue(const LLSD& value);
-	LLSD 			getValue() const;
 
- 	const std::string&	getText() const;
+ 	std::string     getText() const;
 	
 	// Non-undoable
 	void			setText(const LLStringExplicit &utf8str);
@@ -255,9 +303,9 @@ public:
 	BOOL			isScrolledToBottom();
 
 	// Getters
-	const LLWString& getWText() const { return mWText; }
-	llwchar			getWChar(S32 pos) const { return mWText[pos]; }
-	LLWString		getWSubString(S32 pos, S32 len) const { return mWText.substr(pos, len); }
+	LLWString       getWText() const;
+	llwchar			getWChar(S32 pos) const { return getWText()[pos]; }
+	LLWString		getWSubString(S32 pos, S32 len) const { return getWText().substr(pos, len); }
 	
 	const LLTextSegment*	getCurrentSegment() const { return getSegmentAtOffset(mCursorPos); }
 	const LLTextSegment*	getPreviousSegment() const;
@@ -270,7 +318,7 @@ protected:
 	// Methods
 	//
 
-	S32				getLength() const { return mWText.length(); }
+	S32				getLength() const { return getWText().length(); }
 	void			getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const;
 	void			drawPreeditMarker();
 
@@ -439,8 +487,10 @@ private:
 	//
 	// Methods
 	//
-	void	                pasteHelper(bool is_primary);
+	void	        pasteHelper(bool is_primary);
 
+	virtual 		LLTextViewModel* getViewModel() const;
+					
 	void			updateSegments();
 	void			pruneSegments();
 
@@ -473,13 +523,10 @@ private:
 	class LLTextCmdOverwriteChar;
 	class LLTextCmdRemove;
 
-	LLWString		mWText;
-	mutable std::string mUTF8Text;
-	mutable BOOL	mTextIsUpToDate;
-	
 	S32				mMaxTextByteLength;		// Maximum length mText is allowed to be in bytes
 
 	const LLFontGL*	mGLFont;
+	U8              mGLFontStyle; // the font style from xml
 
 	class LLViewBorder*	mBorder;
 
@@ -519,14 +566,13 @@ private:
 
 	LLFrameTimer	mKeystrokeTimer;
 
-	LLColor4		mCursorColor;
-
-	LLColor4		mFgColor;
-	LLColor4		mDefaultColor;
-	LLColor4		mReadOnlyFgColor;
-	LLColor4		mWriteableBgColor;
-	LLColor4		mReadOnlyBgColor;
-	LLColor4		mFocusBgColor;
+	LLUIColor	mCursorColor;
+	LLUIColor	mFgColor;
+	LLUIColor	mDefaultColor;
+	LLUIColor	mReadOnlyFgColor;
+	LLUIColor	mWriteableBgColor;
+	LLUIColor	mReadOnlyBgColor;
+	LLUIColor	mFocusBgColor;
 
 	BOOL			mReadOnly;
 	BOOL			mWordWrap;
diff --git a/indra/llui/lltextparser.cpp b/indra/llui/lltextparser.cpp
index 227d24a865..707dd0afdd 100644
--- a/indra/llui/lltextparser.cpp
+++ b/indra/llui/lltextparser.cpp
@@ -1,10 +1,9 @@
 /** 
- * @file lltexteditor.cpp
- * @brief LLTextEditor base class
+ * @file lltextparser.cpp
  *
  * $LicenseInfo:firstyear=2001&license=viewergpl$
  * 
- * Copyright (c) 2001-2007, Linden Research, Inc.
+ * Copyright (c) 2001-2009, Linden Research, Inc.
  * 
  * Second Life Viewer Source Code
  * The source code in this file ("Source Code") is provided by Linden Lab
@@ -12,12 +11,13 @@
  * ("GPL"), unless you have obtained a separate licensing agreement
  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  * 
  * There are special exceptions to the terms and conditions of the GPL as
  * it is applied to this Source Code. View the full text of the exception
  * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  * 
  * By copying, modifying or distributing this software, you acknowledge
  * that you have read and understood your obligations described above,
@@ -31,6 +31,8 @@
 
 #include "linden_common.h"
 
+#include "lltextparser.h"
+
 #include "llsd.h"
 #include "llsdserialize.h"
 #include "llerror.h"
@@ -39,22 +41,12 @@
 #include "message.h"
 #include "llmath.h"
 #include "v4color.h"
-#include "audioengine.h"
-#include "llwindow.h"
 #include "lldir.h"
 
-#include "lltextparser.h"
-//#include "lltexttospeech.h"
-
 // Routines used for parsing text for TextParsers and html
 
 LLTextParser* LLTextParser::sInstance = NULL;
 
-//
-// Constants
-//
-const F32 SOUND_GAIN = 1.0f;
-
 //
 // Member Functions
 //
@@ -75,38 +67,7 @@ LLTextParser* LLTextParser::getInstance()
 	return sInstance;
 }
 
-void LLTextParser::triggerAlerts(LLUUID agent_id, LLVector3d position, std::string text, LLWindow* viewer_window)
-{
-//    bool spoken=FALSE;
-	for (S32 i=0;i<mHighlights.size();i++)
-	{
-		if (findPattern(text,mHighlights[i]) >= 0 )
-		{
-			if(gAudiop)
-			{
-				if ((std::string)mHighlights[i]["sound_lluuid"] != LLUUID::null.asString())
-				{
-					gAudiop->triggerSound(mHighlights[i]["sound_lluuid"].asUUID(), agent_id, SOUND_GAIN, LLAudioEngine::AUDIO_TYPE_UI, position);
-				}
-/*				
-				if (!spoken) 
-				{
-					LLTextToSpeech* text_to_speech = NULL;
-					text_to_speech = LLTextToSpeech::getInstance();
-					spoken = text_to_speech->speak((LLString)mHighlights[i]["voice"],text); 
-				}
- */
-			}
-			if (mHighlights[i]["flash"])
-			{
-				if (viewer_window && viewer_window->getMinimized())
-				{
-					viewer_window->flashIcon(5.f);
-				}
-			}
-		}
-	}
-}
+// Moved triggerAlerts() to llfloaterchat.cpp to break llui/llaudio library dependency.
 
 S32 LLTextParser::findPattern(const std::string &text, LLSD highlight)
 {
diff --git a/indra/llui/lltextparser.h b/indra/llui/lltextparser.h
index 5c5c3f3301..fb1a7758b7 100644
--- a/indra/llui/lltextparser.h
+++ b/indra/llui/lltextparser.h
@@ -3,6 +3,30 @@
  * @brief GUI for user-defined highlights
  *
  * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
  * $/LicenseInfo$
  *
  */
@@ -10,12 +34,10 @@
 #ifndef LL_LLTEXTPARSER_H
 #define LL_LLTEXTPARSER_H
 
-#include <vector>
-#include "linden_common.h"
-
 #include "lltextparser.h"
 
-class LLSD;
+#include "llsd.h"
+
 class LLUUID;
 class LLVector3d;
 class LLColor4;
@@ -35,13 +57,13 @@ public:
 	S32  findPattern(const std::string &text, LLSD highlight);
 	LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color,S32 part=WHOLE, S32 index=0);
 	bool parseFullLineHighlights(const std::string &text, LLColor4 *color);
-	void triggerAlerts(LLUUID agent_id, LLVector3d position, std::string text, LLWindow* viewer_window);
 
 	std::string getFileName();
 	LLSD loadFromDisk();
 	bool saveToDisk(LLSD highlights);
+
 public:
-		LLSD	mHighlights;
+	LLSD	mHighlights;
 private:
 	static LLTextParser* sInstance;
 };
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 57ce13c9c6..dfe435d2e3 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -52,8 +52,15 @@
 #include "llui.h"
 #include "llview.h"
 #include "lllineeditor.h"
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llmenugl.h"
 #include "llwindow.h"
 
+// for XUIParse
+#include "llquaternion.h"
+#include <boost/tokenizer.hpp>
+
 //
 // Globals
 //
@@ -65,18 +72,18 @@ BOOL gShowTextEditCursor = TRUE;
 // Language for UI construction
 std::map<std::string, std::string> gTranslation;
 std::list<std::string> gUntranslated;
+/*static*/ LLUI::settings_map_t LLUI::sSettingGroups;
+/*static*/ LLImageProviderInterface* LLUI::sImageProvider = NULL;
+/*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL;
+/*static*/ LLVector2		LLUI::sGLScaleFactor(1.f, 1.f);
+/*static*/ LLWindow*		LLUI::sWindow = NULL;
+/*static*/ LLHtmlHelp*		LLUI::sHtmlHelp = NULL;
+/*static*/ LLView*			LLUI::sRootView = NULL;
+/*static*/ BOOL            LLUI::sShowXUINames = FALSE;
+/*static*/ std::stack<LLRect> LLScreenClipRect::sClipRectStack;
+
+/*static*/ std::vector<std::string> LLUI::sXUIPaths;
 
-LLControlGroup* LLUI::sConfigGroup = NULL;
-LLControlGroup* LLUI::sIgnoresGroup = NULL;
-LLControlGroup* LLUI::sColorsGroup = NULL;
-LLImageProviderInterface* LLUI::sImageProvider = NULL;
-LLUIAudioCallback LLUI::sAudioCallback = NULL;
-LLVector2		LLUI::sGLScaleFactor(1.f, 1.f);
-LLWindow*		LLUI::sWindow = NULL;
-LLHtmlHelp*		LLUI::sHtmlHelp = NULL;
-BOOL            LLUI::sShowXUINames = FALSE;
-std::stack<LLRect> LLScreenClipRect::sClipRectStack;
-BOOL            LLUI::sQAMode = FALSE;
 
 //
 // Functions
@@ -84,18 +91,18 @@ BOOL            LLUI::sQAMode = FALSE;
 void make_ui_sound(const char* namep)
 {
 	std::string name = ll_safe_string(namep);
-	if (!LLUI::sConfigGroup->controlExists(name))
+	if (!LLUI::sSettingGroups["config"]->controlExists(name))
 	{
 		llwarns << "tried to make ui sound for unknown sound name: " << name << llendl;	
 	}
 	else
 	{
-		LLUUID uuid(LLUI::sConfigGroup->getString(name));		
+		LLUUID uuid(LLUI::sSettingGroups["config"]->getString(name));
 		if (uuid.isNull())
 		{
-			if (LLUI::sConfigGroup->getString(name) == LLUUID::null.asString())
+			if (LLUI::sSettingGroups["config"]->getString(name) == LLUUID::null.asString())
 			{
-				if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle"))
+				if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
 				{
 					llinfos << "ui sound name: " << name << " triggered but silent (null uuid)" << llendl;	
 				}				
@@ -108,7 +115,7 @@ void make_ui_sound(const char* namep)
 		}
 		else if (LLUI::sAudioCallback != NULL)
 		{
-			if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle"))
+			if (LLUI::sSettingGroups["config"]->getBOOL("UISndDebugSpamToggle"))
 			{
 				llinfos << "ui sound name: " << name << llendl;	
 			}
@@ -1554,21 +1561,18 @@ bool handleShowXUINamesChanged(const LLSD& newvalue)
 	return true;
 }
 
-void LLUI::initClass(LLControlGroup* config, 
-					 LLControlGroup* ignores, 
-					 LLControlGroup* colors, 
+void LLUI::initClass(const settings_map_t& settings,
 					 LLImageProviderInterface* image_provider,
 					 LLUIAudioCallback audio_callback,
 					 const LLVector2* scale_factor,
 					 const std::string& language)
 {
-	sConfigGroup = config;
-	sIgnoresGroup = ignores;
-	sColorsGroup = colors;
+	sSettingGroups = settings;
 
-	if (sConfigGroup == NULL
-		|| sIgnoresGroup == NULL
-		|| sColorsGroup == NULL)
+	if ((get_ptr_in_map(sSettingGroups, std::string("config")) == NULL) ||
+		(get_ptr_in_map(sSettingGroups, std::string("color")) == NULL) ||
+		(get_ptr_in_map(sSettingGroups, std::string("floater")) == NULL) ||
+		(get_ptr_in_map(sSettingGroups, std::string("ignores")) == NULL))
 	{
 		llerrs << "Failure to initialize configuration groups" << llendl;
 	}
@@ -1577,16 +1581,31 @@ void LLUI::initClass(LLControlGroup* config,
 	sAudioCallback = audio_callback;
 	sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor;
 	sWindow = NULL; // set later in startup
-	LLFontGL::sShadowColor = colors->getColor("ColorDropShadow");
+	LLFontGL::sShadowColor = LLUI::sSettingGroups["color"]->getColor("ColorDropShadow");
 
-	LLUI::sShowXUINames = LLUI::sConfigGroup->getBOOL("ShowXUINames");
-	LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(&handleShowXUINamesChanged);
+	static LLUICachedControl<bool> show_xui_names ("ShowXUINames", false);
+	LLUI::sShowXUINames = show_xui_names;
+	LLUI::sSettingGroups["config"]->getControl("ShowXUINames")->getSignal()->connect(boost::bind(&handleShowXUINamesChanged, _2));
+	
+	// Callbacks for associating controls with floater visibilty:
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Toggle", boost::bind(&LLFloaterReg::toggleFloaterInstance, _2));
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Show", boost::bind(&LLFloaterReg::showFloaterInstance, _2));
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.Hide", boost::bind(&LLFloaterReg::hideFloaterInstance, _2));
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Floater.InitToVisibilityControl", boost::bind(&LLFloaterReg::initUICtrlToFloaterVisibilityControl, _1, _2));
+	
+	// Button initialization callback for toggle buttons
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.SetFloaterToggle", boost::bind(&LLButton::setFloaterToggle, _1, _2));
+	
+	// Currently unused, but kept for reference:
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("Button.ToggleFloater", boost::bind(&LLButton::toggleFloaterAndSetToggleState, _1, _2));
+	
+	// Used by menus along with Floater.Toggle to display visibility as a checkmark
+	LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::floaterInstanceVisible, _2));
 }
 
 void LLUI::cleanupClass()
 {
 	sImageProvider->cleanUp();
-	LLLineEditor::cleanupLineEditor();
 }
 
 
@@ -1679,16 +1698,16 @@ void LLUI::getCursorPositionLocal(const LLView* viewp, S32 *x, S32 *y)
 std::string LLUI::getLanguage()
 {
 	std::string language = "en-us";
-	if (sConfigGroup)
+	if (sSettingGroups["config"])
 	{
-		language = sConfigGroup->getString("Language");
+		language = sSettingGroups["config"]->getString("Language");
 		if (language.empty() || language == "default")
 		{
-			language = sConfigGroup->getString("InstallLanguage");
+			language = sSettingGroups["config"]->getString("InstallLanguage");
 		}
 		if (language.empty() || language == "default")
 		{
-			language = sConfigGroup->getString("SystemLanguage");
+			language = sSettingGroups["config"]->getString("SystemLanguage");
 		}
 		if (language.empty() || language == "default")
 		{
@@ -1698,6 +1717,40 @@ std::string LLUI::getLanguage()
 	return language;
 }
 
+//static
+void LLUI::setupPaths()
+{
+	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "paths.xml");
+
+	LLXMLNodePtr root;
+	BOOL success  = LLXMLNode::parseFile(filename, root, NULL);
+	sXUIPaths.clear();
+	
+	if (success)
+	{
+		LLStringUtil::format_map_t path_args;
+		path_args["[LANGUAGE]"] = LLUI::getLanguage();
+		
+		for (LLXMLNodePtr path = root->getFirstChild(); path.notNull(); path = path->getNextSibling())
+		{
+			std::string path_val_ui(path->getValue());
+			LLStringUtil::format(path_val_ui, path_args);
+			if (std::find(sXUIPaths.begin(), sXUIPaths.end(), path_val_ui) == sXUIPaths.end())
+			{
+				sXUIPaths.push_back(path_val_ui);
+			}
+		}
+	}
+	else // parsing failed
+	{
+		std::string slash = gDirUtilp->getDirDelimiter();
+		std::string dir = "xui" + slash + "en-us";
+		llwarns << "XUI::config file unable to open: " << filename << llendl;
+		sXUIPaths.push_back(dir);
+	}
+}
+
+
 //static
 std::string LLUI::locateSkin(const std::string& filename)
 {
@@ -1707,7 +1760,7 @@ std::string LLUI::locateSkin(const std::string& filename)
 	{
 		found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS?
 	}
-	if (sConfigGroup && sConfigGroup->controlExists("Language"))
+	if (sSettingGroups["config"] && sSettingGroups["config"]->controlExists("Language"))
 	{
 		if (!gDirUtilp->fileExists(found_file))
 		{
@@ -1765,10 +1818,23 @@ void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen)
 	glPointToScreen(gl.mRight, gl.mBottom, &screen->mRight, &screen->mBottom);
 }
 
+//static
+LLPointer<LLUIImage> LLUI::getUIImageByID(const LLUUID& image_id)
+{
+	if (sImageProvider)
+	{
+		return sImageProvider->getUIImageByID(image_id);
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
 //static 
-LLUIImage* LLUI::getUIImage(const std::string& name)
+LLPointer<LLUIImage> LLUI::getUIImage(const std::string& name)
 {
-	if (!name.empty())
+	if (!name.empty() && sImageProvider)
 		return sImageProvider->getUIImage(name);
 	else
 		return NULL;
@@ -1780,10 +1846,23 @@ void LLUI::setHtmlHelp(LLHtmlHelp* html_help)
 	LLUI::sHtmlHelp = html_help;
 }
 
-//static 
-void LLUI::setQAMode(BOOL b)
+// static
+boost::function<const LLColor4&()> LLUI::getCachedColorFunctor(const std::string& color_name)
+{
+	return LLCachedControl<LLColor4>(*sSettingGroups["color"], color_name, LLColor4::magenta);
+}
+
+// static
+LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
 {
-	LLUI::sQAMode = b;
+	for (settings_map_t::iterator itor = sSettingGroups.begin();
+		 itor != sSettingGroups.end(); ++itor)
+	{
+		if (sSettingGroups[(itor->first)]->controlExists(controlname))
+			return *sSettingGroups[(itor->first)];
+	}
+
+	return *sSettingGroups["config"]; // default group
 }
 
 LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) : mScissorState(GL_SCISSOR_TEST), mEnabled(enabled)
@@ -1849,102 +1928,163 @@ LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled)
 {
 }
 
-
-//
-// LLUIImage
-//
-
-LLUIImage::LLUIImage(const std::string& name, LLPointer<LLImageGL> image) :
-						mName(name),
-						mImage(image),
-						mScaleRegion(0.f, 1.f, 1.f, 0.f),
-						mClipRegion(0.f, 1.f, 1.f, 0.f),
-						mUniformScaling(TRUE),
-						mNoClip(TRUE)
+namespace LLInitParam
 {
-}
+	TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLUIColor& value, ParamDescriptor::validation_func_t func)
+	:	super_t(descriptor, name, value, func),
+		red("red"),
+		green("green"),
+		blue("blue"),
+		alpha("alpha"),
+		control("")
+	{}
 
-void LLUIImage::setClipRegion(const LLRectf& region) 
-{ 
-	mClipRegion = region; 
-	mNoClip = mClipRegion.mLeft == 0.f
-				&& mClipRegion.mRight == 1.f
-				&& mClipRegion.mBottom == 0.f
-				&& mClipRegion.mTop == 1.f;
-}
+	LLUIColor TypedParam<LLUIColor>::getValueFromBlock() const
+	{
+		if (control.isProvided())
+		{
+			return LLUI::getCachedColorFunctor(control);
+		}
+		else
+		{
+			return LLColor4(red, green, blue, alpha);
+		}
+	}
 
-void LLUIImage::setScaleRegion(const LLRectf& region) 
-{ 
-	mScaleRegion = region; 
-	mUniformScaling = mScaleRegion.mLeft == 0.f
-					&& mScaleRegion.mRight == 1.f
-					&& mScaleRegion.mBottom == 0.f
-					&& mScaleRegion.mTop == 1.f;
-}
+	void TypeValues<LLUIColor>::declareValues()
+	{
+		declare("white", LLColor4::white);
+		declare("black", LLColor4::black);
+		declare("red", LLColor4::red);
+		declare("green", LLColor4::green);
+		declare("blue", LLColor4::blue);
+	}
 
-//TODO: move drawing implementation inside class
-void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const
-{
-	gl_draw_image(x, y, mImage, color, mClipRegion);
-}
+	TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLFontGL*const value, ParamDescriptor::validation_func_t func)
+	:	super_t(descriptor, name, value, func),
+		name("", std::string("")),
+		size("size", std::string("")),
+		style("style", std::string(""))
+	{}
 
-void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const
-{
-	if (mUniformScaling)
+	const LLFontGL* TypedParam<const LLFontGL*>::getValueFromBlock() const
 	{
-		gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion);
+		if (name.isProvided())
+		{
+			const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
+			if (res_fontp)
+			{
+				return res_fontp;
+			}
+
+			U8 fontstyle = 0;
+			fontstyle = LLFontGL::getStyleFromString(style());
+			LLFontDescriptor desc(name(), size(), fontstyle);
+			const LLFontGL* fontp = LLFontGL::getFont(desc);
+			if (fontp)
+			{
+				return fontp;
+			}
+		}
+
+		// default to current value
+		return mData.mValue;
 	}
-	else
+
+	TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLRect& value, ParamDescriptor::validation_func_t func)
+	:	super_t(descriptor, name, value, func),
+		left("left"),
+		top("top"),
+		right("right"),
+		bottom("bottom"),
+		width("width"),
+		height("height")
+	{}
+
+	LLRect TypedParam<LLRect>::getValueFromBlock() const
 	{
-		gl_draw_scaled_image_with_border(
-			x, y, 
-			width, height, 
-			mImage, 
-			color,
-			FALSE,
-			mClipRegion,
-			mScaleRegion);
-	}
-}
+		LLRect rect;
 
-void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const
-{
-	gl_draw_scaled_image_with_border(
-		x, y, 
-		width, height, 
-		mImage, 
-		color, 
-		TRUE,
-		mClipRegion,
-		mScaleRegion);
-}
+		//calculate from params
+		// prefer explicit left and right
+		if (left.isProvided() && right.isProvided())
+		{
+			rect.mLeft = left;
+			rect.mRight = right;
+		}
+		// otherwise use width along with specified side, if any
+		else if (width.isProvided())
+		{
+			// only right + width provided
+			if (right.isProvided())
+			{
+				rect.mRight = right;
+				rect.mLeft = right - width;
+			}
+			else // left + width, or just width
+			{
+				rect.mLeft = left;
+				rect.mRight = left + width;
+			}
+		}
+		// just left, just right, or none
+		else
+		{
+			rect.mLeft = left;
+			rect.mRight = right;
+		}
 
-void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const
-{
-	LLRect border_rect;
-	border_rect.setOriginAndSize(x, y, width, height);
-	border_rect.stretch(border_width, border_width);
-	drawSolid(border_rect, color);
-}
+		// prefer explicit bottom and top
+		if (bottom.isProvided() && top.isProvided())
+		{
+			rect.mBottom = bottom;
+			rect.mTop = top;
+		}
+		// otherwise height along with specified side, if any
+		else if (height.isProvided())
+		{
+			// top + height provided
+			if (top.isProvided())
+			{
+				rect.mTop = top;
+				rect.mBottom = top - height;
+			}
+			// bottom + height or just height
+			else
+			{
+				rect.mBottom = bottom;
+				rect.mTop = bottom + height;
+			}
+		}
+		// just bottom, just top, or none
+		else
+		{
+			rect.mBottom = bottom;
+			rect.mTop = top;
+		}
+		return rect;
+	}
 
-S32 LLUIImage::getWidth() const
-{ 
-	// return clipped dimensions of actual image area
-	return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth()); 
-}
+	void TypeValues<LLFontGL::HAlign>::declareValues()
+	{
+		declare("left", LLFontGL::LEFT);
+		declare("right", LLFontGL::RIGHT);
+		declare("center", LLFontGL::HCENTER);
+	}
 
-S32 LLUIImage::getHeight() const
-{ 
-	// return clipped dimensions of actual image area
-	return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight()); 
-}
+	void TypeValues<LLFontGL::VAlign>::declareValues()
+	{
+		declare("top", LLFontGL::TOP);
+		declare("center", LLFontGL::VCENTER);
+		declare("baseline", LLFontGL::BASELINE);
+		declare("bottom", LLFontGL::BOTTOM);
+	}
 
-S32 LLUIImage::getTextureWidth() const
-{
-	return mImage->getWidth(0);
+	void TypeValues<LLFontGL::ShadowType>::declareValues()
+	{
+		declare("none", LLFontGL::NO_SHADOW);
+		declare("hard", LLFontGL::DROP_SHADOW);
+		declare("soft", LLFontGL::DROP_SHADOW_SOFT);
+	}
 }
 
-S32 LLUIImage::getTextureHeight() const
-{
-	return mImage->getHeight(0);
-}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index ebcc7304b1..b5a42bce13 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -35,28 +35,34 @@
 #ifndef LL_LLUI_H
 #define LL_LLUI_H
 
+#include "llpointer.h"		// LLPointer<>
 #include "llrect.h"
 #include "llcontrol.h"
-#include "llrect.h"
 #include "llcoord.h"
 //#include "llhtmlhelp.h"
 #include "llgl.h"			// *TODO: break this dependency
 #include <stack>
-//#include "llimagegl.h"
+#include "lluiimage.h"		// *TODO: break this dependency, need to add #include "lluiimage.h" to all widgets that hold an Optional<LLUIImage*> in their paramblocks
+#include "llinitparam.h"
+#include "llregistry.h"
 #include <boost/signal.hpp>
+#include "lllazyvalue.h"
 
 // LLUIFactory
 #include "llsd.h"
 
+// for initparam specialization
+#include "llfontgl.h"
+
 class LLColor4; 
 class LLHtmlHelp;
 class LLImageGL;
 class LLVector3;
 class LLVector2;
+class LLUIImage;
 class LLUUID;
 class LLWindow;
 class LLView;
-class LLUIImage;
 
 // UI colors
 extern const LLColor4 UI_VERTEX_COLOR;
@@ -157,9 +163,8 @@ public:
 	//
 	// Methods
 	//
-	static void initClass(LLControlGroup* config, 
-						  LLControlGroup* ignores,
-						  LLControlGroup* colors, 
+	typedef std::map<std::string, LLControlGroup*> settings_map_t;
+	static void initClass(const settings_map_t& settings,
 						  LLImageProviderInterface* image_provider,
 						  LLUIAudioCallback audio_callback = NULL,
 						  const LLVector2 *scale_factor = NULL,
@@ -174,41 +179,45 @@ public:
 	// Return the ISO639 language name ("en", "ko", etc.) for the viewer UI.
 	// http://www.loc.gov/standards/iso639-2/php/code_list.php
 	static std::string getLanguage();
-
+	
+	static void setupPaths();
+	static const std::vector<std::string>& getXUIPaths() { return sXUIPaths; }
+	static std::string getSkinPath() { return sXUIPaths.front(); }
+	
 	//helper functions (should probably move free standing rendering helper functions here)
+	static LLView* getRootView() { return sRootView; }
+	static void setRootView(LLView* view) { sRootView = view; }
 	static std::string locateSkin(const std::string& filename);
 	static void setCursorPositionScreen(S32 x, S32 y);
 	static void setCursorPositionLocal(const LLView* viewp, S32 x, S32 y);
 	static void getCursorPositionLocal(const LLView* viewp, S32 *x, S32 *y);
 	static void setScaleFactor(const LLVector2& scale_factor);
 	static void setLineWidth(F32 width);
-	static LLUIImage* getUIImage(const std::string& name);
+	static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id);
+	static LLPointer<LLUIImage> getUIImage(const std::string& name);
 	static LLVector2 getWindowSize();
 	static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
 	static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
 	static void screenRectToGL(const LLRect& screen, LLRect *gl);
 	static void glRectToScreen(const LLRect& gl, LLRect *screen);
 	static void setHtmlHelp(LLHtmlHelp* html_help);
-
+	static boost::function<const LLColor4&()> getCachedColorFunctor(const std::string& color_name);
+	// Returns the control group containing the control name, or the default group
+	static LLControlGroup& getControlControlGroup (const std::string& controlname);
+	
 	//
 	// Data
 	//
-	static LLControlGroup* sConfigGroup;
-	static LLControlGroup* sIgnoresGroup;
-	static LLControlGroup* sColorsGroup;
-	static LLImageProviderInterface* sImageProvider;
+	static settings_map_t sSettingGroups;
 	static LLUIAudioCallback sAudioCallback;
 	static LLVector2		sGLScaleFactor;
 	static LLWindow*		sWindow;
 	static BOOL             sShowXUINames;
 	static LLHtmlHelp*		sHtmlHelp;
-
-	// *TODO: remove the following when QAR-369 settings clean-up work is in.
-	// Also remove the call to this method which will then be obsolete.
-	// Search for QAR-369 below to enable the proper accessing of this feature. -MG
-	static void setQAMode(BOOL b);
-	static BOOL sQAMode;
-
+	static LLView*			sRootView;
+private:
+	static LLImageProviderInterface* sImageProvider;
+	static std::vector<std::string> sXUIPaths;
 };
 
 //	FactoryPolicy is a static class that controls the creation and lookup of UI elements, 
@@ -365,7 +374,6 @@ protected:
 
 	// T must derive from LLUISingleton<T>
 	LLUISingleton() { sInstance = static_cast<T*>(this); }
-
 	~LLUISingleton() { sInstance = NULL; }
 
 public:
@@ -383,6 +391,12 @@ public:
 		return sInstance;
 	}
 
+	static void destroyInstance()
+	{
+		delete sInstance;
+		sInstance = NULL;
+	}
+	
 private:
 	static T*	sInstance;
 };
@@ -413,49 +427,6 @@ public:
 	LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
 };
 
-class LLUIImage : public LLRefCount
-{
-public:
-	LLUIImage(const std::string& name, LLPointer<LLImageGL> image);
-
-	void setClipRegion(const LLRectf& region);
-	void setScaleRegion(const LLRectf& region);
-
-	LLPointer<LLImageGL> getImage() { return mImage; }
-	const LLPointer<LLImageGL>& getImage() const { return mImage; }
-
-	void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const;
-	void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const;
-	void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); }
-	
-	void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const;
-	void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); }
-	void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, mImage->getWidth(0), mImage->getHeight(0), color); }
-
-	void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const;
-	void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); }
-	void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, mImage->getWidth(0), mImage->getHeight(0), color, border_width); }
-	
-	const std::string& getName() const { return mName; }
-
-	S32 getWidth() const;
-	S32 getHeight() const;
-
-	// returns dimensions of underlying textures, which might not be equal to ui image portion
-	S32 getTextureWidth() const;
-	S32 getTextureHeight() const;
-
-protected:
-	std::string			mName;
-	LLRectf				mScaleRegion;
-	LLRectf				mClipRegion;
-	LLPointer<LLImageGL> mImage;
-	BOOL				mUniformScaling;
-	BOOL				mNoClip;
-};
-
-typedef LLPointer<LLUIImage> LLUIImagePtr;
-
 template <typename T>
 class LLTombStone : public LLRefCount
 {
@@ -593,71 +564,15 @@ private:
 //RN: maybe this needs to moved elsewhere?
 class LLImageProviderInterface
 {
-public:
+protected:
 	LLImageProviderInterface() {};
 	virtual ~LLImageProviderInterface() {};
-
-	virtual LLUIImagePtr getUIImage(const std::string& name) = 0;
-	virtual LLUIImagePtr getUIImageByID(const LLUUID& id) = 0;
-	virtual void cleanUp() = 0;
-};
-
-// This mix-in class adds support for tracking all instances of the specificed class parameter T
-// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
-// If KEY is not provided, then instances are stored in a simple list
-template<typename T, typename KEY = T*>
-class LLInstanceTracker : boost::noncopyable
-{
 public:
-	typedef typename std::map<KEY, T*>::iterator instance_iter;
-	typedef typename std::map<KEY, T*>::const_iterator instance_const_iter;
-
-	static T* getInstance(KEY k) { instance_iter found = sInstances.find(k); return (found == sInstances.end()) ? NULL : found->second; }
-
-	static instance_iter beginInstances() { return sInstances.begin(); }
-	static instance_iter endInstances() { return sInstances.end(); }
-	static S32 instanceCount() { return sInstances.size(); }
-protected:
-	LLInstanceTracker(KEY key) { add(key); }
-	virtual ~LLInstanceTracker() { remove(); }
-	virtual void setKey(KEY key) { remove(); add(key); }
-	virtual const KEY& getKey() const { return mKey; }
-
-private:
-	void add(KEY key) 
-	{ 
-		mKey = key; 
-		sInstances[key] = static_cast<T*>(this); 
-	}
-	void remove() { sInstances.erase(mKey); }
-
-private:
-
-	KEY mKey;
-	static std::map<KEY, T*> sInstances;
-};
-
-template<typename T>
-class LLInstanceTracker<T, T*> : boost::noncopyable
-{
-public:
-	typedef typename std::set<T*>::iterator instance_iter;
-	typedef typename std::set<T*>::const_iterator instance_const_iter;
-
-	static instance_iter instancesBegin() { return sInstances.begin(); }
-	static instance_iter instancesEnd() { return sInstances.end(); }
-	static S32 instanceCount() { return sInstances.size(); }
-
-protected:
-	LLInstanceTracker() { sInstances.insert(static_cast<T*>(this)); }
-	virtual ~LLInstanceTracker() { sInstances.erase(static_cast<T*>(this)); }
-
-	static std::set<T*> sInstances;
+	virtual LLPointer<LLUIImage> getUIImage(const std::string& name) = 0;
+	virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id) = 0;
+	virtual void cleanUp() = 0;
 };
 
-template <typename T, typename KEY> std::map<KEY, T*> LLInstanceTracker<T, KEY>::sInstances;
-template <typename T> std::set<T*> LLInstanceTracker<T, T*>::sInstances;
-
 class LLCallbackRegistry
 {
 public:
@@ -746,93 +661,116 @@ private:
 template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(&T::initClass);
 template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(&T::destroyClass);
 
+// useful parameter blocks
+struct TimeIntervalParam : public LLInitParam::Choice<TimeIntervalParam>
+{
+	Option<F32>		seconds;
+	Option<S32>		frames;
+	TimeIntervalParam()
+	:	seconds("seconds"),
+		frames("frames")
+	{}
+};
 
-template <typename DERIVED>
-class LLParamBlock
+template <class T>
+class LLUICachedControl : public LLCachedControl<T>
 {
-protected:
-	LLParamBlock() { sBlock = (DERIVED*)this; }
+public:
+	// This constructor will declare a control if it doesn't exist in the contol group
+	LLUICachedControl(const std::string& name,
+					  const T& default_value,
+					  const std::string& comment = "Declared In Code")
+	:	LLCachedControl<T>(LLUI::getControlControlGroup(name), name, default_value, comment)
+	{}
+
+	// This constructor will signal an error if the control doesn't exist in the control group
+	LLUICachedControl(const std::string& name)
+	:	LLCachedControl<T>(LLUI::getControlControlGroup(name), name)
+	{}
+};
 
-	typedef typename boost::add_const<DERIVED>::type Tconst;
+typedef LLLazyValue<LLColor4> LLUIColor;
 
-	template <typename T>
-	class LLMandatoryParam
+namespace LLInitParam
+{
+	template<>
+	class TypedParam<LLRect> 
+	:	public BlockValue<LLRect>
 	{
+        typedef BlockValue<LLRect> super_t;
 	public:
-		typedef typename boost::add_const<T>::type T_const;
+		Optional<S32>	left,
+						top,
+						right,
+						bottom,
+						width,
+						height;
 
-		LLMandatoryParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
-		LLMandatoryParam(const LLMandatoryParam<T>& other) : mVal(other.mVal) {}
+		TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLRect& value, ParamDescriptor::validation_func_t func);
 
-		DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
-		operator T() const { return mVal; } 
-		T operator=(T_const set_value) { mVal = set_value; return mVal; }
+		LLRect getValueFromBlock() const;
+	};
 
-	private: 
-		T	mVal;
-		DERIVED* mBlock;
+	template<>
+	struct TypeValues<LLUIColor> : public TypeValuesHelper<LLUIColor>
+	{
+		static void declareValues();
 	};
 
-	template <typename T>
-	class LLOptionalParam
+	template<>
+	class TypedParam<LLUIColor> 
+	:	public BlockValue<LLUIColor>
 	{
+        typedef BlockValue<LLUIColor> super_t;
 	public:
-		typedef typename boost::add_const<T>::type T_const;
-
-		LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
-		LLOptionalParam() : mBlock(sBlock) {}
-		LLOptionalParam(const LLOptionalParam<T>& other) : mVal(other.mVal) {}
-
-		DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
-		operator T() const { return mVal; } 
-		T operator=(T_const set_value) { mVal = set_value; return mVal; }
-
-	private:
-		T	mVal;
-		DERIVED* mBlock;
+		Optional<F32> red;
+		Optional<F32> green;
+		Optional<F32> blue;
+		Optional<F32> alpha;
+		Optional<std::string> control;
+
+		TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLUIColor& value, ParamDescriptor::validation_func_t func);
+		LLUIColor getValueFromBlock() const;
 	};
 
-	// specialization that requires initialization for reference types 
-	template <typename T>
-	class LLOptionalParam <T&>
+	template<>
+	class TypedParam<const LLFontGL*> 
+	:	public BlockValue<const LLFontGL*>
 	{
+        typedef BlockValue<const LLFontGL*> super_t;
 	public:
-		typedef typename boost::add_const<T&>::type T_const;
+		Optional<std::string> name;
+		Optional<std::string> size;
+		Optional<std::string> style;
 
-		LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
-		LLOptionalParam(const LLOptionalParam<T&>& other) : mVal(other.mVal) {}
-
-		DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
-		operator T&() const { return mVal; } 
-		T& operator=(T_const set_value) { mVal = set_value; return mVal; }
+		TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLFontGL* const value, ParamDescriptor::validation_func_t func);
+		const LLFontGL* getValueFromBlock() const;
+	};
 
-	private:
-		T&	mVal;
-		DERIVED* mBlock;
+	template<>
+	struct TypeValues<LLFontGL::HAlign> : public TypeValuesHelper<LLFontGL::HAlign>
+	{
+		static void declareValues();
 	};
 
-	// specialization that initializes pointer params to NULL
-	template<typename T> 
-	class LLOptionalParam<T*>
+	template<>
+	struct TypeValues<LLFontGL::VAlign> : public TypeValuesHelper<LLFontGL::VAlign>
 	{
-	public:
-		typedef typename boost::add_const<T*>::type T_const;
-
-		LLOptionalParam(T_const initial_val) : mVal(initial_val), mBlock(sBlock) {}
-		LLOptionalParam() : mVal((T*)NULL), mBlock(sBlock)  {}
-		LLOptionalParam(const LLOptionalParam<T*>& other) : mVal(other.mVal) {}
-
-		DERIVED& operator ()(T_const set_value) { mVal = set_value; return *mBlock; }
-		operator T*() const { return mVal; } 
-		T* operator=(T_const set_value) { mVal = set_value; return mVal; }
-	private:
-		T*	mVal;
-		DERIVED* mBlock;
+		static void declareValues();
 	};
 
-	static DERIVED* sBlock;
-};
+	template<>
+	struct TypeValues<LLFontGL::ShadowType> : public TypeValuesHelper<LLFontGL::ShadowType>
+	{
+		static void declareValues();
+	};
+}
 
-template <typename T> T* LLParamBlock<T>::sBlock = NULL;
+namespace LLInitParam
+{
+    template<>
+	bool ParamCompare<LLLazyValue<LLColor4> >::equals(
+		const LLLazyValue<LLColor4> &a, const LLLazyValue<LLColor4> &b); 
+}
 
 #endif
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 9d97312ab0..da0db0424a 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -36,13 +36,30 @@
 #include "lluictrl.h"
 #include "llfocusmgr.h"
 #include "llpanel.h"
+#include "lluictrlfactory.h"
 
 static LLRegisterWidget<LLUICtrl> r("ui_ctrl");
 
+LLUICtrl::Params::Params()
+:	tab_stop("tab_stop", true),
+	label("label"),
+	initial_value("initial_value"),
+	init_callback("init_callback"),
+	commit_callback("commit_callback"),
+	validate_callback("validate_callback"),
+	control_name("control_name"),
+	enabled_control("enabled_control")
+{
+	addSynonym(initial_value, "initial_val");
+	// this is the canonical name for text contents of an xml node
+	addSynonym(initial_value, "value");
+}
+
 LLFocusableElement::LLFocusableElement()
 :	mFocusLostCallback(NULL),
 	mFocusReceivedCallback(NULL),
 	mFocusChangedCallback(NULL),
+	mTopLostCallback(NULL),
 	mFocusCallbackUserData(NULL)
 {
 }
@@ -77,6 +94,14 @@ void LLFocusableElement::onFocusLost()
 	}
 }
 
+void LLFocusableElement::onTopLost()
+{
+	if (mTopLostCallback)
+	{
+		mTopLostCallback(this, mFocusCallbackUserData);
+	}
+}
+
 BOOL LLFocusableElement::hasFocus() const
 {
 	return FALSE;
@@ -86,36 +111,61 @@ void LLFocusableElement::setFocus(BOOL b)
 {
 }
 
-
-
-LLUICtrl::LLUICtrl() :
-	mCommitCallback(NULL),
-	mLostTopCallback(NULL),
-	mValidateCallback(NULL),
-	mCallbackUserData(NULL),
+LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) 
+:	LLView(p),
 	mTentative(FALSE),
-	mTabStop(TRUE),
-	mIsChrome(FALSE)
+	mIsChrome(FALSE),
+    mViewModel(viewmodel),
+	mControlVariable(NULL),
+	mEnabledControlVariable(NULL)
 {
+	mUICtrlHandle.bind(this);
 }
 
-LLUICtrl::LLUICtrl(const std::string& name, const LLRect& rect, BOOL mouse_opaque,
-	void (*on_commit_callback)(LLUICtrl*, void*),
-	void* callback_userdata,
-	U32 reshape)
-:	// can't make this automatically follow top and left, breaks lots
-	// of buttons in the UI. JC 7/20/2002
-	LLView( name, rect, mouse_opaque, reshape ),
-	mCommitCallback( on_commit_callback) ,
-	mLostTopCallback( NULL ),
-	mValidateCallback( NULL ),
-	mCallbackUserData( callback_userdata ),
-	mTentative( FALSE ),
-	mTabStop( TRUE ),
-	mIsChrome(FALSE)
+void LLUICtrl::initFromParams(const Params& p)
 {
+	LLView::initFromParams(p);
+
+	setControlName(p.control_name);
+	if (p.enabled_control.isProvided())
+	{
+		LLControlVariable* control = findControl(p.enabled_control);
+		if (control)
+			setEnabledControlVariable(control);
+	}
+	setTabStop(p.tab_stop);
+	setFocusLostCallback(p.focus_lost_callback());
+
+	if (p.initial_value.isProvided() 
+		&& !p.control_name.isProvided())
+	{
+        setValue(p.initial_value);
+	}
+	
+	if (p.commit_callback.isProvided())
+		initCommitCallback(p.commit_callback, mCommitSignal);
+	
+	if (p.validate_callback.isProvided())
+		initEnableCallback(p.validate_callback, mValidateSignal);
+	
+	if (p.init_callback.isProvided())
+	{
+		if (p.init_callback.function.isProvided())
+		{
+			p.init_callback.function()(this, p.init_callback.parameter);
+		}
+		else
+		{
+			commit_callback_t* initfunc = (CallbackRegistry<commit_callback_t>::getValue(p.init_callback.function_name));
+			if (initfunc)
+			{
+				(*initfunc)(this, p.init_callback.parameter);
+			}
+		}
+	}
 }
 
+
 LLUICtrl::~LLUICtrl()
 {
 	gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
@@ -127,24 +177,178 @@ LLUICtrl::~LLUICtrl()
 	}
 }
 
-void LLUICtrl::onCommit()
+void LLUICtrl::initCommitCallback(const CommitCallbackParam& cb, commit_signal_t& sig)
 {
-	if( mCommitCallback )
+	if (cb.function.isProvided())
 	{
-		mCommitCallback( this, mCallbackUserData );
+		if (cb.parameter.isProvided())
+			sig.connect(boost::bind(cb.function(), _1, cb.parameter));
+		else
+			sig.connect(cb.function());
+	}
+	else
+	{
+		std::string function_name = cb.function_name;
+		commit_callback_t* func = (CallbackRegistry<commit_callback_t>::getValue(function_name));
+		if (func)
+		{
+			if (cb.parameter.isProvided())
+				sig.connect(boost::bind((*func), _1, cb.parameter));
+			else
+				sig.connect(*func);
+		}
+		else if (!function_name.empty())
+		{
+			llwarns << "No callback found for: '" << function_name << "' in control: " << getName() << llendl;
+		}			
 	}
 }
 
+void LLUICtrl::initEnableCallback(const EnableCallbackParam& cb, enable_signal_t& sig)
+{
+	// Set the callback function
+	if (cb.function.isProvided())
+	{
+		if (cb.parameter.isProvided())
+			sig.connect(boost::bind(cb.function(), this, cb.parameter));
+		else
+			sig.connect(cb.function());
+	}
+	else
+	{
+		enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name));
+		if (func)
+		{
+			if (cb.parameter.isProvided())
+				sig.connect(boost::bind((*func), this, cb.parameter));
+			else
+				sig.connect(*func);
+		}
+	}
+}
+
+
+void LLUICtrl::onCommit()
+{
+	mCommitSignal(this, getValue());
+}
+
 //virtual
 BOOL LLUICtrl::isCtrl() const
 {
 	return TRUE;
 }
 
+//virtual 
+void LLUICtrl::setValue(const LLSD& value)
+{
+    mViewModel->setValue(value);
+}
+
 //virtual
 LLSD LLUICtrl::getValue() const
 {
-	return LLSD();
+	return mViewModel->getValue();
+}
+
+/// When two widgets are displaying the same data (e.g. during a skin
+/// change), share their ViewModel.
+void    LLUICtrl::shareViewModelFrom(const LLUICtrl& other)
+{
+    // Because mViewModel is an LLViewModelPtr, this assignment will quietly
+    // dispose of the previous LLViewModel -- unless it's already shared by
+    // somebody else.
+    mViewModel = other.mViewModel;
+}
+
+//virtual
+LLViewModel* LLUICtrl::getViewModel() const
+{
+	return mViewModel;
+}
+
+bool LLUICtrl::setControlValue(const LLSD& value)
+{
+	if (mControlVariable)
+	{
+		mControlVariable->set(value);
+		return true;
+	}
+	return false;
+}
+
+void LLUICtrl::setControlVariable(LLControlVariable* control)
+{
+	if (mControlVariable)
+	{
+		//RN: this will happen in practice, should we try to avoid it?
+		//llwarns << "setControlName called twice on same control!" << llendl;
+		mControlConnection.disconnect(); // disconnect current signal
+		mControlVariable = NULL;
+	}
+	
+	if (control)
+	{
+		mControlVariable = control;
+		mControlConnection = mControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("value")));
+		setValue(mControlVariable->getValue());
+	}
+}
+
+//virtual
+void LLUICtrl::setControlName(const std::string& control_name, LLView *context)
+{
+	if (context == NULL)
+	{
+		context = this;
+	}
+
+	// Register new listener
+	if (!control_name.empty())
+	{
+		LLControlVariable* control = context->findControl(control_name);
+		setControlVariable(control);
+	}
+}
+
+void LLUICtrl::setEnabledControlVariable(LLControlVariable* control)
+{
+	if (mEnabledControlVariable)
+	{
+		mEnabledControlConnection.disconnect(); // disconnect current signal
+		mEnabledControlVariable = NULL;
+	}
+	if (control)
+	{
+		mEnabledControlVariable = control;
+		mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("enabled")));
+		setEnabled(mEnabledControlVariable->getValue().asBoolean());
+	}
+}
+
+// static
+bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type)
+{
+	LLUICtrl* ctrl = handle.get();
+	if (ctrl)
+	{
+		if (type == "value")
+		{
+			ctrl->setValue(newvalue);
+			return true;
+		}
+		else if (type == "enabled")
+		{
+			ctrl->setEnabled(newvalue.asBoolean());
+			return true;
+		}
+		else if (type == "visible")
+		{
+			ctrl->setVisible(newvalue.asBoolean());
+			return true;
+		}
+	}
+	return false;
 }
 
 // virtual
@@ -248,12 +452,10 @@ void LLUICtrl::onFocusLost()
 	}
 }
 
-void LLUICtrl::onLostTop()
+void LLUICtrl::onTopLost()
 {
-	if (mLostTopCallback)
-	{
-		mLostTopCallback(this, mCallbackUserData);
-	}
+	// trigger callbacks
+	LLFocusableElement::onTopLost();
 }
 
 
@@ -278,12 +480,13 @@ BOOL LLUICtrl::acceptsTextInput() const
 //virtual
 BOOL LLUICtrl::isDirty() const
 {
-	return FALSE;
+	return mViewModel->isDirty();
 };
 
 //virtual
 void LLUICtrl::resetDirty()
 {
+    mViewModel->resetDirty();
 }
 
 // virtual
@@ -456,7 +659,8 @@ BOOL LLUICtrl::focusNextItem(BOOL text_fields_only)
 {
 	// this assumes that this method is called on the focus root.
 	LLCtrlQuery query = getTabOrderQuery();
-	if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly"))
+	static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
+	if(text_fields_only || tab_to_text_fields_only)
 	{
 		query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
 	}
@@ -468,7 +672,8 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only)
 {
 	// this assumes that this method is called on the focus root.
 	LLCtrlQuery query = getTabOrderQuery();
-	if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly"))
+	static LLUICachedControl<bool> tab_to_text_fields_only ("TabToTextFieldsOnly", false);
+	if(text_fields_only || tab_to_text_fields_only)
 	{
 		query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
 	}
@@ -524,33 +729,6 @@ BOOL LLUICtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect
 	return handled;
 }*/
 
-void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent)
-{
-	BOOL has_tab_stop = hasTabStop();
-	node->getAttributeBOOL("tab_stop", has_tab_stop);
-
-	setTabStop(has_tab_stop);
-
-	LLView::initFromXML(node, parent);
-}
-
-LLXMLNodePtr LLUICtrl::getXML(bool save_children) const
-{
-	LLXMLNodePtr node = LLView::getXML(save_children);
-	node->createChild("tab_stop", TRUE)->setBoolValue(hasTabStop());
-
-	return node;
-}
-
-//static 
-LLView* LLUICtrl::fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory)
-{
-	LLUICtrl* ctrl = new LLUICtrl();
-	ctrl->initFromXML(node, parent);
-	return ctrl;
-}
-
-
 // Skip over any parents that are not LLUICtrl's
 //  Used in focus logic since only LLUICtrl elements can have focus
 LLUICtrl* LLUICtrl::getParentUICtrl() const
@@ -570,6 +748,16 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const
 	return NULL;
 }
 
+// *TODO: Deprecate; for backwards compatability only:
+boost::signals::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
+{
+	return setCommitCallback( boost::bind(cb, _1, data));
+}
+boost::signals::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
+{
+	return mValidateSignal.connect(boost::bind(cb, _2));
+}
+
 // virtual
 void LLUICtrl::setTentative(BOOL b)									
 { 
@@ -582,11 +770,6 @@ BOOL LLUICtrl::getTentative() const
 	return mTentative; 
 }
 
-// virtual
-void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) )				
-{ 
-}
-
 // virtual
 void LLUICtrl::setColor(const LLColor4& color)							
 { }
@@ -598,3 +781,40 @@ void LLUICtrl::setMinValue(LLSD min_value)
 // virtual
 void LLUICtrl::setMaxValue(LLSD max_value)								
 { }
+
+
+
+namespace LLInitParam
+{
+    template<> 
+	bool ParamCompare<LLUICtrl::commit_callback_t>::equals(
+		const LLUICtrl::commit_callback_t &a, 
+		const LLUICtrl::commit_callback_t &b)
+    {
+    	return false;
+    }
+    
+    template<> 
+	bool ParamCompare<LLUICtrl::focus_callback_t>::equals(
+		const LLUICtrl::focus_callback_t &a, 
+		const LLUICtrl::focus_callback_t &b)
+    {
+    	return false;
+    }
+    
+    template<> 
+	bool ParamCompare<LLUICtrl::enable_callback_t>::equals(
+		const LLUICtrl::enable_callback_t &a, 
+		const LLUICtrl::enable_callback_t &b)
+    {
+    	return false;
+    }
+
+    template<> 
+	bool ParamCompare<LLLazyValue<LLColor4> >::equals(
+		const LLLazyValue<LLColor4> &a, 
+		const LLLazyValue<LLColor4> &b)    
+    {
+    	return a.get() == b.get();
+    }
+}
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index db41af8470..e82102d531 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -34,10 +34,17 @@
 #ifndef LL_LLUICTRL_H
 #define LL_LLUICTRL_H
 
-#include "llview.h"
+#include "llboost.h"
 #include "llrect.h"
 #include "llsd.h"
+#include <boost/function.hpp>
+
+#include "llinitparam.h"
+#include "llview.h"
+#include "llviewmodel.h"
 
+const BOOL TAKE_FOCUS_YES = TRUE;
+const BOOL TAKE_FOCUS_NO  = FALSE;
 
 class LLFocusableElement
 {
@@ -49,39 +56,104 @@ public:
 	virtual void	setFocus( BOOL b );
 	virtual BOOL	hasFocus() const;
 
-	void			setFocusLostCallback(void (*cb)(LLFocusableElement* caller, void*), void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; }
-	void			setFocusReceivedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL)	{ mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; }
-	void			setFocusChangedCallback( void (*cb)(LLFocusableElement*, void*), void* user_data = NULL )		{ mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; }
+	typedef boost::function<void(LLFocusableElement*, void*)> focus_callback_t;
+	void	setFocusLostCallback(focus_callback_t cb, void* user_data = NULL)	{ mFocusLostCallback = cb; mFocusCallbackUserData = user_data; }
+	void	setFocusReceivedCallback(focus_callback_t cb, void* user_data = NULL)	{ mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; }
+	void	setFocusChangedCallback(focus_callback_t cb, void* user_data = NULL )	{ mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; }
+	void	setTopLostCallback(focus_callback_t cb, void* user_data = NULL )	{ mTopLostCallback = cb; mFocusCallbackUserData = user_data; }
 
 protected:
 	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
-	void			(*mFocusLostCallback)( LLFocusableElement* caller, void* userdata );
-	void			(*mFocusReceivedCallback)( LLFocusableElement* ctrl, void* userdata );
-	void			(*mFocusChangedCallback)( LLFocusableElement* ctrl, void* userdata );
+	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
+	focus_callback_t mFocusLostCallback;
+	focus_callback_t mFocusReceivedCallback;
+	focus_callback_t mFocusChangedCallback;
+	focus_callback_t mTopLostCallback;
 	void*			mFocusCallbackUserData;
 };
 
 class LLUICtrl
-: public LLView, public LLFocusableElement
+	: public LLView, public LLFocusableElement, public boost::signals::trackable
 {
 public:
-	typedef void (*LLUICtrlCallback)(LLUICtrl* ctrl, void* userdata);
-	typedef BOOL (*LLUICtrlValidate)(LLUICtrl* ctrl, void* userdata);
-
-	LLUICtrl();
-	LLUICtrl( const std::string& name, const LLRect& rect, BOOL mouse_opaque,
-		LLUICtrlCallback callback,
-		void* callback_userdata,
-		U32 reshape=FOLLOWS_NONE);
+
+
+	typedef boost::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t;
+	typedef boost::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t;
+	
+	typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t;
+	typedef boost::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t;
+	
+	struct CallbackParam : public LLInitParam::Block<CallbackParam>
+	{
+		Deprecated				name;
+
+		Optional<std::string>	function_name;
+		Optional<LLSD>			parameter;
+
+		Optional<std::string>	control_name;
+		
+		CallbackParam()
+		  :	name("name"),
+			function_name("function"),
+			parameter("parameter"),
+			control_name("control") // Shortcut to control -> "control_name" for backwards compatability			
+		{
+			addSynonym(parameter, "userdata");
+		}
+	};
+
+	struct CommitCallbackParam : public LLInitParam::Block<CommitCallbackParam, CallbackParam >
+	{
+		Optional<commit_callback_t> function;
+	};
+	
+	struct EnableCallbackParam : public LLInitParam::Block<EnableCallbackParam, CallbackParam >
+	{
+		Optional<enable_callback_t> function;
+	};
+	
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<std::string>			label;
+		Optional<bool>					tab_stop;
+		Optional<LLSD>					initial_value;
+
+		Optional<CommitCallbackParam>	init_callback,
+										commit_callback;
+		Optional<EnableCallbackParam>	validate_callback;
+		
+		Optional<focus_callback_t>		focus_lost_callback;
+		
+		Optional<std::string>			control_name;
+		Optional<std::string>			enabled_control;
+		
+		Params();
+	};
+
 	/*virtual*/ ~LLUICtrl();
 
+	void initFromParams(const Params& p);
+protected:
+	friend class LLUICtrlFactory;
+	LLUICtrl(const Params& p = LLUICtrl::Params(),
+             const LLViewModelPtr& viewmodel=LLViewModelPtr(new LLViewModel));
+	
+	void initCommitCallback(const CommitCallbackParam& cb, commit_signal_t& sig);
+	void initEnableCallback(const EnableCallbackParam& cb, enable_signal_t& sig);
+
+	// We need this virtual so we can override it with derived versions
+	virtual LLViewModel* getViewModel() const;
+    // We shouldn't ever need to set this directly
+    //virtual void    setViewModel(const LLViewModelPtr&);
+	
+public:
 	// LLView interface
-	/*virtual*/ void	initFromXML(LLXMLNodePtr node, LLView* parent);
-	/*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const;
 	/*virtual*/ BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
 	/*virtual*/ void	onFocusReceived();
 	/*virtual*/ void	onFocusLost();
+	/*virtual*/ void	onTopLost();
 	/*virtual*/ BOOL	isCtrl() const;
 	/*virtual*/ void	setTentative(BOOL b);
 	/*virtual*/ BOOL	getTentative() const;
@@ -97,7 +169,20 @@ public:
 	virtual class LLCtrlListInterface* getListInterface();
 	virtual class LLCtrlScrollInterface* getScrollInterface();
 
+	bool setControlValue(const LLSD& value);
+	void setControlVariable(LLControlVariable* control);
+	virtual void setControlName(const std::string& control, LLView *context = NULL);
+	
+	LLControlVariable* getControlVariable() { return mControlVariable; } 
+	
+	void setEnabledControlVariable(LLControlVariable* control);
+
+	virtual void	setValue(const LLSD& value);
 	virtual LLSD	getValue() const;
+    /// When two widgets are displaying the same data (e.g. during a skin
+    /// change), share their ViewModel.
+    virtual void    shareViewModelFrom(const LLUICtrl& other);
+
 	virtual BOOL	setTextArg(  const std::string& key, const LLStringExplicit& text );
 	virtual void	setIsChrome(BOOL is_chrome);
 
@@ -108,14 +193,12 @@ public:
 	virtual BOOL	isDirty() const; // Defauls to false
 	virtual void	resetDirty(); //Defaults to no-op
 	
-	// Call appropriate callbacks
-	virtual void	onLostTop();	// called when registered as top ctrl and user clicks elsewhere
+	// Call appropriate callback
 	virtual void	onCommit();
 	
 	// Default to no-op:
 	virtual void	onTabInto();
 	virtual void	clear();
-	virtual	void	setDoubleClickCallback( void (*cb)(void*) );
 	virtual void	setColor(const LLColor4& color);
 	virtual void	setMinValue(LLSD min_value);
 	virtual void	setMaxValue(LLSD max_value);
@@ -126,6 +209,7 @@ public:
 	BOOL	focusLastItem(BOOL prefer_text_fields = FALSE);
 
 	// Non Virtuals
+	LLHandle<LLUICtrl> getUICtrlHandle() const { return mUICtrlHandle; }
 	BOOL			getIsChrome() const;
 	
 	void			setTabStop( BOOL b );
@@ -133,16 +217,14 @@ public:
 
 	LLUICtrl*		getParentUICtrl() const;
 
-	void*			getCallbackUserData() const								{ return mCallbackUserData; }
-	void			setCallbackUserData( void* data )						{ mCallbackUserData = data; }
+	boost::signals::connection setCommitCallback( const commit_signal_t::slot_type& cb ) { return mCommitSignal.connect(cb); }
+	boost::signals::connection setValidateCallback( const enable_signal_t::slot_type& cb ) { return mValidateSignal.connect(cb); }
 	
-	void			setCommitCallback( void (*cb)(LLUICtrl*, void*) )		{ mCommitCallback = cb; }
-	void			setValidateBeforeCommit( BOOL(*cb)(LLUICtrl*, void*) )	{ mValidateCallback = cb; }
-	void			setLostTopCallback( void (*cb)(LLUICtrl*, void*) )		{ mLostTopCallback = cb; }
+	// *TODO: Deprecate; for backwards compatability only:
+	boost::signals::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data);	
+	boost::signals::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb );
 	
-	static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory);
-
-	LLUICtrl*		findRootMostFocusRoot();
+	LLUICtrl* findRootMostFocusRoot();
 
 	class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter>
 	{
@@ -151,22 +233,53 @@ public:
 			return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->acceptsTextInput(), TRUE);
 		}
 	};
+	
+	template <typename F> class CallbackRegistry : public LLRegistrySingleton<std::string, F, CallbackRegistry<F> >
+	{};	
 
+	typedef CallbackRegistry<commit_callback_t> CommitCallbackRegistry;
+	typedef CallbackRegistry<enable_callback_t> EnableCallbackRegistry;
+	
 protected:
 
-	void			(*mCommitCallback)( LLUICtrl* ctrl, void* userdata );
-	void			(*mLostTopCallback)( LLUICtrl* ctrl, void* userdata );
-	BOOL			(*mValidateCallback)( LLUICtrl* ctrl, void* userdata );
+	static bool controlListener(const LLSD& newvalue, LLHandle<LLUICtrl> handle, std::string type);
+
+	commit_signal_t	mCommitSignal;
+	enable_signal_t mValidateSignal;
 
-	void*			mCallbackUserData;
+    LLViewModelPtr  mViewModel;
+
+	LLControlVariable* mControlVariable;
+	boost::signals::connection mControlConnection;
+	LLControlVariable* mEnabledControlVariable;
+	boost::signals::connection mEnabledControlConnection;
 
 private:
 
 	BOOL			mTabStop;
 	BOOL			mIsChrome;
 	BOOL			mTentative;
+	LLRootHandle<LLUICtrl> mUICtrlHandle;
 
 	class DefaultTabGroupFirstSorter;
 };
 
+namespace LLInitParam
+{   
+    template<> 
+	bool ParamCompare<LLUICtrl::commit_callback_t>::equals(
+		const LLUICtrl::commit_callback_t &a, 
+		const LLUICtrl::commit_callback_t &b); 
+		
+    template<> 
+	bool ParamCompare<LLUICtrl::enable_callback_t>::equals(
+		const LLUICtrl::enable_callback_t &a, 
+		const LLUICtrl::enable_callback_t &b); 
+    
+	template<> 
+	bool ParamCompare<LLUICtrl::focus_callback_t>::equals(
+		const LLUICtrl::focus_callback_t &a, 
+		const LLUICtrl::focus_callback_t &b); 
+}
+
 #endif  // LL_LLUICTRL_H
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 983cc53f69..1f487bdb7e 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -41,6 +41,8 @@
 #include "llcontrol.h"
 #include "lldir.h"
 #include "v4color.h"
+#include "v3dmath.h"
+#include "llquaternion.h"
 
 // this library includes
 #include "llbutton.h"
@@ -64,7 +66,6 @@
 #include "llmultisliderctrl.h"
 #include "llspinctrl.h"
 #include "lltabcontainer.h"
-#include "lltabcontainervertical.h"
 #include "lltextbox.h"
 #include "lltexteditor.h"
 #include "llui.h"
@@ -77,27 +78,32 @@ const S32 VPAD = 4;
 const S32 FLOATER_H_MARGIN = 15;
 const S32 MIN_WIDGET_HEIGHT = 10;
 
-std::vector<std::string> LLUICtrlFactory::sXUIPaths;
+//-----------------------------------------------------------------------------
+// Register widgets that are purely data driven here so they get linked in
+#include "llstatview.h"
+static LLRegisterWidget<LLStatView> register_stat_view("stat_view");
+
+//-----------------------------------------------------------------------------
 
 // UI Ctrl class for padding
 class LLUICtrlLocate : public LLUICtrl
 {
 public:
-	LLUICtrlLocate() : LLUICtrl(std::string("locate"), LLRect(0,0,0,0), FALSE, NULL, NULL) { setTabStop(FALSE); }
-	virtual void draw() { }
-
-	static LLView *fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
-		std::string name("pad");
-		node->getAttributeString("name", name);
+		Params()
+		{
+			name = "locate";
+			tab_stop = false;
+		}
+	};
+
+	LLUICtrlLocate(const Params& p) : LLUICtrl(p) {}
+	virtual void draw() { }
 
-		LLUICtrlLocate *new_ctrl = new LLUICtrlLocate();
-		new_ctrl->setName(name);
-		new_ctrl->initFromXML(node, parent);
-		return new_ctrl;
-	}
 };
 
+//FIXME: this created an ambiguous lookup of template (locate.xml or pad.xml?)
 static LLRegisterWidget<LLUICtrlLocate> r1("locate");
 static LLRegisterWidget<LLUICtrlLocate> r2("pad");
 
@@ -105,9 +111,8 @@ static LLRegisterWidget<LLUICtrlLocate> r2("pad");
 // LLUICtrlFactory()
 //-----------------------------------------------------------------------------
 LLUICtrlFactory::LLUICtrlFactory()
-	: mDummyPanel(NULL)
+	: mDummyPanel(NULL) // instantiated when first needed
 {
-	setupPaths();
 }
 
 LLUICtrlFactory::~LLUICtrlFactory()
@@ -116,43 +121,15 @@ LLUICtrlFactory::~LLUICtrlFactory()
 	mDummyPanel = NULL;
 }
 
-void LLUICtrlFactory::setupPaths()
+void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block)
 {
-	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "paths.xml");
+	std::string filename = std::string("widgets") + gDirUtilp->getDirDelimiter() + widget_tag + ".xml";
+	LLXMLNodePtr root_node;
 
-	LLXMLNodePtr root;
-	BOOL success  = LLXMLNode::parseFile(filename, root, NULL);
-	sXUIPaths.clear();
-	
-	if (success)
+	if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
 	{
-		LLXMLNodePtr path;
-	
-		for (path = root->getFirstChild(); path.notNull(); path = path->getNextSibling())
-		{
-			LLUIString path_val_ui(path->getValue());
-			std::string language = LLUI::getLanguage();
-			path_val_ui.setArg("[LANGUAGE]", language);
-
-			if (std::find(sXUIPaths.begin(), sXUIPaths.end(), path_val_ui.getString()) == sXUIPaths.end())
-			{
-				sXUIPaths.push_back(path_val_ui.getString());
-			}
-		}
+		LLXUIParser::instance().readXUI(root_node, block);
 	}
-	else // parsing failed
-	{
-		std::string slash = gDirUtilp->getDirDelimiter();
-		std::string dir = "xui" + slash + "en-us";
-		llwarns << "XUI::config file unable to open: " << filename << llendl;
-		sXUIPaths.push_back(dir);
-	}
-}
-
-// static
-const std::vector<std::string>& LLUICtrlFactory::getXUIPaths()
-{
-	return sXUIPaths;
 }
 
 //-----------------------------------------------------------------------------
@@ -160,97 +137,61 @@ const std::vector<std::string>& LLUICtrlFactory::getXUIPaths()
 //-----------------------------------------------------------------------------
 bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
 {
-	std::string full_filename = gDirUtilp->findSkinnedFilename(sXUIPaths.front(), xui_filename);
-	if (full_filename.empty())
-	{
-		llwarns << "Couldn't find UI description file: " << sXUIPaths.front() + gDirUtilp->getDirDelimiter() + xui_filename << llendl;
-		return false;
-	}
-
-	if (!LLXMLNode::parseFile(full_filename, root, NULL))
-	{
-		// try filename as passed in since sometimes we load an xml file from a user-supplied path
-		if (!LLXMLNode::parseFile(xui_filename, root, NULL))
-		{
-			llwarns << "Problem reading UI description file: " << xui_filename << llendl;
-			return false;
-		}
-	}
-
-	LLXMLNodePtr updateRoot;
-
-	std::vector<std::string>::const_iterator itor;
-
-	for (itor = sXUIPaths.begin(), ++itor; itor != sXUIPaths.end(); ++itor)
-	{
-		std::string nodeName;
-		std::string updateName;
-
-		std::string layer_filename = gDirUtilp->findSkinnedFilename((*itor), xui_filename);
-		if(layer_filename.empty())
-		{
-			// no localized version of this file, that's ok, keep looking
-			continue;
-		}
-
-		if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL))
-		{
-			llwarns << "Problem reading localized UI description file: " << (*itor) + gDirUtilp->getDirDelimiter() + xui_filename << llendl;
-			return false;
-		}
-
-		updateRoot->getAttributeString("name", updateName);
-		root->getAttributeString("name", nodeName);
-
-		if (updateName == nodeName)
-		{
-			LLXMLNode::updateNode(root, updateRoot);
-		}
-	}
-
-	return true;
+	return LLXMLNode::getLayeredXMLNode(xui_filename, root, LLUI::getXUIPaths());
 }
 
-
 //-----------------------------------------------------------------------------
 // buildFloater()
 //-----------------------------------------------------------------------------
-void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, 
-									const LLCallbackMap::map_t* factory_map, BOOL open) /* Flawfinder: ignore */
+void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, BOOL open_floater, LLXMLNodePtr output_node)
 {
 	LLXMLNodePtr root;
 
 	if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
 	{
+		llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
 		return;
 	}
 	
 	// root must be called floater
-	if( !(root->hasName("floater") || root->hasName("multi_floater") ) )
+	if( !(root->hasName("floater") || root->hasName("multi_floater")) )
 	{
 		llwarns << "Root node should be named floater in: " << filename << llendl;
 		return;
 	}
 
-	if (factory_map)
+	lldebugs << "Building floater " << filename << llendl;
+	mFileNames.push_back(gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename));
 	{
-		mFactoryStack.push_front(factory_map);
-	}
-
-	floaterp->initFloaterXML(root, NULL, this, open);	/* Flawfinder: ignore */
-
-	if (LLUI::sShowXUINames)
-	{
-		floaterp->setToolTip(filename);
-	}
+		if (!floaterp->getFactoryMap().empty())
+		{
+			mFactoryStack.push_front(&floaterp->getFactoryMap());
+		}
+		
+		floaterp->getCommitCallbackRegistrar().pushScope(); // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+		
+		floaterp->initFloaterXML(root, floaterp->getParent(), open_floater, output_node);
 
-	if (factory_map)
-	{
-		mFactoryStack.pop_front();
+		if (LLUI::sShowXUINames)
+		{
+			floaterp->setToolTip(filename);
+		}
+		
+		floaterp->getCommitCallbackRegistrar().popScope();
+		
+		if (!floaterp->getFactoryMap().empty())
+		{
+			mFactoryStack.pop_front();
+		}
 	}
+	mFileNames.pop_back();
+}
 
-	LLHandle<LLFloater> handle = floaterp->getHandle();
-	mBuiltFloaters[handle] = filename;
+LLFloater* LLUICtrlFactory::buildFloaterFromXML(const std::string& filename, BOOL open_floater)
+{
+	LLFloater* floater = new LLFloater();
+	buildFloater(floater, filename, open_floater);
+	return floater;
 }
 
 //-----------------------------------------------------------------------------
@@ -258,34 +199,20 @@ void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filen
 //-----------------------------------------------------------------------------
 S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
 {
-	llofstream out(filename);
-	if (!out.good())
-	{
-		llwarns << "Unable to open " << filename << " for output." << llendl;
-		return 1;
-	}
-
-	out << XML_HEADER;
-
-	LLXMLNodePtr xml_node = viewp->getXML();
-
-	xml_node->writeToOstream(out);
-
-	out.close();
 	return 0;
 }
 
 //-----------------------------------------------------------------------------
 // buildPanel()
 //-----------------------------------------------------------------------------
-BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename,
-									const LLCallbackMap::map_t* factory_map)
+BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, LLXMLNodePtr output_node)
 {
 	BOOL didPost = FALSE;
 	LLXMLNodePtr root;
 
 	if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
 	{
+		llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
 		return didPost;
 	}
 
@@ -296,246 +223,733 @@ BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename,
 		return didPost;
 	}
 
-	if (factory_map)
+	lldebugs << "Building panel " << filename << llendl;
+
+	mFileNames.push_back(gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename));
 	{
-		mFactoryStack.push_front(factory_map);
+		if (!panelp->getFactoryMap().empty())
+		{
+			mFactoryStack.push_front(&panelp->getFactoryMap());
+		}
+		
+		didPost = panelp->initPanelXML(root, NULL, output_node);
+		
+		if (LLUI::sShowXUINames)
+		{
+			panelp->setToolTip(filename);
+		}
+
+		if (!panelp->getFactoryMap().empty())
+		{
+			mFactoryStack.pop_front();
+		}
 	}
+	mFileNames.pop_back();
+	return didPost;
+}
 
-	didPost = panelp->initPanelXML(root, NULL, this);
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename,  LLXMLNodePtr output_node)
+{
+	std::string ctrl_type = node->getName()->mString;
+	LLStringUtil::toLower(ctrl_type);
 	
-	if (LLUI::sShowXUINames)
+	LLWidgetCreatorFunc* funcp = LLWidgetCreatorRegistry::getInstance()->getValue(ctrl_type);
+
+	if (funcp == NULL)
 	{
-		panelp->setToolTip(filename);
+		return NULL;
 	}
 
-	LLHandle<LLPanel> handle = panelp->getHandle();
-	mBuiltPanels[handle] = filename;
-
-	if (factory_map)
+	if (parent == NULL)
+	{
+		if (mDummyPanel == NULL)
+		{
+			mDummyPanel = new LLPanel();
+		}
+		parent = mDummyPanel;
+	}
+	LLView *view = (*funcp)(node, parent, output_node);	
+	if (LLUI::sShowXUINames && view && !filename.empty())
 	{
-		mFactoryStack.pop_front();
+		view->setToolTip(filename);
 	}
-
-	return didPost;
+	
+	return view;
 }
 
 //-----------------------------------------------------------------------------
-// buildMenu()
+// createFactoryPanel()
 //-----------------------------------------------------------------------------
-LLMenuGL *LLUICtrlFactory::buildMenu(const std::string &filename, LLView* parentp)
+LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name)
 {
-	// TomY TODO: Break this function into buildMenu and buildMenuBar
-	LLXMLNodePtr root;
-	LLMenuGL*    menu;
-
-	if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+	std::deque<const LLCallbackMap::map_t*>::iterator itor;
+	for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor)
 	{
-		return NULL;
+		const LLCallbackMap::map_t* factory_map = *itor;
+
+		// Look up this panel's name in the map.
+		LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
+		if (iter != factory_map->end())
+		{
+			// Use the factory to create the panel, instead of using a default LLPanel.
+			LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
+			return ret;
+		}
 	}
+	return new LLPanel();
+}
 
-	// root must be called panel
-	if( !root->hasName( "menu_bar" ) && !root->hasName( "menu" ))
+//-----------------------------------------------------------------------------
+
+//static
+BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color)
+{
+	std::string colorstring;
+	BOOL res = node->getAttributeString(name.c_str(), colorstring);
+	if (res && LLUI::sSettingGroups["color"])
 	{
-		llwarns << "Root node should be named menu bar or menu in : " << filename << llendl;
-		return NULL;
+		if (LLUI::sSettingGroups["color"]->controlExists(colorstring))
+		{
+			color.setVec(LLUI::sSettingGroups["color"]->getColor(colorstring));
+		}
+		else
+		{
+			res = FALSE;
+		}
+	}
+	if (!res)
+	{
+		res = LLColor4::parseColor(colorstring, &color);
+	}	
+	if (!res)
+	{
+		res = node->getAttributeColor(name.c_str(), color);
 	}
+	return res;
+}
 
-	if (root->hasName("menu"))
+//static
+void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group)
+{
+	if (tab_group < 0) tab_group = parent->getLastTabGroup();
+	parent->addChild(view, tab_group);
+}
+
+
+// Avoid directly using LLUI and LLDir in the template code
+//static
+std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename)
+{
+	return gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename);
+}
+
+void LLUICtrlFactory::pushFactoryFunctions(const LLCallbackMap::map_t* map)
+{
+	mFactoryStack.push_back(map);
+}
+
+void LLUICtrlFactory::popFactoryFunctions()
+{
+	if (!mFactoryStack.empty())
 	{
-		menu = (LLMenuGL*)LLMenuGL::fromXML(root, parentp, this);
+		mFactoryStack.pop_back();
 	}
-	else
+}
+
+
+//
+// LLXUIParser
+//
+LLXUIParser::LLXUIParser()
+:	mLastWriteGeneration(-1)
+{
+	registerParserFuncs<bool>(boost::bind(&LLXUIParser::readBoolValue, this, _1),
+								boost::bind(&LLXUIParser::writeBoolValue, this, _1, _2));
+	registerParserFuncs<std::string>(boost::bind(&LLXUIParser::readStringValue, this, _1),
+								boost::bind(&LLXUIParser::writeStringValue, this, _1, _2));
+	registerParserFuncs<U8>(boost::bind(&LLXUIParser::readU8Value, this, _1),
+								boost::bind(&LLXUIParser::writeU8Value, this, _1, _2));
+	registerParserFuncs<S8>(boost::bind(&LLXUIParser::readS8Value, this, _1),
+								boost::bind(&LLXUIParser::writeS8Value, this, _1, _2));
+	registerParserFuncs<U16>(boost::bind(&LLXUIParser::readU16Value, this, _1),
+								boost::bind(&LLXUIParser::writeU16Value, this, _1, _2));
+	registerParserFuncs<S16>(boost::bind(&LLXUIParser::readS16Value, this, _1),
+								boost::bind(&LLXUIParser::writeS16Value, this, _1, _2));
+	registerParserFuncs<U32>(boost::bind(&LLXUIParser::readU32Value, this, _1),
+								boost::bind(&LLXUIParser::writeU32Value, this, _1, _2));
+	registerParserFuncs<S32>(boost::bind(&LLXUIParser::readS32Value, this, _1),
+								boost::bind(&LLXUIParser::writeS32Value, this, _1, _2));
+	registerParserFuncs<F32>(boost::bind(&LLXUIParser::readF32Value, this, _1),
+								boost::bind(&LLXUIParser::writeF32Value, this, _1, _2));
+	registerParserFuncs<F64>(boost::bind(&LLXUIParser::readF64Value, this, _1),
+								boost::bind(&LLXUIParser::writeF64Value, this, _1, _2));
+	registerParserFuncs<LLColor4>(boost::bind(&LLXUIParser::readColor4Value, this, _1),
+								boost::bind(&LLXUIParser::writeColor4Value, this, _1, _2));
+	registerParserFuncs<LLUIColor>(boost::bind(&LLXUIParser::readUIColorValue, this, _1),
+								boost::bind(&LLXUIParser::writeUIColorValue, this, _1, _2));
+	registerParserFuncs<LLUUID>(boost::bind(&LLXUIParser::readUUIDValue, this, _1),
+								boost::bind(&LLXUIParser::writeUUIDValue, this, _1, _2));
+	registerParserFuncs<LLSD>(boost::bind(&LLXUIParser::readSDValue, this, _1),
+								boost::bind(&LLXUIParser::writeSDValue, this, _1, _2));
+}
+
+void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent)
+{
+	mNameStack.clear();
+	setParseSilently(silent);
+
+	if (node.isNull())
 	{
-		menu = (LLMenuGL*)LLMenuBarGL::fromXML(root, parentp, this);
+		parserWarning("Invalid node");
 	}
-	
-	if (LLUI::sShowXUINames)
+	else
 	{
-		menu->setToolTip(filename);
+		readXUIImpl(node, std::string(node->getName()->mString), block);
 	}
+}
 
-    return menu;
+void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block)
+{
+	mLastWriteGeneration = -1;
+	mWriteRootNode = node;
+	block.serializeBlock(*this, Parser::name_stack_t(), diff_block);
 }
 
-//-----------------------------------------------------------------------------
-// buildMenu()
-//-----------------------------------------------------------------------------
-LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* parentp)
+// go from a stack of names to a specific XML node
+LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack)
 {
-	LLXMLNodePtr root;
+	if (stack.empty() || mWriteRootNode.isNull()) return NULL;
+
+	std::string attribute_name = stack.front().first;
+
+	// heuristic to make font always attribute of parent node
+	bool is_font = (attribute_name == "font");
+	// XML spec says that attributes have their whitespace normalized
+	// on parse: http://www.w3.org/TR/REC-xml/#AVNormalize
+	// Therefore text-oriented widgets that might have carriage returns
+	// have their values serialized as text contents, not the
+	// initial_value attribute. JC
+	if (attribute_name == "initial_value")
+	{
+		const char* root_node_name = mWriteRootNode->getName()->mString;
+		if (!strcmp(root_node_name, "text")		// LLTextBox
+			|| !strcmp(root_node_name, "text_editor") 
+			|| !strcmp(root_node_name, "line_editor")) // for consistency
+		{
+			// writeStringValue will write to this node
+			return mWriteRootNode;
+		}
+	}
 
-	if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+	for (name_stack_t::const_iterator it = ++stack.begin();
+		it != stack.end();
+		++it)
 	{
-		return NULL;
+		attribute_name += ".";
+		attribute_name += it->first;
 	}
 
-	// root must be called panel
-	if( !root->hasName( LL_PIE_MENU_TAG ))
+	LLXMLNodePtr attribute_node;
+
+	const char* attribute_cstr = attribute_name.c_str();
+	if (stack.size() != 1
+		&& !is_font)
 	{
-		llwarns << "Root node should be named " << LL_PIE_MENU_TAG << " in : " << filename << llendl;
-		return NULL;
-	}
+		std::string child_node_name(mWriteRootNode->getName()->mString);
+		child_node_name += ".";
+		child_node_name += stack.front().first;
+
+		LLXMLNodePtr child_node;
 
-	std::string name("menu");
-	root->getAttributeString("name", name);
+		if (mLastWriteGeneration == stack.front().second)
+		{
+			child_node = mLastWrittenChild;
+		}
+		else
+		{
+			mLastWriteGeneration = stack.front().second;
+			child_node = mWriteRootNode->createChild(child_node_name.c_str(), false);
+		}
+
+		mLastWrittenChild = child_node;
 
-	LLPieMenu *menu = new LLPieMenu(name);
-	parentp->addChild(menu);
-	menu->initXML(root, parentp, this);
+		name_stack_t::const_iterator it = ++stack.begin();
+		std::string short_attribute_name(it->first);
+
+		for (++it;
+			it != stack.end();
+			++it)
+		{
+			short_attribute_name += ".";
+			short_attribute_name += it->first;
+		}
+
+		if (child_node->hasAttribute(short_attribute_name.c_str()))
+		{
+			llerrs << "Attribute " << short_attribute_name << " already exists!" << llendl;
+		}
 
-	if (LLUI::sShowXUINames)
+		attribute_node = child_node->createChild(short_attribute_name.c_str(), true);
+	}
+	else
 	{
-		menu->setToolTip(filename);
+		if (mWriteRootNode->hasAttribute(attribute_cstr))
+		{
+			mWriteRootNode->getAttribute(attribute_cstr, attribute_node);
+		}
+		else
+		{
+			attribute_node = mWriteRootNode->createChild(attribute_name.c_str(), true);
+		}
 	}
 
-	return menu;
+	return attribute_node;
 }
 
-//-----------------------------------------------------------------------------
-// rebuild()
-//-----------------------------------------------------------------------------
-void LLUICtrlFactory::rebuild()
+
+bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, const std::string& scope, LLInitParam::BaseBlock& block)
 {
-	built_panel_t::iterator built_panel_it;
-	for (built_panel_it = mBuiltPanels.begin();
-		built_panel_it != mBuiltPanels.end();
-		++built_panel_it)
-	{
-		std::string filename = built_panel_it->second;
-		LLPanel* panelp = built_panel_it->first.get();
-		if (!panelp)
+	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+	boost::char_separator<char> sep(".");
+
+	bool values_parsed = false;
+
+	// submit attributes for current node
+	values_parsed |= readAttributes(nodep, block);
+
+	// treat text contents of xml node as "value" parameter
+	std::string text_contents = nodep->getSanitizedValue();
+	if (!text_contents.empty())
+	{
+		mCurReadNode = nodep;
+		mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration()));
+		block.submitValue(mNameStack, *this);
+		mNameStack.pop_back();
+	}
+
+	// then traverse children
+	// child node must start with last name of parent node (our "scope")
+	// for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>"
+	// which equates to the following nesting:
+	// button
+	//     param
+	//         nested_param1
+	//         nested_param2
+	//             nested_param3	
+	for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();)
+	{
+		std::string child_name(childp->getName()->mString);
+		S32 num_tokens_pushed = 0;
+
+		// for non "dotted" child nodes	check to see if child node maps to another widget type
+		// and if not, treat as a child element of the current node
+		// e.g. <button><rect left="10"/></button> will interpret <rect> as "button.rect"
+		// since there is no widget named "rect"
+		if (child_name.find(".") == std::string::npos) 
 		{
-			continue;
+			// skip over children with registered names
+			if (LLWidgetCreatorRegistry::instance().exists(child_name))
+			{
+				childp = childp->getNextSibling();
+				continue;
+			}
+
+			mNameStack.push_back(std::make_pair(child_name, newParseGeneration()));
+			num_tokens_pushed++;
 		}
-		llinfos << "Rebuilding UI panel " << panelp->getName() 
-			<< " from " << filename
-			<< llendl;
-		BOOL visible = panelp->getVisible();
-		panelp->setVisible(FALSE);
-		panelp->setFocus(FALSE);
-		panelp->deleteAllChildren();
+		else
+		{
+			// parse out "dotted" name into individual tokens
+			tokenizer name_tokens(child_name, sep);
+
+			tokenizer::iterator name_token_it = name_tokens.begin();
+			if(name_token_it == name_tokens.end()) 
+			{
+				childp = childp->getNextSibling();
+				continue;
+			}
 
-		buildPanel(panelp, filename.c_str(), &panelp->getFactoryMap());
-		panelp->setVisible(visible);
+			// check for proper nesting
+			if(!scope.empty() && *name_token_it != scope)
+			{
+				childp = childp->getNextSibling();
+				continue;
+			}
+
+			// now ignore first token
+			++name_token_it; 
+
+			// copy remaining tokens on to our running token list
+			for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push)
+			{
+				mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration()));
+				num_tokens_pushed++;
+			}
+		}
+
+		// recurse and visit children XML nodes
+		if(readXUIImpl(childp, mNameStack.empty() ? scope : mNameStack.back().first, block))
+		{
+			// child node successfully parsed, remove from DOM
+
+			values_parsed = true;
+			LLXMLNodePtr node_to_remove = childp;
+			childp = childp->getNextSibling();
+
+			nodep->deleteChild(node_to_remove);
+		}
+		else
+		{
+			childp = childp->getNextSibling();
+		}
+
+		while(num_tokens_pushed-- > 0)
+		{
+			mNameStack.pop_back();
+		}
 	}
+	return values_parsed;
+}
+
+bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
+{
+	typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+	boost::char_separator<char> sep(".");
 
-	built_floater_t::iterator built_floater_it;
-	for (built_floater_it = mBuiltFloaters.begin();
-		built_floater_it != mBuiltFloaters.end();
-		++built_floater_it)
+	bool any_parsed = false;
+
+	for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); 
+		attribute_it != nodep->mAttributes.end(); 
+		++attribute_it)
 	{
-		LLFloater* floaterp = built_floater_it->first.get();
-		if (!floaterp)
+		S32 num_tokens_pushed = 0;
+		std::string attribute_name(attribute_it->first->mString);
+		mCurReadNode = attribute_it->second;
+
+		tokenizer name_tokens(attribute_name, sep);
+		// copy remaining tokens on to our running token list
+		for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push)
 		{
-			continue;
+			mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration()));
+			num_tokens_pushed++;
 		}
-		std::string filename = built_floater_it->second;
-		llinfos << "Rebuilding UI floater " << floaterp->getName()
-			<< " from " << filename
-			<< llendl;
-		BOOL visible = floaterp->getVisible();
-		floaterp->setVisible(FALSE);
-		floaterp->setFocus(FALSE);
-		floaterp->deleteAllChildren();
 
-		gFloaterView->removeChild(floaterp);
-		buildFloater(floaterp, filename, &floaterp->getFactoryMap());
-		floaterp->setVisible(visible);
+		any_parsed |= block.submitValue(mNameStack, *this);
+		
+		while(num_tokens_pushed-- > 0)
+		{
+			mNameStack.pop_back();
+		}
 	}
+
+	return any_parsed;
 }
 
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
+bool LLXUIParser::readBoolValue(void* val_ptr)
+{
+	S32 value;
+	bool success = mCurReadNode->getBoolValue(1, &value);
+	*((bool*)val_ptr) = (value != FALSE);
+	return success;
+}
 
-LLView *LLUICtrlFactory::createCtrlWidget(LLPanel *parent, LLXMLNodePtr node)
+bool LLXUIParser::writeBoolValue(const void* val_ptr, const name_stack_t& stack)
 {
-	std::string ctrl_type = node->getName()->mString;
-	LLStringUtil::toLower(ctrl_type);
-	
-	LLWidgetClassRegistry::factory_func_t func = LLWidgetClassRegistry::getInstance()->getCreatorFunc(ctrl_type);
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		node->setBoolValue(*((bool*)val_ptr));
+		return true;
+	}
+	return false;
+}
 
-	if (func == NULL)
+bool LLXUIParser::readStringValue(void* val_ptr)
+{
+	*((std::string*)val_ptr) = mCurReadNode->getSanitizedValue();
+	return true;
+}
+
+bool LLXUIParser::writeStringValue(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		llwarns << "Unknown control type " << ctrl_type << llendl;
-		return NULL;
+		node->setStringValue(*((std::string*)val_ptr));
+		return true;
 	}
+	return false;
+}
 
-	if (parent == NULL)
+bool LLXUIParser::readU8Value(void* val_ptr)
+{
+	return mCurReadNode->getByteValue(1, (U8*)val_ptr);
+}
+
+bool LLXUIParser::writeU8Value(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		if (mDummyPanel == NULL)
-		{
-			mDummyPanel = new LLPanel;
-		}
-		parent = mDummyPanel;
+		node->setUnsignedValue(*((U8*)val_ptr));
+		return true;
 	}
-	LLView *ctrl = func(node, parent, this);
+	return false;
+}
 
-	return ctrl;
+bool LLXUIParser::readS8Value(void* val_ptr)
+{
+	S32 value;
+	if(mCurReadNode->getIntValue(1, &value))
+	{
+		*((S8*)val_ptr) = value;
+		return true;
+	}
+	return false;
 }
 
-LLView* LLUICtrlFactory::createWidget(LLPanel *parent, LLXMLNodePtr node)
+bool LLXUIParser::writeS8Value(const void* val_ptr, const name_stack_t& stack)
 {
-	LLView* view = createCtrlWidget(parent, node);
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		node->setIntValue(*((S8*)val_ptr));
+		return true;
+	}
+	return false;
+}
 
-	S32 tab_group = parent->getLastTabGroup();
-	node->getAttributeS32("tab_group", tab_group);
+bool LLXUIParser::readU16Value(void* val_ptr)
+{
+	U32 value;
+	if(mCurReadNode->getUnsignedValue(1, &value))
+	{
+		*((U16*)val_ptr) = value;
+		return true;
+	}
+	return false;
+}
 
-	if (view)
+bool LLXUIParser::writeU16Value(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		parent->addChild(view, tab_group);
+		node->setUnsignedValue(*((U16*)val_ptr));
+		return true;
 	}
+	return false;
+}
 
-	return view;
+bool LLXUIParser::readS16Value(void* val_ptr)
+{
+	S32 value;
+	if(mCurReadNode->getIntValue(1, &value))
+	{
+		*((S16*)val_ptr) = value;
+		return true;
+	}
+	return false;
 }
 
-//-----------------------------------------------------------------------------
-// createFactoryPanel()
-//-----------------------------------------------------------------------------
-LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name)
+bool LLXUIParser::writeS16Value(const void* val_ptr, const name_stack_t& stack)
 {
-	std::deque<const LLCallbackMap::map_t*>::iterator itor;
-	for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor)
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		const LLCallbackMap::map_t* factory_map = *itor;
+		node->setIntValue(*((S16*)val_ptr));
+		return true;
+	}
+	return false;
+}
 
-		// Look up this panel's name in the map.
-		LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
-		if (iter != factory_map->end())
-		{
-			// Use the factory to create the panel, instead of using a default LLPanel.
-			LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
-			return ret;
-		}
+bool LLXUIParser::readU32Value(void* val_ptr)
+{
+	return mCurReadNode->getUnsignedValue(1, (U32*)val_ptr);
+}
+
+bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		node->setUnsignedValue(*((U32*)val_ptr));
+		return true;
 	}
-	return NULL;
+	return false;
 }
 
-//-----------------------------------------------------------------------------
+bool LLXUIParser::readS32Value(void* val_ptr)
+{
+	return mCurReadNode->getIntValue(1, (S32*)val_ptr);
+}
 
-//static
-BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color)
+bool LLXUIParser::writeS32Value(const void* val_ptr, const name_stack_t& stack)
 {
-	std::string colorstring;
-	BOOL res = node->getAttributeString(name.c_str(), colorstring);
-	if (res && LLUI::sColorsGroup)
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		if (LLUI::sColorsGroup->controlExists(colorstring))
-		{
-			color.setVec(LLUI::sColorsGroup->getColor(colorstring));
-		}
-		else
-		{
-			res = FALSE;
-		}
+		node->setIntValue(*((S32*)val_ptr));
+		return true;
 	}
-	if (!res)
+	return false;
+}
+
+bool LLXUIParser::readF32Value(void* val_ptr)
+{
+	return mCurReadNode->getFloatValue(1, (F32*)val_ptr);
+}
+
+bool LLXUIParser::writeF32Value(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		res = LLColor4::parseColor(colorstring, &color);
-	}	
-	if (!res)
+		node->setFloatValue(*((F32*)val_ptr));
+		return true;
+	}
+	return false;
+}
+
+bool LLXUIParser::readF64Value(void* val_ptr)
+{
+	return mCurReadNode->getDoubleValue(1, (F64*)val_ptr);
+}
+
+bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
 	{
-		res = node->getAttributeColor(name.c_str(), color);
+		node->setDoubleValue(*((F64*)val_ptr));
+		return true;
 	}
-	return res;
+	return false;
 }
 
+bool LLXUIParser::readColor4Value(void* val_ptr)
+{
+	LLColor4* colorp = (LLColor4*)val_ptr;
+	if(mCurReadNode->getFloatValue(4, colorp->mV) >= 3)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+bool LLXUIParser::writeColor4Value(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		LLColor4 color = *((LLColor4*)val_ptr);
+		node->setFloatValue(4, color.mV);
+		return true;
+	}
+	return false;
+}
+
+bool LLXUIParser::readUIColorValue(void* val_ptr)
+{
+	LLUIColor* param = (LLUIColor*)val_ptr;
+	LLColor4 color;
+	bool success =  mCurReadNode->getFloatValue(4, color.mV) >= 3;
+	if (success)
+	{
+		param->set(color);
+		return true;
+	}
+	return false;
+}
+
+bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		LLUIColor color = *((LLUIColor*)val_ptr);
+		node->setFloatValue(4, color.get().mV);
+		return true;
+	}
+	return false;
+}
+
+bool LLXUIParser::readUUIDValue(void* val_ptr)
+{
+	LLUUID temp_id;
+	// LLUUID::set is destructive, so use temporary value
+	if (temp_id.set(mCurReadNode->getSanitizedValue()))
+	{
+		*(LLUUID*)(val_ptr) = temp_id;
+		return true;
+	}
+	return false;
+}
+
+bool LLXUIParser::writeUUIDValue(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		node->setStringValue(((LLUUID*)val_ptr)->asString());
+		return true;
+	}
+	return false;
+}
+
+bool LLXUIParser::readSDValue(void* val_ptr)
+{
+	*((LLSD*)val_ptr) = LLSD(mCurReadNode->getSanitizedValue());
+	return true;
+}
+
+bool LLXUIParser::writeSDValue(const void* val_ptr, const name_stack_t& stack)
+{
+	LLXMLNodePtr node = getNode(stack);
+	if (node.notNull())
+	{
+		node->setStringValue(((LLSD*)val_ptr)->asString());
+		return true;
+	}
+	return false;
+}
+
+/*virtual*/ std::string LLXUIParser::getCurrentElementName()
+{
+	std::string full_name;
+	for (name_stack_t::iterator it = mNameStack.begin();	
+		it != mNameStack.end();
+		++it)
+	{
+		full_name += it->first + "."; // build up dotted names: "button.param.nestedparam."
+	}
+
+	return full_name;
+}
+
+void LLXUIParser::parserWarning(const std::string& message)
+{
+#ifdef LL_WINDOWS
+	// use Visual Studo friendly formatting of output message for easy access to originating xml
+	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", LLUICtrlFactory::getInstance()->getCurFileName().c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
+	utf16str += '\n';
+	OutputDebugString(utf16str.c_str());
+#else
+	Parser::parserWarning(message);
+#endif
+}
+
+void LLXUIParser::parserError(const std::string& message)
+{
+#ifdef LL_WINDOWS
+	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", LLUICtrlFactory::getInstance()->getCurFileName().c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
+	utf16str += '\n';
+	OutputDebugString(utf16str.c_str());
+#else
+	Parser::parserError(message);
+#endif
+}
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 5e7c24efc0..5b04557368 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -33,68 +33,326 @@
 #ifndef LLUICTRLFACTORY_H
 #define LLUICTRLFACTORY_H
 
+#include "llcallbackmap.h"
+#include "llinitparam.h"
+#include "llxmlnode.h"
+
+#include <boost/function.hpp>
 #include <iosfwd>
 #include <stack>
 
-#include "llcallbackmap.h"
-#include "llfloater.h"
-
-class LLView;
 class LLPanel;
+class LLFloater;
+class LLView;
 
-class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
+class LLXUIParser : public LLInitParam::Parser, public LLSingleton<LLXUIParser>
 {
+LOG_CLASS(LLXUIParser);
+
+protected:
+	LLXUIParser();
+	friend class LLSingleton<LLXUIParser>;
 public:
+	typedef LLInitParam::Parser::name_stack_t name_stack_t;
+
+	/*virtual*/ std::string getCurrentElementName();
+	/*virtual*/ void parserWarning(const std::string& message);
+	/*virtual*/ void parserError(const std::string& message);
+
+	void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent=false);
+	void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL);
+
+private:
+	typedef std::list<std::pair<std::string, bool> >	token_list_t;
+
+	bool readXUIImpl(LLXMLNodePtr node, const std::string& scope, LLInitParam::BaseBlock& block);
+	bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block);
+
+	//reader helper functions
+	bool readBoolValue(void* val_ptr);
+	bool readStringValue(void* val_ptr);
+	bool readU8Value(void* val_ptr);
+	bool readS8Value(void* val_ptr);
+	bool readU16Value(void* val_ptr);
+	bool readS16Value(void* val_ptr);
+	bool readU32Value(void* val_ptr);
+	bool readS32Value(void* val_ptr);
+	bool readF32Value(void* val_ptr);
+	bool readF64Value(void* val_ptr);
+	bool readColor4Value(void* val_ptr);
+	bool readUIColorValue(void* val_ptr);
+	bool readUUIDValue(void* val_ptr);
+	bool readSDValue(void* val_ptr);
+
+	//writer helper functions
+	bool writeBoolValue(const void* val_ptr, const name_stack_t&);
+	bool writeStringValue(const void* val_ptr, const name_stack_t&);
+	bool writeU8Value(const void* val_ptr, const name_stack_t&);
+	bool writeS8Value(const void* val_ptr, const name_stack_t&);
+	bool writeU16Value(const void* val_ptr, const name_stack_t&);
+	bool writeS16Value(const void* val_ptr, const name_stack_t&);
+	bool writeU32Value(const void* val_ptr, const name_stack_t&);
+	bool writeS32Value(const void* val_ptr, const name_stack_t&);
+	bool writeF32Value(const void* val_ptr, const name_stack_t&);
+	bool writeF64Value(const void* val_ptr, const name_stack_t&);
+	bool writeColor4Value(const void* val_ptr, const name_stack_t&);
+	bool writeUIColorValue(const void* val_ptr, const name_stack_t&);
+	bool writeUUIDValue(const void* val_ptr, const name_stack_t&);
+	bool writeSDValue(const void* val_ptr, const name_stack_t&);
+
+	LLXMLNodePtr getNode(const name_stack_t& stack);
+
+private:
+	Parser::name_stack_t			mNameStack;
+	LLXMLNodePtr					mCurReadNode;
+	// Root of the widget XML sub-tree, for example, "line_editor"
+	LLXMLNodePtr					mWriteRootNode;
+	S32								mLastWriteGeneration;
+	LLXMLNodePtr					mLastWrittenChild;
+};
+
+// global static instance for registering all widget types
+typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc;
+
+class LLWidgetCreatorRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, LLWidgetCreatorRegistry>
+{
+protected:
+	LLWidgetCreatorRegistry() {}
+	
+private:
+	friend class LLSingleton<LLWidgetCreatorRegistry>;
+};
+
+struct LLCompareTypeID
+{
+	bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
+	{
+		return lhs->before(*rhs);
+	}
+};
+
+
+class LLWidgetTemplateRegistry 
+:	public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetTemplateRegistry, LLCompareTypeID>
+{
+
+};
+
+// local static instance for registering a particular widget
+template<typename T, typename PARAM_BLOCK = typename T::Params>
+class LLRegisterWidget
+:	public LLWidgetCreatorRegistry::StaticRegistrar
+{
+public:
+	// register with either the provided builder, or the generic templated builder
+	LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func = NULL);
+};
+
+class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
+{
+private:
+	friend class LLSingleton<LLUICtrlFactory>;
 	LLUICtrlFactory();
-	// do not call!  needs to be public so run-time can clean up the singleton
-	virtual ~LLUICtrlFactory();
+	~LLUICtrlFactory();
+
+	// only partial specialization allowed in inner classes, so use extra dummy parameter
+	template <typename T, int DUMMY>
+	class ParamDefaults : public LLSingleton<ParamDefaults<T, DUMMY> > 
+	{
+	public:
+		ParamDefaults()
+		{
+			// recursively initialize from base class param block
+			((typename T::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename T::base_block_t, DUMMY>::instance().get());
+			// after initializing base classes, look up template file for this param block
+			std::string* param_block_tag = LLWidgetTemplateRegistry::instance().getValue(&typeid(T));
+			if (param_block_tag)
+			{
+				LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, mPrototype);
+			}
+		}
 
-	void setupPaths();
+		const T& get() { return mPrototype; }
 
-	void buildFloater(LLFloater* floaterp, const std::string &filename, 
-					const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE);
-	BOOL buildPanel(LLPanel* panelp, const std::string &filename,
-					const LLCallbackMap::map_t* factory_map = NULL);
+	private:
+		T mPrototype;
+	};
 
-	void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); }
-	void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); }
+	// base case for recursion, there are NO base classes of LLInitParam::BaseBlock
+	template<int DUMMY>
+	class ParamDefaults<LLInitParam::BaseBlock, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlock, DUMMY> >
+	{
+	public:
+		const LLInitParam::BaseBlock& get() { return mBaseBlock; }
+	private:
+		LLInitParam::BaseBlock mBaseBlock;
+	};
 
-	class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp);
-	class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp);
+public:
+
+	template<typename T>
+	static const T& getDefaultParams()
+	{
+		//#pragma message("Generating ParamDefaults")
+		return ParamDefaults<T, 0>::instance().get();
+	}
+
+	void buildFloater(LLFloater* floaterp, const std::string &filename, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL);
+	LLFloater* buildFloaterFromXML(const std::string& filename, BOOL open_floater = TRUE);
+	BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL);
 
 	// Does what you want for LLFloaters and LLPanels
 	// Returns 0 on success
 	S32 saveToXML(LLView* viewp, const std::string& filename);
 
-	// Rebuilds all currently built panels.
-	void rebuild();
+	std::string getCurFileName() { return mFileNames.empty() ? "" : mFileNames.back(); }
 
 	static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color);
 
 	LLPanel* createFactoryPanel(const std::string& name);
 
-	virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node);
-	virtual LLView* createWidget(LLPanel *parent, LLXMLNodePtr node);
+	void pushFactoryFunctions(const LLCallbackMap::map_t* map);
+	void popFactoryFunctions();
 
-	static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
+	template<typename T>
+	static T* create(typename T::Params& params, LLView* parent = NULL)
+	{
+		//#pragma message("Generating LLUICtrlFactory::create")
+		params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
+		//S32 foo = "test";
 
-	static const std::vector<std::string>& getXUIPaths();
+		if (!params.validateBlock())
+		{
+			llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
+		}
+		T* widget = new T(params);
+		widget->initFromParams(params);
+		if (parent)
+			widget->setParent(parent);
+		return widget;
+	}
 
-private:
-	bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root);
+	LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename = LLStringUtil::null,  LLXMLNodePtr output_node = NULL);
+
+	template<typename T>
+	static T* createFromFile(const std::string &filename, LLView *parent)
+	{
+		//#pragma message("Generating LLUICtrlFactory::createFromFile")
+		T* widget = NULL;
+
+		std::string skinned_filename = findSkinnedFilename(filename);
+		getInstance()->mFileNames.push_back(skinned_filename);
+		{
+			LLXMLNodePtr root_node;
+
+			if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
+			{
+				LLView* view = getInstance()->createFromXML(root_node, parent, filename);
+				if (view)
+				{
+					widget = dynamic_cast<T*>(view);
+					// not of right type, so delete it
+					if (!widget) 
+					{
+						delete view;
+						view = NULL;
+					}
+				
+				}
+			}
+			else
+			{
+				llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl;
+			}
+		}
+		getInstance()->mFileNames.pop_back();
 
-	typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t;
-	built_panel_t mBuiltPanels;
+		return widget;
+	}
 
-	typedef std::map<LLHandle<LLFloater>, std::string> built_floater_t;
-	built_floater_t mBuiltFloaters;
+	template <class T> 
+	static T* createDummyWidget(const std::string& name) 
+	{
+		//#pragma message("Generating LLUICtrlFactory::createDummyWidget")
+		typename T::Params params;
+		params.name(name);
+		
+		return create<T>(params);
+	}
 
-	std::deque<const LLCallbackMap::map_t*> mFactoryStack;
+	template<typename T, typename PARAM_BLOCK>
+	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
+	{
+		//#pragma message("Generating LLUICtrlFactory::defaultBuilder")
+		PARAM_BLOCK params(getDefaultParams<PARAM_BLOCK>());
 
-	static std::vector<std::string> sXUIPaths;
+		LLXUIParser::instance().readXUI(node, params);
 
-	LLPanel* mDummyPanel;
+		if (output_node)
+		{
+			// We always want to output top-left coordinates
+			PARAM_BLOCK output_params(params);
+			T::setupParamsForExport(output_params, parent);
+			// Export only the differences between this any default params
+			PARAM_BLOCK default_params(getDefaultParams<PARAM_BLOCK>());
+			output_node->setName(node->getName()->mString);
+			LLXUIParser::instance().writeXUI(
+				output_node, output_params, &default_params);
+		}
+
+		// Apply layout transformations, usually munging rect
+		T::setupParams(params, parent);
+
+		if (!params.validateBlock())
+		{
+			llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
+		}
+		T* widget = new T(params);
+		widget->initFromParams(params);
+
+		if (parent)
+		{
+			S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
+			setCtrlParent(widget, parent, tab_group);
+		}
+
+		widget->addChildren(node, output_node);
+
+		if (!widget->postBuild())
+		{
+			delete widget;
+			return NULL;
+		}
+
+		return widget;
+	}
+
+	static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
+
+	static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
+
+private:
+	//static void setCtrlValue(LLView* view, LLXMLNodePtr node);
+	static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group);
+
+	// Avoid directly using LLUI and LLDir in the template code
+	static std::string findSkinnedFilename(const std::string& filename);
+
+	typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
+	factory_stack_t					mFactoryStack;
+
+	LLPanel*		mDummyPanel;
+	std::vector<std::string>	mFileNames;
 };
 
+// this is here to make gcc happy with reference to LLUICtrlFactory
+template<typename T, typename PARAM_BLOCK>
+LLRegisterWidget<T, PARAM_BLOCK>::LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func)
+:	LLWidgetCreatorRegistry::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T, PARAM_BLOCK> : func)
+{
+	//FIXME: inventory_panel will register itself with LLPanel::Params but it does have its own params...:(
+	LLWidgetTemplateRegistry::instance().defaultRegistrar().add(&typeid(PARAM_BLOCK), tag);
+}
+
 
 #endif //LLUICTRLFACTORY_H
diff --git a/indra/llui/lluifwd.h b/indra/llui/lluifwd.h
index 32d5c9b44f..f99bb39fdd 100644
--- a/indra/llui/lluifwd.h
+++ b/indra/llui/lluifwd.h
@@ -53,7 +53,6 @@ class LLSlider;
 class LLSliderCtrl;
 class LLSpinCtrl;
 class LLTabContainer;
-class LLTabContainerVertical;
 class LLTextBox;
 class LLTextEditor;
 class LLTextureCtrl;
diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp
new file mode 100644
index 0000000000..0ed2283742
--- /dev/null
+++ b/indra/llui/lluiimage.cpp
@@ -0,0 +1,158 @@
+/** 
+ * @file lluiimage.cpp
+ * @brief UI implementation
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Utilities functions the user interface needs
+
+//#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+// Project includes
+#include "lluiimage.h"
+#include "llui.h"
+
+LLUIImage::LLUIImage(const std::string& name, LLPointer<LLImageGL> image) :
+						mName(name),
+						mImage(image),
+						mScaleRegion(0.f, 1.f, 1.f, 0.f),
+						mClipRegion(0.f, 1.f, 1.f, 0.f),
+						mUniformScaling(TRUE),
+						mNoClip(TRUE)
+{
+}
+
+void LLUIImage::setClipRegion(const LLRectf& region) 
+{ 
+	mClipRegion = region; 
+	mNoClip = mClipRegion.mLeft == 0.f
+				&& mClipRegion.mRight == 1.f
+				&& mClipRegion.mBottom == 0.f
+				&& mClipRegion.mTop == 1.f;
+}
+
+void LLUIImage::setScaleRegion(const LLRectf& region) 
+{ 
+	mScaleRegion = region; 
+	mUniformScaling = mScaleRegion.mLeft == 0.f
+					&& mScaleRegion.mRight == 1.f
+					&& mScaleRegion.mBottom == 0.f
+					&& mScaleRegion.mTop == 1.f;
+}
+
+//TODO: move drawing implementation inside class
+void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const
+{
+	gl_draw_image(x, y, mImage, color, mClipRegion);
+}
+
+void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const
+{
+	if (mUniformScaling)
+	{
+		gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion);
+	}
+	else
+	{
+		gl_draw_scaled_image_with_border(
+			x, y, 
+			width, height, 
+			mImage, 
+			color,
+			FALSE,
+			mClipRegion,
+			mScaleRegion);
+	}
+}
+
+void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const
+{
+	gl_draw_scaled_image_with_border(
+		x, y, 
+		width, height, 
+		mImage, 
+		color, 
+		TRUE,
+		mClipRegion,
+		mScaleRegion);
+}
+
+void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const
+{
+	LLRect border_rect;
+	border_rect.setOriginAndSize(x, y, width, height);
+	border_rect.stretch(border_width, border_width);
+	drawSolid(border_rect, color);
+}
+
+S32 LLUIImage::getWidth() const
+{ 
+	// return clipped dimensions of actual image area
+	return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth()); 
+}
+
+S32 LLUIImage::getHeight() const
+{ 
+	// return clipped dimensions of actual image area
+	return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight()); 
+}
+
+S32 LLUIImage::getTextureWidth() const
+{
+	return mImage->getWidth(0);
+}
+
+S32 LLUIImage::getTextureHeight() const
+{
+	return mImage->getHeight(0);
+}
+
+namespace LLInitParam
+{
+	LLUIImage* TypedParam<LLUIImage*>::getValueFromBlock() const
+	{
+		LLUIImage* imagep =  LLUI::getUIImage(name());
+		if (!imagep)
+		{
+			// default to current value
+			imagep = mData.mValue;
+		}
+		return imagep;
+	}
+
+	template<>
+	bool ParamCompare<LLUIImage*>::equals(
+		LLUIImage* const &a,
+		LLUIImage* const &b)
+	{
+		// force all LLUIImages for XML UI export to be "non-default"
+		return false;
+	}
+}
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
new file mode 100644
index 0000000000..cd660a0954
--- /dev/null
+++ b/indra/llui/lluiimage.h
@@ -0,0 +1,113 @@
+/** 
+ * @file lluiimage.h
+ * @brief wrapper for images used in the UI that handles smart scaling, etc.
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLUIIMAGE_H
+#define LL_LLUIIMAGE_H
+
+#include "llgl.h"
+#include "llimagegl.h"
+#include "llrefcount.h"
+#include "llrect.h"
+#include <boost/function.hpp>
+#include "llinitparam.h"
+
+extern const LLColor4 UI_VERTEX_COLOR;
+
+class LLUIImage : public LLRefCount
+{
+public:
+	LLUIImage(const std::string& name, LLPointer<LLImageGL> image);
+
+	void setClipRegion(const LLRectf& region);
+	void setScaleRegion(const LLRectf& region);
+
+	LLPointer<LLImageGL> getImage() { return mImage; }
+	const LLPointer<LLImageGL>& getImage() const { return mImage; }
+
+	void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const;
+	void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const;
+	void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); }
+	
+	void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const;
+	void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); }
+	void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, mImage->getWidth(0), mImage->getHeight(0), color); }
+
+	void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const;
+	void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); }
+	void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, mImage->getWidth(0), mImage->getHeight(0), color, border_width); }
+	
+	const std::string& getName() const { return mName; }
+
+	S32 getWidth() const;
+	S32 getHeight() const;
+
+	// returns dimensions of underlying textures, which might not be equal to ui image portion
+	S32 getTextureWidth() const;
+	S32 getTextureHeight() const;
+
+protected:
+	std::string			mName;
+	LLRectf				mScaleRegion;
+	LLRectf				mClipRegion;
+	LLPointer<LLImageGL> mImage;
+	BOOL				mUniformScaling;
+	BOOL				mNoClip;
+};
+
+namespace LLInitParam
+{
+	template<>
+	class TypedParam<LLUIImage*, TypeValues<LLUIImage*>, false> 
+	:	public BlockValue<LLUIImage*>
+	{
+		typedef boost::add_reference<boost::add_const<LLUIImage*>::type>::type	T_const_ref;
+		typedef BlockValue<LLUIImage*> super_t;
+	public:
+		Optional<std::string> name;
+
+		TypedParam(BlockDescriptor& descriptor, const std::string& name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func)
+		:	super_t(descriptor, name, value, func)
+		{
+		}
+
+		LLUIImage* getValueFromBlock() const;
+	};
+
+	// Need custom comparison function for our test app, which only loads
+	// LLUIImage* as NULL.
+	template<>
+	bool ParamCompare<LLUIImage*>::equals(
+		LLUIImage* const &a, LLUIImage* const &b);
+}
+
+typedef LLPointer<LLUIImage> LLUIImagePtr;
+#endif
diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp
index 0b76b8e814..ce73990d27 100644
--- a/indra/llui/lluistring.cpp
+++ b/indra/llui/lluistring.cpp
@@ -33,6 +33,7 @@
 #include "linden_common.h"
 #include "lluistring.h"
 #include "llsd.h"
+#include "lltrans.h"
 
 const LLStringUtil::format_map_t LLUIString::sNullArgs;
 
@@ -112,6 +113,10 @@ void LLUIString::clear()
 void LLUIString::format()
 {
 	mResult = mOrig;
-	LLStringUtil::format(mResult, mArgs);
+	
+	// get the defailt args + local args
+	LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs();
+	combined_args.insert(mArgs.begin(), mArgs.end());
+	LLStringUtil::format(mResult, combined_args);
 	mWResult = utf8str_to_wstring(mResult);
 }
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 2350ea6050..462fd16b60 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -56,17 +56,18 @@
 #include "lltexteditor.h"
 #include "lltextbox.h"
 
-//HACK: this allows you to instantiate LLView from xml with "<view/>" which we don't want
-static LLRegisterWidget<LLView> r("view");
-
 BOOL	LLView::sDebugRects = FALSE;
 BOOL	LLView::sDebugKeys = FALSE;
 S32		LLView::sDepth = 0;
 BOOL	LLView::sDebugMouseHandling = FALSE;
 std::string LLView::sMouseHandlerMessage;
-BOOL	LLView::sEditingUI = FALSE;
+//BOOL	LLView::sEditingUI = FALSE;
 BOOL	LLView::sForceReshape = FALSE;
-LLView*	LLView::sEditingUIView = NULL;
+//LLView*	LLView::sEditingUIView = NULL;
+std::set<LLView*> LLView::sPreviewHighlightedElements;
+BOOL LLView::sHighlightingDiffs = FALSE;
+LLView* LLView::sPreviewClickedElement = NULL;
+BOOL	LLView::sDrawPreviewHighlights = FALSE;
 S32		LLView::sLastLeftXML = S32_MIN;
 S32		LLView::sLastBottomXML = S32_MIN;
 
@@ -74,77 +75,76 @@ S32		LLView::sLastBottomXML = S32_MIN;
 BOOL LLView::sIsDrawing = FALSE;
 #endif
 
-LLView::LLView() :
-	mParentView(NULL),
-	mReshapeFlags(FOLLOWS_NONE),
-	mDefaultTabGroup(0),
-	mEnabled(TRUE),
-	mMouseOpaque(TRUE),
-	mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
-	mSaveToXML(TRUE),
-	mIsFocusRoot(FALSE),
-	mLastVisible(TRUE),
-	mUseBoundingRect(FALSE),
-	mVisible(TRUE),
-	mNextInsertionOrdinal(0),
-	mHoverCursor(UI_CURSOR_ARROW)
-{
-}
-
-LLView::LLView(const std::string& name, BOOL mouse_opaque) :
+LLView::Params::Params()
+:	name("name", std::string("unnamed")),
+	enabled("enabled", true),
+	visible("visible", true),
+	mouse_opaque("mouse_opaque", true),
+	follows("follows"),
+	hover_cursor("hover_cursor", "UI_CURSOR_ARROW"),
+	use_bounding_rect("use_bounding_rect", false),
+	tab_group("tab_group", 0),
+	default_tab_group("default_tab_group"),
+	tool_tip("tool_tip"),
+	sound_flags("sound_flags", MOUSE_UP),
+	font("font", LLFontGL::getFontSansSerif()),
+	font_halign("halign"),
+	font_valign("valign"),
+	layout("layout"),
+	rect("rect"),
+	bottom_delta("bottom_delta", S32_MAX),
+	left_delta("left_delta", S32_MAX),
+	top_delta("top_delta"),
+	right_delta("right_delta"),
+	center_horiz("center_horiz", false),
+	center_vert("center_vert", false),
+	serializable("", false),
+	user_resize("user_resize"),
+	auto_resize("auto_resize"),
+	needs_translate("translate")
+{
+	addSynonym(rect, "");
+}
+
+LLView::LLView(const LLView::Params& p)
+:	mName(p.name),
 	mParentView(NULL),
-	mName(name),
 	mReshapeFlags(FOLLOWS_NONE),
-	mDefaultTabGroup(0),
-	mEnabled(TRUE),
-	mMouseOpaque(mouse_opaque),
-	mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
-	mSaveToXML(TRUE),
-	mIsFocusRoot(FALSE),
-	mLastVisible(TRUE),
-	mUseBoundingRect(FALSE),
-	mVisible(TRUE),
-	mNextInsertionOrdinal(0),
-	mHoverCursor(UI_CURSOR_ARROW)
-{
-}
-
-
-LLView::LLView(
-	const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) :
-	mParentView(NULL),
-	mName(name),
-	mRect(rect),
-	mBoundingRect(rect),
-	mReshapeFlags(reshape),
-	mDefaultTabGroup(0),
-	mEnabled(TRUE),
-	mMouseOpaque(mouse_opaque),
-	mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
-	mSaveToXML(TRUE),
+	mSaveToXML(p.serializable),
 	mIsFocusRoot(FALSE),
-	mLastVisible(TRUE),
-	mUseBoundingRect(FALSE),
-	mVisible(TRUE),
+	mLastVisible(FALSE),
 	mNextInsertionOrdinal(0),
-	mHoverCursor(UI_CURSOR_ARROW)
+	mHoverCursor(getCursorFromString(p.hover_cursor)),
+	mEnabled(p.enabled),
+	mVisible(p.visible),
+	mMouseOpaque(p.mouse_opaque),
+	mSoundFlags(p.sound_flags),
+	mUseBoundingRect(p.use_bounding_rect),
+	mDefaultTabGroup(p.default_tab_group),
+	mLastTabGroup(0),
+	mToolTipMsg((LLStringExplicit)p.tool_tip())
 {
+	// create rect first, as this will supply initial follows flags
+	setShape(p.rect);
+	parseFollowsFlags(p);
 }
 
-
 LLView::~LLView()
 {
 	//llinfos << "Deleting view " << mName << ":" << (void*) this << llendl;
 // 	llassert(LLView::sIsDrawing == FALSE);
+	
+//	llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators
+	
 	if( gFocusMgr.getKeyboardFocus() == this )
 	{
-		llwarns << "View holding keyboard focus deleted: " << getName() << ".  Keyboard focus removed." << llendl;
+		//llwarns << "View holding keyboard focus deleted: " << getName() << ".  Keyboard focus removed." << llendl;
 		gFocusMgr.removeKeyboardFocusWithoutCallback( this );
 	}
 
 	if( hasMouseCapture() )
 	{
-		llwarns << "View holding mouse capture deleted: " << getName() << ".  Mouse capture removed." << llendl;
+		//llwarns << "View holding mouse capture deleted: " << getName() << ".  Mouse capture removed." << llendl;
 		gFocusMgr.removeMouseCaptureWithoutCallback( this );
 	}
 
@@ -155,14 +155,6 @@ LLView::~LLView()
 		mParentView->removeChild(this);
 	}
 
-	dispatch_list_t::iterator itor;
-	for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
-	{
-		(*itor).second->clearDispatchers();
-	}
-
-	std::for_each(mFloaterControls.begin(), mFloaterControls.end(),
-				  DeletePairedPointer());
 	std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(),
 				  DeletePairedPointer());
 }
@@ -185,7 +177,6 @@ BOOL LLView::isPanel() const
 	return FALSE;
 }
 
-// virtual
 void LLView::setToolTip(const LLStringExplicit& msg)
 {
 	mToolTipMsg = msg;
@@ -232,19 +223,31 @@ const std::string& LLView::getName() const
 
 void LLView::sendChildToFront(LLView* child)
 {
+// 	llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
 	if (child && child->getParent() == this) 
 	{
-		mChildList.remove( child );
-		mChildList.push_front(child);
+		// minor optimization, but more importantly,
+		//  won't temporarily create an empty list
+		if (child != mChildList.front())
+		{
+			mChildList.remove( child );
+			mChildList.push_front(child);
+		}
 	}
 }
 
 void LLView::sendChildToBack(LLView* child)
 {
+// 	llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
 	if (child && child->getParent() == this) 
 	{
-		mChildList.remove( child );
-		mChildList.push_back(child);
+		// minor optimization, but more importantly,
+		//  won't temporarily create an empty list
+		if (child != mChildList.back())
+		{
+			mChildList.remove( child );
+			mChildList.push_back(child);
+		}
 	}
 }
 
@@ -264,12 +267,46 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
 	}
 }
 
-void LLView::addChild(LLView* child, S32 tab_group)
+void LLView::addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node)
+{
+	if (node.isNull()) return;
+
+	for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
+	{
+		LLXMLNodePtr outputChild;
+		if (output_node) 
+		{
+			outputChild = output_node->createChild("", FALSE);
+		}
+
+		if (!LLUICtrlFactory::getInstance()->createFromXML(child_node, this, LLStringUtil::null, outputChild))
+		{
+			std::string child_name = std::string(child_node->getName()->mString);
+			if (child_name.find(".") == std::string::npos)
+			{
+				llwarns << "Could not create widget named " << child_node->getName()->mString << llendl;
+			}
+		}
+
+		if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty())
+		{
+			output_node->deleteChild(outputChild);
+		}
+	}
+}
+
+// virtual
+bool LLView::addChild(LLView* child, S32 tab_group)
 {
+	if (!child)
+	{
+		return false;
+	}
 	if (mParentView == child) 
 	{
 		llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
 	}
+
 	// remove from current parent
 	if (child->mParentView) 
 	{
@@ -282,55 +319,46 @@ void LLView::addChild(LLView* child, S32 tab_group)
 	// add to ctrl list if is LLUICtrl
 	if (child->isCtrl())
 	{
-		// controls are stored in reverse order from render order
-		addCtrlAtEnd((LLUICtrl*) child, tab_group);
+		LLUICtrl* ctrl = static_cast<LLUICtrl*>(child);
+		mCtrlOrder.insert(tab_order_pair_t(ctrl,
+							tab_order_t(tab_group, mNextInsertionOrdinal)));
+
+		mNextInsertionOrdinal++;
 	}
 
 	child->mParentView = this;
 	updateBoundingRect();
+	mLastTabGroup = tab_group;
+	return true;
 }
 
 
-void LLView::addChildAtEnd(LLView* child, S32 tab_group)
+bool LLView::addChildInBack(LLView* child, S32 tab_group)
 {
-	if (mParentView == child) 
-	{
-		llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
-	}
-	// remove from current parent
-	if (child->mParentView) 
+	if(addChild(child, tab_group))
 	{
-		child->mParentView->removeChild(child);
+		sendChildToBack(child);
+		return true;
 	}
 
-	// add to back of child list
-	mChildList.push_back(child);
-
-	// add to ctrl list if is LLUICtrl
-	if (child->isCtrl())
-	{
-		// controls are stored in reverse order from render order
-		addCtrl((LLUICtrl*) child, tab_group);
-	}
-	
-	child->mParentView = this;
-	updateBoundingRect();
+	return false;
 }
 
 // remove the specified child from the view, and set it's parent to NULL.
-void LLView::removeChild(LLView* child, BOOL deleteIt)
+void LLView::removeChild(LLView* child)
 {
+	//llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs
 	if (child->mParentView == this) 
 	{
 		mChildList.remove( child );
 		child->mParentView = NULL;
 		if (child->isCtrl())
 		{
-			removeCtrl((LLUICtrl*)child);
-		}
-		if (deleteIt)
-		{
-			delete child;
+			child_tab_order_t::iterator found = mCtrlOrder.find(static_cast<LLUICtrl*>(child));
+			if(found != mCtrlOrder.end())
+			{
+				mCtrlOrder.erase(found);
+			}
 		}
 	}
 	else
@@ -340,28 +368,6 @@ void LLView::removeChild(LLView* child, BOOL deleteIt)
 	updateBoundingRect();
 }
 
-void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
-{
-	mCtrlOrder.insert(tab_order_pair_t(ctrl,
-								tab_order_t(tab_group, mNextInsertionOrdinal++)));
-}
-
-void LLView::addCtrl( LLUICtrl* ctrl, S32 tab_group)
-{
-	// add to front of list by using negative ordinal, which monotonically increases
-	mCtrlOrder.insert(tab_order_pair_t(ctrl,
-								tab_order_t(tab_group, -1 * mNextInsertionOrdinal++)));
-}
-
-void LLView::removeCtrl(LLUICtrl* ctrl)
-{
-	child_tab_order_t::iterator found = mCtrlOrder.find(ctrl);
-	if(found != mCtrlOrder.end())
-	{
-		mCtrlOrder.erase(found);
-	}
-}
-
 LLView::ctrl_list_t LLView::getCtrlList() const
 {
 	ctrl_list_t controls;
@@ -651,7 +657,7 @@ BOOL LLView::canSnapTo(const LLView* other_view)
 }
 
 // virtual
-void LLView::snappedTo(const LLView* snap_view)
+void LLView::setSnappedTo(const LLView* snap_view)
 {
 }
 
@@ -669,6 +675,17 @@ BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
 	return handled;
 }
 
+void LLView::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+	//llinfos << "Mouse entered " << getName() << llendl;
+}
+
+void LLView::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+	//llinfos << "Mouse left " << getName() << llendl;
+}
+
+
 std::string LLView::getShowNamesToolTip()
 {
 	LLView* view = getParent();
@@ -729,23 +746,14 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s
 
 	// get our own tooltip
 	tool_tip = mToolTipMsg.getString();
-	if (
-		LLUI::sShowXUINames 
+	
+	if (LLUI::sShowXUINames 
 		&& (tool_tip.find(".xml", 0) == std::string::npos) 
 		&& (mName.find("Drag", 0) == std::string::npos))
 	{
 		tool_tip = getShowNamesToolTip();
 	}
 
-	BOOL show_names_text_box = LLUI::sShowXUINames && dynamic_cast<LLTextBox*>(this) != NULL;
-
-	// don't allow any siblings to handle this event
-	// even if we don't have a tooltip
-	if (getMouseOpaque() || show_names_text_box)
-	{
-		handled = TRUE;
-	}
-
 	if(!tool_tip.empty())
 	{
 		msg = tool_tip;
@@ -757,7 +765,13 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s
 		localPointToScreen(
 			mRect.getWidth(), mRect.getHeight(),
 			&(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
-		
+	}
+	// don't allow any siblings to handle this event
+	// even if we don't have a tooltip
+	if (getMouseOpaque() || 
+		(!tool_tip.empty() && 
+		 (!LLUI::sShowXUINames || dynamic_cast<LLTextBox*>(this))))
+	{
 		handled = TRUE;
 	}
 
@@ -923,22 +937,22 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
 		handled_view = this;
 	}
 
-	// HACK If we're editing UI, select the leaf view that ate the click.
-	if (sEditingUI && handled_view)
-	{
-		// need to find leaf views, big hack
-		LLButton* buttonp = dynamic_cast<LLButton*>(handled_view);
-		LLLineEditor* line_editorp = dynamic_cast<LLLineEditor*>(handled_view);
-		LLTextEditor* text_editorp = dynamic_cast<LLTextEditor*>(handled_view);
-		LLTextBox* text_boxp = dynamic_cast<LLTextBox*>(handled_view);
-		if (buttonp
-			|| line_editorp
-			|| text_editorp
-			|| text_boxp)
-		{
-			sEditingUIView = handled_view;
-		}
-	}
+	//// HACK If we're editing UI, select the leaf view that ate the click.
+	//if (sEditingUI && handled_view)
+	//{
+	//	// need to find leaf views, big hack
+	//	LLButton* buttonp = dynamic_cast<LLButton*>(handled_view);
+	//	LLLineEditor* line_editorp = dynamic_cast<LLLineEditor*>(handled_view);
+	//	LLTextEditor* text_editorp = dynamic_cast<LLTextEditor*>(handled_view);
+	//	LLTextBox* text_boxp = dynamic_cast<LLTextBox*>(handled_view);
+	//	if (buttonp
+	//		|| line_editorp
+	//		|| text_editorp
+	//		|| text_boxp)
+	//	{
+	//		sEditingUIView = handled_view;
+	//	}
+	//}
 
 	return handled;
 }
@@ -1164,6 +1178,7 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
 				{
 					sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
 				}
+
 				handled_view = viewp;
 				break;
 			}
@@ -1326,55 +1341,58 @@ void LLView::draw()
 		}
 	}
 
-	LLRect rootRect = getRootView()->getRect();
-	LLRect screenRect;
-
-	// draw focused control on top of everything else
-	LLView* focus_view = gFocusMgr.getKeyboardFocus();
-	if (focus_view && focus_view->getParent() != this)
+	if (!mChildList.empty())
 	{
-		focus_view = NULL;
-	}
+		LLRect rootRect = getRootView()->getRect();
+		LLRect screenRect;
 
-	++sDepth;
-	for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
-	{
-		LLView *viewp = *child_iter;
+		// draw focused control on top of everything else
+		LLView* focus_view = gFocusMgr.getKeyboardFocus();
+		if (focus_view && focus_view->getParent() != this)
+		{
+			focus_view = NULL;
+		}
+
+		++sDepth;
 
-		if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid())
+		for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();)  // ++child_iter)
 		{
-			// Only draw views that are within the root view
-			localRectToScreen(viewp->getRect(),&screenRect);
-			if ( rootRect.rectInRect(&screenRect) )
+			child_list_reverse_iter_t child = child_iter++;
+			LLView *viewp = *child;
+
+			if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid())
 			{
-				glMatrixMode(GL_MODELVIEW);
-				LLUI::pushMatrix();
+				// Only draw views that are within the root view
+				localRectToScreen(viewp->getRect(),&screenRect);
+				if ( rootRect.rectInRect(&screenRect) )
 				{
-					LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
-					viewp->draw();
+					glMatrixMode(GL_MODELVIEW);
+					LLUI::pushMatrix();
+					{
+						LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
+						viewp->draw();
+					}
+					LLUI::popMatrix();
 				}
-				LLUI::popMatrix();
 			}
-		}
 
-	}
-	--sDepth;
+		}
+		--sDepth;
 
-	if (focus_view && focus_view->getVisible())
-	{
-		drawChild(focus_view);
+		if (focus_view && focus_view->getVisible())
+		{
+			drawChild(focus_view);
+		}
 	}
 
-	// HACK
-	if (sEditingUI && this == sEditingUIView)
-	{
-		drawDebugRect();
-	}
+	gGL.getTexUnit(0)->disable();
 }
 
 //Draw a box for debugging.
 void LLView::drawDebugRect()
 {
+	std::set<LLView*>::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);	// figure out if it's a previewed element
+
 	LLUI::pushMatrix();
 	{
 		// drawing solids requires texturing be disabled
@@ -1389,9 +1407,21 @@ void LLView::drawDebugRect()
 
 		// draw red rectangle for the border
 		LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
-		if (sEditingUI)
+		//if (sEditingUI)
+		//{
+		//	border_color.mV[0] = 1.f;
+		//}
+		if(preview_iter != sPreviewHighlightedElements.end())
 		{
-			border_color.mV[0] = 1.f;
+			if(LLView::sPreviewClickedElement && this == sPreviewClickedElement)
+			{
+				border_color = LLColor4::red;
+			}
+			else
+			{
+				static LLUICachedControl<LLColor4> scroll_highlighted_color ("ScrollHighlightedColor", *(new LLColor4));
+				border_color = scroll_highlighted_color;
+			}
 		}
 		else
 		{
@@ -1414,8 +1444,8 @@ void LLView::drawDebugRect()
 			gGL.vertex2i(0, debug_rect.getHeight() - 1);
 		gGL.end();
 
-		// Draw the name if it's not a leaf node
-		if (mChildList.size() && !sEditingUI)
+		// Draw the name if it's not a leaf node or not in editing or preview mode
+		if (mChildList.size() && preview_iter == sPreviewHighlightedElements.end())
 		{
 			//char temp[256];
 			S32 x, y;
@@ -1425,7 +1455,7 @@ void LLView::drawDebugRect()
 			std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
 										debug_rect.getWidth(), debug_rect.getHeight());
 			LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
-												LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
+												LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
 												S32_MAX, S32_MAX, NULL, FALSE);
 		}
 	}
@@ -1581,15 +1611,28 @@ void LLView::updateBoundingRect()
 	}
 }
 
-LLRect LLView::getScreenRect() const
+LLRect LLView::calcScreenRect() const
 {
-	// *FIX: check for one-off error
 	LLRect screen_rect;
 	localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom);
 	localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop);
 	return screen_rect;
 }
 
+LLRect LLView::calcScreenBoundingRect() const
+{
+	LLRect screen_rect;
+	// get bounding rect, if used
+	LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect;
+
+	// convert to local coordinates, as defined by mRect
+	bounding_rect.translate(-mRect.mLeft, -mRect.mBottom);
+
+	localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom);
+	localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop);
+	return screen_rect;
+}
+
 LLRect LLView::getLocalBoundingRect() const
 {
 	LLRect local_bounding_rect = getBoundingRect();
@@ -1688,7 +1731,12 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_
 
 	if (create_if_missing)
 	{
-		return createDummyWidget<LLView>(name);
+		LLView* view = getDummyWidget<LLView>(name);
+		if (!view)
+		{
+			 view = LLUICtrlFactory::createDummyWidget<LLView>(name);
+		}
+		return view;
 	}
 	return NULL;
 }
@@ -1777,12 +1825,32 @@ LLView* LLView::getRootView()
 	return view;
 }
 
-BOOL LLView::deleteViewByHandle(LLHandle<LLView> handle)
+LLView* LLView::findPrevSibling(LLView* child)
+{
+	child_list_t::iterator prev_it = std::find(mChildList.begin(), mChildList.end(), child);
+	if (prev_it != mChildList.end() && prev_it != mChildList.begin())
+	{
+		return *(--prev_it);
+	}
+	return NULL;
+}
+
+LLView* LLView::findNextSibling(LLView* child)
+{
+	child_list_t::iterator next_it = std::find(mChildList.begin(), mChildList.end(), child);
+	if (next_it != mChildList.end())
+	{
+		next_it++;
+	}
+
+	return (next_it != mChildList.end()) ? *next_it : NULL;
+}
+
+void LLView::deleteViewByHandle(LLHandle<LLView> handle)
 {
 	LLView* viewp = handle.get();
 
 	delete viewp;
-	return viewp != NULL;
 }
 
 
@@ -1943,132 +2011,6 @@ BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* o
 	return FALSE;
 }
 
-// virtual
-LLXMLNodePtr LLView::getXML(bool save_children) const
-{
-	//FIXME: need to provide actual derived type tag, probably outside this method
-	LLXMLNodePtr node = new LLXMLNode("view", FALSE);
-
-	node->createChild("name", TRUE)->setStringValue(getName());
-	node->createChild("width", TRUE)->setIntValue(getRect().getWidth());
-	node->createChild("height", TRUE)->setIntValue(getRect().getHeight());
-
-	LLView* parent = getParent();
-	S32 left = getRect().mLeft;
-	S32 bottom = getRect().mBottom;
-	if (parent) bottom -= parent->getRect().getHeight();
-
-	node->createChild("left", TRUE)->setIntValue(left);
-	node->createChild("bottom", TRUE)->setIntValue(bottom);
-
-	U32 follows_flags = getFollows();
-	if (follows_flags)
-	{
-		std::stringstream buffer;
-		bool pipe = false;
-		if (followsLeft())
-		{
-			buffer << "left";
-			pipe = true;
-		}
-		if (followsTop())
-		{
-			if (pipe) buffer << "|";
-			buffer << "top";
-			pipe = true;
-		}
-		if (followsRight())
-		{
-			if (pipe) buffer << "|";
-			buffer << "right";
-			pipe = true;
-		}
-		if (followsBottom())
-		{
-			if (pipe) buffer << "|";
-			buffer << "bottom";
-		}
-		node->createChild("follows", TRUE)->setStringValue(buffer.str());
-	}
-	// Export all widgets as enabled and visible - code must disable.
-	node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque );
-	if (!mToolTipMsg.getString().empty())
-	{
-		node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg.getString());
-	}
-	if (mSoundFlags != MOUSE_UP)
-	{
-		node->createChild("sound_flags", TRUE)->setIntValue((S32)mSoundFlags);
-	}
-
-	node->createChild("enabled", TRUE)->setBoolValue(getEnabled());
-
-	if (!mControlName.empty())
-	{
-		node->createChild("control_name", TRUE)->setStringValue(mControlName);
-	}
-	return node;
-}
-
-//static 
-LLView* LLView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	LLView* viewp = new LLView();
-	viewp->initFromXML(node, parent);
-	return viewp;
-}
-
-// static
-void LLView::addColorXML(LLXMLNodePtr node, const LLColor4& color,
-							const char* xml_name, const char* control_name)
-{
-	if (color != LLUI::sColorsGroup->getColor(ll_safe_string(control_name)))
-	{
-		node->createChild(xml_name, TRUE)->setFloatValue(4, color.mV);
-	}
-}
-
-//static 
-std::string LLView::escapeXML(const std::string& xml, std::string& indent)
-{
-	std::string ret = indent + "\"" + LLXMLNode::escapeXML(xml);
-
-	//replace every newline with a close quote, new line, indent, open quote
-	size_t index = ret.size()-1;
-	size_t fnd;
-	
-	while ((fnd = ret.rfind("\n", index)) != std::string::npos)
-	{
-		ret.replace(fnd, 1, "\"\n" + indent + "\"");
-		index = fnd-1;
-	}
-
-	//append close quote
-	ret.append("\"");
-	
-	return ret;	
-}
-
-// static
-LLWString LLView::escapeXML(const LLWString& xml)
-{
-	LLWString out;
-	for (LLWString::size_type i = 0; i < xml.size(); ++i)
-	{
-		llwchar c = xml[i];
-		switch(c)
-		{
-		case '"':	out.append(utf8string_to_wstring("&quot;"));	break;
-		case '\'':	out.append(utf8string_to_wstring("&apos;"));	break;
-		case '&':	out.append(utf8string_to_wstring("&amp;"));		break;
-		case '<':	out.append(utf8string_to_wstring("&lt;"));		break;
-		case '>':	out.append(utf8string_to_wstring("&gt;"));		break;
-		default:	out.push_back(c); break;
-		}
-	}
-	return out;
-}
-
 // static
 const LLCtrlQuery & LLView::getTabOrderQuery()
 {
@@ -2105,7 +2047,12 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()
 }
 
 
-void	LLView::userSetShape(const LLRect& new_rect)
+void	LLView::setShape(const LLRect& new_rect, bool by_user)
+{
+	handleReshape(new_rect, by_user);
+}
+
+void LLView::handleReshape(const LLRect& new_rect, bool by_user)
 {
 	reshape(new_rect.getWidth(), new_rect.getHeight());
 	translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom);
@@ -2353,306 +2300,52 @@ LLView*	LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna
 // Listener dispatch functions
 //-----------------------------------------------------------------------------
 
-void LLView::registerEventListener(std::string name, LLSimpleListener* function)
-{
-	mDispatchList.insert(std::pair<std::string, LLSimpleListener*>(name, function));
-}
-
-void LLView::deregisterEventListener(std::string name)
-{
-	dispatch_list_t::iterator itor = mDispatchList.find(name);
-	if (itor != mDispatchList.end())
-	{
-		mDispatchList.erase(itor);
-	}
-}
-
-std::string LLView::findEventListener(LLSimpleListener *listener) const
-{
-	dispatch_list_t::const_iterator itor;
-	for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
-	{
-		if (itor->second == listener)
-		{
-			return itor->first;
-		}
-	}
-	if (mParentView)
-	{
-		return mParentView->findEventListener(listener);
-	}
-	return LLStringUtil::null;
-}
-
-LLSimpleListener* LLView::getListenerByName(const std::string& callback_name)
-{
-	LLSimpleListener* callback = NULL;
-	dispatch_list_t::iterator itor = mDispatchList.find(callback_name);
-	if (itor != mDispatchList.end())
-	{
-		callback = itor->second;
-	}
-	else if (mParentView)
-	{
-		callback = mParentView->getListenerByName(callback_name);
-	}
-	return callback;
-}
 
 LLControlVariable *LLView::findControl(const std::string& name)
 {
-	control_map_t::iterator itor = mFloaterControls.find(name);
-	if (itor != mFloaterControls.end())
+	LLControlVariable* control;
+	control = LLUI::sSettingGroups["color"]->getControl(name);
+	if (control)
 	{
-		return itor->second;
+		return control;
 	}
-	if (mParentView)
-	{
-		return mParentView->findControl(name);
-	}
-	return LLUI::sConfigGroup->getControl(name);
+	
+	return LLUI::sSettingGroups["config"]->getControl(name);
 }
 
 const S32 FLOATER_H_MARGIN = 15;
 const S32 MIN_WIDGET_HEIGHT = 10;
 const S32 VPAD = 4;
 
-// static
-U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect)
-{
-	U32 follows = 0;
-	S32 x = rect.mLeft;
-	S32 y = rect.mBottom;
-	S32 w = rect.getWidth();
-	S32 h = rect.getHeight();
-
-	U32 last_x = 0;
-	U32 last_y = 0;
-	if (parent_view)
-	{
-		last_y = parent_view->getRect().getHeight();
-		child_list_t::const_iterator itor = parent_view->getChildList()->begin();
-		if (itor != parent_view->getChildList()->end())
-		{
-			LLView *last_view = (*itor);
-			if (last_view->getSaveToXML())
-			{
-				last_x = last_view->getRect().mLeft;
-				last_y = last_view->getRect().mBottom;
-			}
-		}
-	}
-
-	std::string rect_control;
-	node->getAttributeString("rect_control", rect_control);
-	if (! rect_control.empty())
-	{
-		LLRect rect = LLUI::sConfigGroup->getRect(rect_control);
-		x = rect.mLeft;
-		y = rect.mBottom;
-		w = rect.getWidth();
-		h = rect.getHeight();
-	}
-	
-	if (node->hasAttribute("left"))
-	{
-		node->getAttributeS32("left", x);
-	}
-	if (node->hasAttribute("bottom"))
-	{
-		node->getAttributeS32("bottom", y);
-	}
-
-	// Make your width the width of the containing
-	// view if you don't specify a width.
-	if (parent_view)
-	{
-		if(w == 0)
-		{
-			w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
-		}
-
-		if(h == 0)
-		{
-			h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
-		}
-	}
-
-	if (node->hasAttribute("width"))
-	{
-		node->getAttributeS32("width", w);
-	}
-	if (node->hasAttribute("height"))
-	{
-		node->getAttributeS32("height", h);
-	}
-
-	if (parent_view)
-	{
-		if (node->hasAttribute("left_delta"))
-		{
-			S32 left_delta = 0;
-			node->getAttributeS32("left_delta", left_delta);
-			x = last_x + left_delta;
-		}
-		else if (node->hasAttribute("left") && node->hasAttribute("right"))
-		{
-			// compute width based on left and right
-			S32 right = 0;
-			node->getAttributeS32("right", right);
-			if (right < 0)
-			{
-				right = parent_view->getRect().getWidth() + right;
-			}
-			w = right - x;
-		}
-		else if (node->hasAttribute("left"))
-		{
-			if (x < 0)
-			{
-				x = parent_view->getRect().getWidth() + x;
-				follows |= FOLLOWS_RIGHT;
-			}
-			else
-			{
-				follows |= FOLLOWS_LEFT;
-			}
-		}
-		else if (node->hasAttribute("width") && node->hasAttribute("right"))
-		{
-			S32 right = 0;
-			node->getAttributeS32("right", right);
-			if (right < 0)
-			{
-				right = parent_view->getRect().getWidth() + right;
-			}
-			x = right - w;
-		}
-		else
-		{
-			// left not specified, same as last
-			x = last_x;
-		}
-
-		if (node->hasAttribute("bottom_delta"))
-		{
-			S32 bottom_delta = 0;
-			node->getAttributeS32("bottom_delta", bottom_delta);
-			y = last_y + bottom_delta;
-		}
-		else if (node->hasAttribute("top"))
-		{
-			// compute height based on top
-			S32 top = 0;
-			node->getAttributeS32("top", top);
-			if (top < 0)
-			{
-				top = parent_view->getRect().getHeight() + top;
-			}
-			h = top - y;
-		}
-		else if (node->hasAttribute("bottom"))
-		{
-			if (y < 0)
-			{
-				y = parent_view->getRect().getHeight() + y;
-				follows |= FOLLOWS_TOP;
-			}
-			else
-			{
-				follows |= FOLLOWS_BOTTOM;
-			}
-		}
-		else
-		{
-			// if bottom not specified, generate automatically
-			if (last_y == 0)
-			{
-				// treat first child as "bottom"
-				y = parent_view->getRect().getHeight() - (h + VPAD);
-				follows |= FOLLOWS_TOP;
-			}
-			else
-			{
-				// treat subsequent children as "bottom_delta"
-				y = last_y - (h + VPAD);
-			}
-		}
-	}
-	else
-	{
-		x = llmax(x, 0);
-		y = llmax(y, 0);
-		follows = FOLLOWS_LEFT | FOLLOWS_TOP;
-	}
-	rect.setOriginAndSize(x, y, w, h);
-
-	return follows;
-}
-
-void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
+void LLView::initFromParams(const LLView::Params& params)
 {
-	// create rect first, as this will supply initial follows flags
-	LLRect view_rect;
-	U32 follows_flags = createRect(node, view_rect, parent, getRequiredRect());
-	// call reshape in case there are any child elements that need to be layed out
-	reshape(view_rect.getWidth(), view_rect.getHeight());
-	setRect(view_rect);
-	setFollows(follows_flags);
-
-	parseFollowsFlags(node);
+	LLRect required_rect = getRequiredRect();
 
-	if (node->hasAttribute("control_name"))
-	{
-		std::string control_name;
-		node->getAttributeString("control_name", control_name);
-		setControlName(control_name, NULL);
-	}
+	S32 width = llmax(getRect().getWidth(), required_rect.getWidth());
+	S32 height = llmax(getRect().getHeight(), required_rect.getHeight());
 
-	if (node->hasAttribute("tool_tip"))
-	{
-		std::string tool_tip_msg;
-		node->getAttributeString("tool_tip", tool_tip_msg);
-		setToolTip(tool_tip_msg);
-	}
+	reshape(width, height);
 
-	if (node->hasAttribute("enabled"))
-	{
-		BOOL enabled;
-		node->getAttributeBOOL("enabled", enabled);
-		setEnabled(enabled);
-	}
-	
-	if (node->hasAttribute("visible"))
-	{
-		BOOL visible;
-		node->getAttributeBOOL("visible", visible);
-		setVisible(visible);
-	}
+	// call virtual methods with most recent data
+	// use getters because these values might not come through parameter block
+	setEnabled(getEnabled());
+	setVisible(getVisible());
 
-	if (node->hasAttribute("hover_cursor"))
+	if (!params.name().empty())
 	{
-		std::string cursor_string;
-		node->getAttributeString("hover_cursor", cursor_string);
-		mHoverCursor = getCursorFromString(cursor_string);
+		setName(params.name());
 	}
-	
-	node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect);
-	node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
 
-	node->getAttributeS32("default_tab_group", mDefaultTabGroup);
-	
-	reshape(view_rect.getWidth(), view_rect.getHeight());
+	mLayout = params.layout();
 }
 
-void LLView::parseFollowsFlags(LLXMLNodePtr node)
+void LLView::parseFollowsFlags(const LLView::Params& params)
 {
-	if (node->hasAttribute("follows"))
+	if (params.follows.string.isProvided())
 	{
-		setFollowsNone();
+		setFollows(FOLLOWS_NONE);
 
-		std::string follows;
-		node->getAttributeString("follows", follows);
+		std::string follows = params.follows.string;
 
 		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
 		boost::char_separator<char> sep("|");
@@ -2685,45 +2378,13 @@ void LLView::parseFollowsFlags(LLXMLNodePtr node)
 			++token_iter;
 		}
 	}
-}
-
-// static
-LLFontGL* LLView::selectFont(LLXMLNodePtr node)
-{
-	std::string font_name, font_size, font_style;
-	U8 style = 0;
-	
-	if (node->hasAttribute("font"))
-	{
-		node->getAttributeString("font", font_name);
-	}
-	
-	if (node->hasAttribute("font_size"))
-	{
-		node->getAttributeString("font_size", font_size);
-	}
-
-	if (node->hasAttribute("font_style"))
-	{
-		node->getAttributeString("font_style", font_style);
-		style = LLFontGL::getStyleFromString(font_style);
-	}
-
-	if (node->hasAttribute("font-style"))
+	else if (params.follows.flags.isProvided())
 	{
-		node->getAttributeString("font-style", font_style);
-		style = LLFontGL::getStyleFromString(font_style);
+		setFollows(params.follows.flags);
 	}
-
-	if (font_name.empty())
-		return NULL;
-
-	LLFontDescriptor desc(font_name, font_size, style);
-	LLFontGL* gl_font = LLFontGL::getFont(desc);
-
-	return gl_font;
 }
 
+
 // static
 LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
 {
@@ -2738,175 +2399,216 @@ LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
 	return gl_hfont_align;
 }
 
-// static
-LLFontGL::VAlign LLView::selectFontVAlign(LLXMLNodePtr node)
+//static
+void LLView::setupParams(LLView::Params& p, LLView* parent)
 {
-	LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
+	const S32 VPAD = 4;
+	const S32 MIN_WIDGET_HEIGHT = 10;
+	
+	p.serializable(true);
+
+	// *NOTE: Do not inherit layout from parent until we re-export
+	// all nodes and make topleft the default. JC
+	//if (p.layout().empty() && parent) 
+	//	p.layout = parent->getLayout();
 
-	if (node->hasAttribute("valign"))
+	if (parent)
 	{
-		std::string vert_align_name;
-		node->getAttributeString("valign", vert_align_name);
-		gl_vfont_align = LLFontGL::vAlignFromName(vert_align_name);
-	}
-	return gl_vfont_align;
-}
+		LLRect parent_rect = parent->getLocalRect();
+		// overwrite uninitialized rect params, using context
+		LLRect last_rect = parent->getLocalRect();
 
-// static
-LLFontGL::StyleFlags LLView::selectFontStyle(LLXMLNodePtr node)
-{
-	LLFontGL::StyleFlags gl_font_style = LLFontGL::NORMAL;
+		bool layout_topleft = (p.layout() == "topleft");
+		if (layout_topleft)
+		{
+			//invert top to bottom
+			if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
+			if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom;
+		}
 
-	if (node->hasAttribute("style"))
-	{
-		std::string style_flags_name;
-		node->getAttributeString("style", style_flags_name);
+		// convert negative or centered coordinates to parent relative values
+		// Note: some of this logic matches the logic in TypedParam<LLRect>::getValueFromBlock()
 
-		if (style_flags_name == "normal")
+		if (p.center_horiz)
 		{
-			gl_font_style = LLFontGL::NORMAL;
+			if (p.rect.left.isProvided() && p.rect.right.isProvided())
+			{
+				S32 width = p.rect.right - p.rect.left;
+				width = llmax(width, 0);
+				S32 offset = parent_rect.getWidth()/2 - width/2;
+				p.rect.left = p.rect.left + offset;
+				p.rect.right = p.rect.right + offset;
+			}
+			else
+			{
+				p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2;
+			}
 		}
-		else if (style_flags_name == "bold")
+		else
 		{
-			gl_font_style = LLFontGL::BOLD;
+			if (p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth();
+			if (p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth();
 		}
-		else if (style_flags_name == "italic")
+		if (p.center_vert)
 		{
-			gl_font_style = LLFontGL::ITALIC;
+			if (p.rect.bottom.isProvided() && p.rect.top.isProvided())
+			{
+				S32 height = p.rect.top - p.rect.bottom;
+				height = llmax(height, 0);
+				S32 offset = parent_rect.getHeight()/2 - height/2;
+				p.rect.bottom = p.rect.bottom + offset;
+				p.rect.top = p.rect.top + offset;
+			}
+			else
+			{
+				p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2;
+			}
 		}
-		else if (style_flags_name == "underline")
+		else
 		{
-			gl_font_style = LLFontGL::UNDERLINE;
+			if (p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight();
+			if (p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight();
 		}
-		//else leave left
-	}
-	return gl_font_style;
-}
-
-bool LLView::setControlValue(const LLSD& value)
-{
-	std::string ctrlname = getControlName();
-	if (!ctrlname.empty())
-	{
-		LLUI::sConfigGroup->setValue(ctrlname, value);
-		return true;
-	}
-	return false;
-}
 
-//virtual
-void LLView::setControlName(const std::string& control_name, LLView *context)
-{
-	if (context == NULL)
-	{
-		context = this;
-	}
 
-	if (!mControlName.empty())
-	{
-		llwarns << "setControlName called twice on same control!" << llendl;
-		mControlConnection.disconnect(); // disconnect current signal
-		mControlName.clear();
-	}
-	
-	// Register new listener
-	if (!control_name.empty())
-	{
-		LLControlVariable *control = context->findControl(control_name);
-		if (control)
+		// DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels
+		if (!p.rect.height.isProvided() && !p.rect.top.isProvided())
 		{
-			mControlName = control_name;
-			mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _1, getHandle(), std::string("value")));
-			setValue(control->getValue());
+			p.rect.height = MIN_WIDGET_HEIGHT;
 		}
-	}
-}
 
-// static
-bool LLView::controlListener(const LLSD& newvalue, LLHandle<LLView> handle, std::string type)
-{
-	LLView* view = handle.get();
-	if (view)
-	{
-		if (type == "value")
+		last_rect.translate(0, last_rect.getHeight());
+
+		LLView::child_list_t::const_iterator itor = parent->getChildList()->begin();
+		for (;itor != parent->getChildList()->end(); ++itor)
 		{
-			view->setValue(newvalue);
-			return true;
+			LLView *last_view = (*itor);
+			if (last_view->getSaveToXML())
+			{
+				last_rect = last_view->getRect();
+				break;
+			}
 		}
-		else if (type == "enabled")
+
+		if (layout_topleft)
 		{
-			view->setEnabled(newvalue.asBoolean());
-			return true;
+			S32 left_delta = 0;
+			p.bottom_delta.setIfNotProvided(0, false);
+
+			// Invert the sense of bottom_delta for topleft layout
+			if (p.bottom_delta.isProvided())
+			{
+				p.bottom_delta = -p.bottom_delta;
+			}
+			else if (p.top_delta.isProvided()) 
+			{
+				p.bottom_delta = -(p.rect.height + p.top_delta);
+			}
+			else if (!p.left_delta.isProvided() && !p.right_delta.isProvided() && !p.top_delta.isProvided())
+			{
+				// set default position is just below last rect
+				p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false);
+			}
+	
+			// *TODO: Add left_pad for padding off the last widget's right edge
+			// if (p.left_pad.isProvided())
+			//{
+			//	left_delta = p.left_pad + last_rect.getWidth();
+			//}
+			//else if ...
+			if (p.left_delta.isProvided())
+			{
+				left_delta = p.left_delta;
+			}
+			else if (p.right_delta.isProvided())
+			{
+				left_delta = -(p.right_delta + p.rect.width);
+			}
+			
+			last_rect.translate(left_delta, p.bottom_delta);				
 		}
-		else if (type == "visible")
-		{
-			view->setVisible(newvalue.asBoolean());
-			return true;
+		else
+		{	
+			// set default position is just below last rect
+			p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false);
+			p.left_delta.setIfNotProvided(0, false);
+			last_rect.translate(p.left_delta, p.bottom_delta);
 		}
-	}
-	return false;
-}
 
-void LLView::addBoolControl(const std::string& name, bool initial_value)
-{
-	mFloaterControls[name] = new LLControlVariable(name, TYPE_BOOLEAN, initial_value, std::string("Internal floater control"));
-}
+		// this handles case where *both* x and x_delta are provided
+		// ignore x in favor of default x + x_delta
+		if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false);
+		if (p.left_delta.isProvided()) p.rect.left.set(0, false);
 
-LLControlVariable *LLView::getControl(const std::string& name)
-{
-	control_map_t::iterator itor = mFloaterControls.find(name);
-	if (itor != mFloaterControls.end())
-	{
-		return itor->second;
+		// selectively apply rectangle defaults, making sure that
+		// params are not flagged as having been "provided"
+		// as rect params are overconstrained and rely on provided flags
+		p.rect.left.setIfNotProvided(last_rect.mLeft, false);
+		p.rect.bottom.setIfNotProvided(last_rect.mBottom, false);
+		p.rect.top.setIfNotProvided(last_rect.mTop, false);
+		p.rect.right.setIfNotProvided(last_rect.mRight, false);
+		p.rect.width.setIfNotProvided(last_rect.getWidth(), false);
+		p.rect.height.setIfNotProvided(last_rect.getHeight(), false);
 	}
-	return NULL;
-}
-
-//virtual 
-void	LLView::setValue(const LLSD& value)
-{
 }
 
-//virtual 
-LLSD	LLView::getValue() const 
+static S32 invert_vertical(S32 y, LLView* parent)
 {
-	return LLSD();
+	if (y < 0)
+	{
+		// already based on top-left, just invert
+		return -y;
+	}
+	else if (parent)
+	{
+		// use parent to flip coordinate
+		S32 parent_height = parent->getRect().getHeight();
+		return parent_height - y;
+	}
+	else
+	{
+		llwarns << "Attempting to convert layout to top-left with no parent" << llendl;
+		return y;
+	}
 }
 
-LLView* LLView::createWidget(LLXMLNodePtr xml_node) const
+//static
+void LLView::setupParamsForExport(Params& p, LLView* parent)
 {
-	// forward requests to ui ctrl factory
-	return LLUICtrlFactory::getInstance()->createCtrlWidget(NULL, xml_node);
-}
-
-//
-// LLWidgetClassRegistry
-//
-
-LLWidgetClassRegistry::LLWidgetClassRegistry()
-{ 
-}
+	// Don't convert if already top-left based
+	if (p.layout() == "topleft") 
+	{
+		return;
+	}
 
-void LLWidgetClassRegistry::registerCtrl(const std::string& tag, LLWidgetClassRegistry::factory_func_t function)
-{ 
-	std::string lower_case_tag = tag;
-	LLStringUtil::toLower(lower_case_tag);
-	
-	mCreatorFunctions[lower_case_tag] = function;
+	if (p.rect.top.isProvided())
+	{
+		p.rect.top = invert_vertical(p.rect.top, parent);
+	}
+	if (p.top_delta.isProvided())
+	{
+		p.top_delta = -p.top_delta;
+	}
+	if (p.rect.bottom.isProvided())
+	{
+		p.rect.bottom = invert_vertical(p.rect.bottom, parent);
+	}
+	if (p.bottom_delta.isProvided())
+	{
+		p.bottom_delta = -p.bottom_delta;
+	}
+	p.layout = "topleft";
 }
 
-BOOL LLWidgetClassRegistry::isTagRegistered(const std::string &tag)
+LLView::tree_iterator_t LLView::beginTree() 
 { 
-	return mCreatorFunctions.find(tag) != mCreatorFunctions.end();
+	return tree_iterator_t(this, 
+							boost::bind(boost::mem_fn(&LLView::beginChild), _1), 
+							boost::bind(boost::mem_fn(&LLView::endChild), _1)); 
 }
 
-LLWidgetClassRegistry::factory_func_t LLWidgetClassRegistry::getCreatorFunc(const std::string& ctrl_type)
+LLView::tree_iterator_t LLView::endTree() 
 { 
-	factory_map_t::const_iterator found_it = mCreatorFunctions.find(ctrl_type);
-	if (found_it == mCreatorFunctions.end())
-	{
-		return NULL;
-	}
-	return found_it->second;
+	// an empty iterator is an "end" iterator
+	return tree_iterator_t();
 }
-
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index e0e0f6ba47..69ae7dd993 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -47,12 +47,15 @@
 #include "llrect.h"
 #include "llui.h"
 #include "lluistring.h"
-#include "lluixmltags.h"
 #include "llviewquery.h"
 #include "llxmlnode.h"
 #include "stdenums.h"
 #include "lluistring.h"
 #include "llcursortypes.h"
+#include "lluictrlfactory.h"
+#include "lltreeiterators.h"
+
+#include <list>
 
 const U32	FOLLOWS_NONE	= 0x00;
 const U32	FOLLOWS_LEFT	= 0x01;
@@ -75,9 +78,6 @@ virtual BOOL isPanel();
 		LLPanel
 virtual void setRect(const LLRect &rect);
 		LLLineEditor
-virtual void	addCtrl( LLUICtrl* ctrl, S32 tab_group);
-virtual void	addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group);
-virtual void	removeCtrl( LLUICtrl* ctrl);
 		LLPanel
 virtual BOOL canFocusChildren() const		{ return TRUE; }
 		LLFolderView
@@ -103,7 +103,7 @@ virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 		LLUICtrl, et. al.
 virtual void	translate( S32 x, S32 y );
 		LLMenuGL		
-virtual void	userSetShape(const LLRect& new_rect);
+virtual void	setShape(const LLRect& new_rect, bool by_user);
 		LLFloater, LLScrollLIstVtrl
 virtual LLView*	findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0);
 virtual LLView*	findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0);
@@ -121,10 +121,6 @@ virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,EDragAndDropTy
 virtual void	draw();
 		*
 
-		*
-virtual LLXMLNodePtr getXML(bool save_children = true) const;
-		*
-virtual void initFromXML(LLXMLNodePtr node, LLView* parent);
 		*
 virtual void onFocusLost() {}
 		LLUICtrl, LLScrollListCtrl, LLMenuGL, LLLineEditor, LLComboBox
@@ -132,14 +128,8 @@ virtual void onFocusReceived() {}
 		LLUICtrl, LLTextEditor, LLScrollListVtrl, LLMenuGL, LLLineEditor
 virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
 		LLTabContainer, LLPanel, LLMenuGL
-virtual void	setControlName(const std::string& control, LLView *context);
-		LLSliderCtrl, LLCheckBoxCtrl
-virtual std::string getControlName() const { return mControlName; }
-		LLSliderCtrl, LLCheckBoxCtrl
 virtual bool	handleEvent(LLPointer<LLEvent> event, const LLSD& userdata);
 		LLMenuItem
-virtual void	setValue(const LLSD& value);
-		*
 
 protected:
 virtual BOOL	handleKeyHere(KEY key, MASK mask);
@@ -148,67 +138,65 @@ virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 		*
 */
 
-class LLUICtrlFactory;
-
-// maps xml strings to widget classes
-class LLWidgetClassRegistry : public LLSingleton<LLWidgetClassRegistry>
+class LLView : public LLMouseHandler, public LLMortician
 {
-	friend class LLSingleton<LLWidgetClassRegistry>;
 public:
-	typedef LLView* (*factory_func_t)(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
-	typedef std::map<std::string, factory_func_t> factory_map_t;
-
-	void registerCtrl(const std::string& xml_tag, factory_func_t function);
-	BOOL isTagRegistered(const std::string& xml_tag);
-	factory_func_t getCreatorFunc(const std::string& xml_tag);
-
-	// get (first) xml tag for a given class
-	template <class T> std::string getTag()
+	struct Follows : public LLInitParam::Choice<Follows>
 	{
-		factory_map_t::iterator it;
-		for(it = mCreatorFunctions.begin(); it != mCreatorFunctions.end(); ++it)
-		{
-			if (it->second == T::fromXML)
-			{
-				return it->first;
-			}
-		}
-
-		return "";
-	}
-
-private:
-	LLWidgetClassRegistry();
-	virtual ~LLWidgetClassRegistry() {};
-
-	typedef std::set<std::string> ctrl_name_set_t;
-	ctrl_name_set_t mUICtrlNames;
+		Option<std::string>	string;
+		Option<U32>			flags;
 
-	// map of xml tags to widget creator functions
-	factory_map_t mCreatorFunctions;
-};
+        Follows()
+		:   string(""),
+			flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP)
+        {}
+	};
 
-template<class T>
-class LLRegisterWidget
-{
-public:
-	LLRegisterWidget(const std::string& tag) 
+	struct Params : public LLInitParam::Block<Params>
 	{
-		LLWidgetClassRegistry* registry = LLWidgetClassRegistry::getInstance();
-		if (registry->isTagRegistered(tag))
-		{
-			//error!
-			llerrs << "Widget named " << tag << " already registered!" << llendl;
-		}
-		else
-		{
-			registry->registerCtrl(tag, T::fromXML);
-		}
-	}
-};
+		Mandatory<std::string>	name;
+
+		Optional<bool>			enabled,
+								visible;
+		Optional<bool>			mouse_opaque;
+		Optional<bool>			use_bounding_rect;
+		Optional<S32>			tab_group,
+								default_tab_group;
+		Optional<std::string>	tool_tip;
+
+		Optional<S32>			sound_flags;
+		Optional<bool>			serializable;
+		Optional<Follows>		follows;
+		Optional<std::string>	hover_cursor;
+		
+		// font params
+		Optional<const LLFontGL*>	font;
+		Optional<LLFontGL::HAlign>	font_halign;
+		Optional<LLFontGL::VAlign>	font_valign;
+
+		Optional<std::string>	layout;
+		Optional<LLRect>		rect;
+		Optional<S32>			top_delta,
+								bottom_delta,
+								right_delta,
+								left_delta;
+								
+		Optional<bool>			center_horiz,
+								center_vert;
+
+		// these are nested attributes for LLLayoutPanel
+		//FIXME: get parent context involved in parsing traversal
+		Deprecated				user_resize,
+								auto_resize,
+								needs_translate;
+
+		Params();
+	};
+	void initFromParams(const LLView::Params&);
 
-class LLView : public LLMouseHandler, public LLMortician
-{
+protected:
+	LLView(const LLView::Params&);
+	friend class LLUICtrlFactory;
 
 public:
 #if LL_DEBUG
@@ -253,10 +241,6 @@ public:
 	typedef child_tab_order_t::reverse_iterator			child_tab_order_reverse_iter_t;
 	typedef child_tab_order_t::const_reverse_iterator	child_tab_order_const_reverse_iter_t;
 
-	LLView();
-	LLView(const std::string& name, BOOL mouse_opaque);
-	LLView(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows=FOLLOWS_NONE);
-
 	virtual ~LLView();
 
 	// Hack to support LLFocusMgr (from LLMouseHandler)
@@ -300,15 +284,21 @@ public:
 	void		sendChildToBack(LLView* child);
 	void		moveChildToFrontOfTabGroup(LLUICtrl* child);
 	void		moveChildToBackOfTabGroup(LLUICtrl* child);
+	
+	void		addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node = NULL);
+	
+	virtual bool addChild(LLView* view, S32 tab_group = 0);
+
+	// implemented in terms of addChild()
+	bool		addChildInBack(LLView* view,  S32 tab_group = 0);
 
-	void		addChild(LLView* view, S32 tab_group = 0);
-	void		addChildAtEnd(LLView* view,  S32 tab_group = 0);
 	// remove the specified child from the view, and set it's parent to NULL.
-	void		removeChild(LLView* view, BOOL deleteIt = FALSE);
+	virtual void	removeChild(LLView* view);
+
+	// helper function for lluictrlfactory.h create<> template
+	void setParent(LLView* parent) { if (parent) parent->addChild(this); }
 
-	virtual void	addCtrl( LLUICtrl* ctrl, S32 tab_group);
-	virtual void	addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group);
-	virtual void	removeCtrl( LLUICtrl* ctrl);
+	virtual BOOL	postBuild() { return TRUE; }
 
 	child_tab_order_t getCtrlOrder() const		{ return mCtrlOrder; }
 	ctrl_list_t getCtrlList() const;
@@ -316,6 +306,7 @@ public:
 	
 	void setDefaultTabGroup(S32 d)				{ mDefaultTabGroup = d; }
 	S32 getDefaultTabGroup() const				{ return mDefaultTabGroup; }
+	S32 getLastTabGroup()						{ return mLastTabGroup; }
 
 	BOOL		isInVisibleChain() const;
 	BOOL		isInEnabledChain() const;
@@ -347,7 +338,7 @@ public:
 	virtual void	onVisibilityChange ( BOOL curVisibilityIn );
 
 	void			pushVisible(BOOL visible)	{ mLastVisible = mVisible; setVisible(visible); }
-	void			popVisible()				{ setVisible(mLastVisible); mLastVisible = TRUE; }
+	void			popVisible()				{ setVisible(mLastVisible); }
 	
 	LLHandle<LLView>	getHandle()				{ mHandle.bind(this); return mHandle; }
 
@@ -361,11 +352,14 @@ public:
 	const LLRect&	getRect() const				{ return mRect; }
 	const LLRect&	getBoundingRect() const		{ return mBoundingRect; }
 	LLRect	getLocalBoundingRect() const;
-	LLRect	getScreenRect() const;
+	LLRect	calcScreenRect() const;
+	LLRect	calcScreenBoundingRect() const;
 	LLRect	getLocalRect() const;
 	virtual LLRect getSnapRect() const;
 	LLRect getLocalSnapRect() const;
 
+	std::string getLayout() { return mLayout; }
+
 	// Override and return required size for this object. 0 for width/height means don't care.
 	virtual LLRect getRequiredRect();
 	void updateBoundingRect();
@@ -373,12 +367,17 @@ public:
 	LLView*		getRootView();
 	LLView*		getParent() const				{ return mParentView; }
 	LLView*		getFirstChild() const			{ return (mChildList.empty()) ? NULL : *(mChildList.begin()); }
+	LLView*		findPrevSibling(LLView* child);
+	LLView*		findNextSibling(LLView* child);
 	S32			getChildCount()	const			{ return (S32)mChildList.size(); }
 	template<class _Pr3> void sortChildren(_Pr3 _Pred) { mChildList.sort(_Pred); }
 	BOOL		hasAncestor(const LLView* parentp) const;
 	BOOL		hasChild(const std::string& childname, BOOL recurse = FALSE) const;
 	BOOL 		childHasKeyboardFocus( const std::string& childname ) const;
-
+	
+	typedef LLTreeDFSIter<LLView, child_list_const_iter_t> tree_iterator_t;
+	tree_iterator_t beginTree();
+	tree_iterator_t endTree();
 
 	//
 	// UTILITIES
@@ -391,13 +390,11 @@ public:
 	BOOL			translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside );
 	void			centerWithin(const LLRect& bounds);
 
-	virtual void	userSetShape(const LLRect& new_rect);
+	void	setShape(const LLRect& new_rect, bool by_user = false);
 	virtual LLView*	findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0);
 	virtual LLView*	findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0);
-
 	virtual BOOL	canSnapTo(const LLView* other_view);
-
-	virtual void	snappedTo(const LLView* snap_view);
+	virtual void	setSnappedTo(const LLView* snap_view);
 
 	virtual BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
 	virtual BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
@@ -407,15 +404,11 @@ public:
 									  EAcceptance* accept,
 									  std::string& tooltip_msg);
 
-	std::string getShowNamesToolTip();
+	virtual std::string getShowNamesToolTip();
 
 	virtual void	draw();
 
-	virtual LLXMLNodePtr getXML(bool save_children = true) const;
-	//FIXME: make LLView non-instantiable from XML
-	static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
-	virtual void initFromXML(LLXMLNodePtr node, LLView* parent);
-	void parseFollowsFlags(LLXMLNodePtr node);
+	void parseFollowsFlags(const LLView::Params& params);
 
 	// Some widgets, like close box buttons, don't need to be saved
 	BOOL getSaveToXML() const { return mSaveToXML; }
@@ -440,25 +433,16 @@ public:
 	void screenRectToLocal( const LLRect& screen, LLRect* local ) const;
 	void localRectToScreen( const LLRect& local, LLRect* screen ) const;
 	
-	// Listener dispatching functions (Dispatcher deletes pointers to listeners on deregistration or destruction)
-	LLSimpleListener* getListenerByName(const std::string& callback_name);
-	void registerEventListener(std::string name, LLSimpleListener* function);
-	void deregisterEventListener(std::string name);
-	std::string findEventListener(LLSimpleListener *listener) const;
-	void addListenerToControl(LLEventDispatcher *observer, const std::string& name, LLSD filter, LLSD userdata);
-
-	void addBoolControl(const std::string& name, bool initial_value);
-	LLControlVariable *getControl(const std::string& name);
 	LLControlVariable *findControl(const std::string& name);
 
-	bool setControlValue(const LLSD& value);
-	virtual void	setControlName(const std::string& control, LLView *context);
-	virtual std::string getControlName() const { return mControlName; }
+    // Moved setValue(), getValue(), setControlValue(), setControlName(),
+    // controlListener() to LLUICtrl because an LLView is NOT assumed to
+    // contain a value. If that's what you want, use LLUICtrl instead.
 //	virtual bool	handleEvent(LLPointer<LLEvent> event, const LLSD& userdata);
-	virtual void	setValue(const LLSD& value);
-	virtual LLSD	getValue() const;
 
 	const child_list_t*	getChildList() const { return &mChildList; }
+	const child_list_const_iter_t	beginChild()  { return mChildList.begin(); }
+	const child_list_const_iter_t	endChild()  { return mChildList.end(); }
 
 	// LLMouseHandler functions
 	//  Default behavior is to pass events to children
@@ -479,26 +463,20 @@ public:
 	/*virtual*/ void	screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
 	/*virtual*/ void	localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
 
-	template <class T> T* getChild(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const
+	// view-specific handlers 
+	virtual void	onMouseEnter(S32 x, S32 y, MASK mask);
+	virtual void	onMouseLeave(S32 x, S32 y, MASK mask);
+
+
+	template <class T> T* findChild(const std::string& name, BOOL recurse = TRUE) const
 	{
 		LLView* child = getChildView(name, recurse, FALSE);
 		T* result = dynamic_cast<T*>(child);
-		if (!result)
-		{
-			// did we find *something* with that name?
-			if (child)
-			{
-				llwarns << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T).name() << llendl;
-			}
-			if (create_if_missing)
-			{
-				// create dummy widget instance here
-				result = createDummyWidget<T>(name);
-			}
-		}
 		return result;
 	}
 
+	template <class T> T* getChild(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
+
 	template <class T> T& getChildRef(const std::string& name, BOOL recurse = TRUE) const
 	{
 		return *getChild<T>(name, recurse, TRUE);
@@ -506,39 +484,6 @@ public:
 
 	virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const;
 
-	template <class T> T* createDummyWidget(const std::string& name) const
-	{
-		T* widget = getDummyWidget<T>(name);
-		if (!widget)
-		{
-			// get xml tag name corresponding to requested widget type (e.g. "button")
-			std::string xml_tag = LLWidgetClassRegistry::getInstance()->getTag<T>();
-			if (xml_tag.empty())
-			{
-				llwarns << "No xml tag registered for this class " << llendl;
-				return NULL;
-			}
-			// create dummy xml node (<button name="foo"/>)
-			LLXMLNodePtr new_node_ptr = new LLXMLNode(xml_tag.c_str(), FALSE);
-			new_node_ptr->createChild("name", TRUE)->setStringValue(name);
-			
-			widget = dynamic_cast<T*>(createWidget(new_node_ptr));
-			if (widget)
-			{
-				// need non-const to update private dummy widget cache
-				llwarns << "Making dummy " << xml_tag << " named " << name << " in " << getName() << llendl;
-				mDummyWidgets.insert(std::make_pair(name, widget));
-			}
-			else
-			{
-				// dynamic cast will fail if T::fromXML only registered for base class
-				llwarns << "Failed to create dummy widget of requested type " << llendl;
-				return NULL;
-			}
-		}
-		return widget;
-	}
-
 	template <class T> T* getDummyWidget(const std::string& name) const
 	{
 		dummy_widget_map_t::const_iterator found_it = mDummyWidgets.find(name);
@@ -549,29 +494,11 @@ public:
 		return dynamic_cast<T*>(found_it->second);
 	}
 
-	LLView* createWidget(LLXMLNodePtr xml_node) const;
-
-
+	//////////////////////////////////////////////
 	// statics
-	static U32 createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect = LLRect());
-	
-	static LLFontGL* selectFont(LLXMLNodePtr node);
+	//////////////////////////////////////////////
 	static LLFontGL::HAlign selectFontHAlign(LLXMLNodePtr node);
-	static LLFontGL::VAlign selectFontVAlign(LLXMLNodePtr node);
-	static LLFontGL::StyleFlags selectFontStyle(LLXMLNodePtr node);
-
-	
-	// Only saves color if different from default setting.
-	static void addColorXML(LLXMLNodePtr node, const LLColor4& color,
-							const char* xml_name, const char* control_name);
-	// Escapes " (quot) ' (apos) & (amp) < (lt) > (gt)
-	//static std::string escapeXML(const std::string& xml);
-	static LLWString escapeXML(const LLWString& xml);
 	
-	//same as above, but wraps multiple lines in quotes and prepends
-	//indent as leading white space on each line
-	static std::string escapeXML(const std::string& xml, std::string& indent);
-
 	// focuses the item in the list after the currently-focused item, wrapping if necessary
 	static	BOOL focusNext(LLView::child_list_t & result);
 	// focuses the item in the list before the currently-focused item, wrapping if necessary
@@ -582,14 +509,24 @@ public:
 	// return query for iterating over focus roots in tab order
 	static const LLCtrlQuery & getFocusRootsQuery();
 
-	static BOOL deleteViewByHandle(LLHandle<LLView> handle);
+	static void deleteViewByHandle(LLHandle<LLView> handle);
 	static LLWindow*	getWindow(void) { return LLUI::sWindow; }
 
+	// Set up params after XML load before calling new(),
+	// usually to adjust layout.
+	static void setupParams(Params& p, LLView* parent);
+
+	// For re-export of floaters and panels, convert the coordinate system
+	// to be top-left based.
+	static void setupParamsForExport(Params& p, LLView* parent);
 	
 protected:
+	//virtual BOOL	addChildFromParam(const LLInitParam::BaseBlock& params) { return TRUE; }
 	virtual BOOL	handleKeyHere(KEY key, MASK mask);
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 
+	virtual void	handleReshape(const LLRect& rect, bool by_user);
+
 	void			drawDebugRect();
 	void			drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);
 
@@ -612,11 +549,8 @@ protected:
 	LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask);
 	LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask);
 
-	static bool controlListener(const LLSD& newvalue, LLHandle<LLView> handle, std::string type);
-
-	typedef std::map<std::string, LLControlVariable*> control_map_t;
-	control_map_t mFloaterControls;
-
+	ECursorType mHoverCursor;
+	
 private:
 	LLView*		mParentView;
 	child_list_t mChildList;
@@ -625,11 +559,13 @@ private:
 	// location in pixels, relative to surrounding structure, bottom,left=0,0
 	LLRect		mRect;
 	LLRect		mBoundingRect;
+	std::string mLayout;
 	
 	U32			mReshapeFlags;
 
 	child_tab_order_t mCtrlOrder;
 	S32			mDefaultTabGroup;
+	S32			mLastTabGroup;
 
 	BOOL		mEnabled;		// Enabled means "accepts input that has an effect on the state of the application."
 								// A disabled view, for example, may still have a scrollbar that responds to mouse events.
@@ -651,18 +587,9 @@ private:
 
 	static LLWindow* sWindow;	// All root views must know about their window.
 
-	typedef std::map<std::string, LLPointer<LLSimpleListener> > dispatch_list_t;
-	dispatch_list_t mDispatchList;
-
-	std::string		mControlName;
-
 	typedef std::map<std::string, LLView*> dummy_widget_map_t;
 	mutable dummy_widget_map_t mDummyWidgets;
 
-	boost::signals::connection mControlConnection;
-
-	ECursorType mHoverCursor;
-	
 public:
 	static BOOL	sDebugRects;	// Draw debug rects behind everything.
 	static BOOL sDebugKeys;
@@ -670,8 +597,12 @@ public:
 	static BOOL sDebugMouseHandling;
 	static std::string sMouseHandlerMessage;
 	static S32	sSelectID;
-	static BOOL sEditingUI;
-	static LLView* sEditingUIView;
+//	static BOOL sEditingUI;
+//	static LLView* sEditingUIView;
+	static std::set<LLView*> sPreviewHighlightedElements;	// DEV-16869
+	static BOOL sHighlightingDiffs;							// DEV-16869
+	static LLView* sPreviewClickedElement;					// DEV-16869
+	static BOOL sDrawPreviewHighlights;
 	static S32 sLastLeftXML;
 	static S32 sLastBottomXML;
 	static BOOL sForceReshape;
@@ -688,5 +619,39 @@ private:
 	LLView::child_tab_order_t mTabOrder;
 };
 
+template <class T> T* LLView::getChild(const std::string& name, BOOL recurse, BOOL create_if_missing) const
+{
+	LLView* child = getChildView(name, recurse, FALSE);
+	T* result = dynamic_cast<T*>(child);
+	if (!result)
+	{
+		// did we find *something* with that name?
+		if (child)
+		{
+			llwarns << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T*).name() << llendl;
+		}
+		if (create_if_missing)
+		{
+			result = getDummyWidget<T>(name);
+			if (!result)
+			{
+				result = LLUICtrlFactory::createDummyWidget<T>(name);
+
+				if (result)
+				{
+					llwarns << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << llendl;
+				}
+				else
+				{
+					llwarns << "Failed to create dummy " << typeid(T).name() << llendl;
+					return NULL;
+				}
+
+				mDummyWidgets[name] = result;
+			}
+		}
+	}
+	return result;
+}
 
 #endif //LL_LLVIEW_H
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index d4a9e9d1bf..540a9f7513 100644
--- a/indra/llui/llviewborder.cpp
+++ b/indra/llui/llviewborder.cpp
@@ -33,25 +33,52 @@
 #include "llviewborder.h"
 #include "llrender.h"
 #include "llfocusmgr.h"
+#include "lluictrlfactory.h"
 
 static LLRegisterWidget<LLViewBorder> r("view_border");
 
-LLViewBorder::LLViewBorder( const std::string& name, const LLRect& rect, EBevel bevel, EStyle style, S32 width )
-	:
-	LLView( name, rect, FALSE ),
-	mBevel( bevel ),
-	mStyle( style ),
-	mHighlightLight( LLUI::sColorsGroup->getColor( "DefaultHighlightLight" ) ),
-	mHighlightDark(	LLUI::sColorsGroup->getColor( "DefaultHighlightDark" ) ),
-	mShadowLight( LLUI::sColorsGroup->getColor( "DefaultShadowLight" ) ),
-	mShadowDark( LLUI::sColorsGroup->getColor( "DefaultShadowDark" ) ),
-	mBorderWidth( width ),
-	mTexture( NULL ),
-	mHasKeyboardFocus( FALSE )
+void LLViewBorder::BevelValues::declareValues()
+{
+	declare("in", LLViewBorder::BEVEL_IN);
+	declare("out", LLViewBorder::BEVEL_OUT);
+	declare("bright", LLViewBorder::BEVEL_BRIGHT);
+	declare("none", LLViewBorder::BEVEL_NONE);
+}
+
+void LLViewBorder::StyleValues::declareValues()
+{
+	declare("line", LLViewBorder::STYLE_LINE);
+	declare("texture", LLViewBorder::STYLE_TEXTURE);
+}
+
+LLViewBorder::Params::Params()
+:	bevel_type("bevel_style", BEVEL_OUT),
+	render_style("border_style", STYLE_LINE),
+	border_thickness("border_thickness"),
+	highlight_light_color("highlight_light_color"),
+	highlight_dark_color("highlight_dark_color"),
+	shadow_light_color("shadow_light_color"),
+	shadow_dark_color("shadow_dark_color")
 {
-	setFollowsAll();
+	name = "view_border";
+	mouse_opaque = false;
+	follows.flags = FOLLOWS_ALL;
 }
 
+
+LLViewBorder::LLViewBorder(const LLViewBorder::Params& p)
+:	LLView(p),
+	mTexture( NULL ),
+	mHasKeyboardFocus( FALSE ),
+	mBorderWidth(p.border_thickness),
+	mHighlightLight(p.highlight_light_color()),
+	mHighlightDark(p.highlight_dark_color()),
+	mShadowLight(p.shadow_light_color()),
+	mShadowDark(p.shadow_dark_color()),
+	mBevel(p.bevel_type),
+	mStyle(p.render_style)
+{}
+
 void LLViewBorder::setColors( const LLColor4& shadow_dark, const LLColor4& highlight_light )
 {
 	mShadowDark = shadow_dark;
@@ -69,7 +96,7 @@ void LLViewBorder::setColorsExtended( const LLColor4& shadow_light, const LLColo
 
 void LLViewBorder::setTexture( const LLUUID &image_id )
 {
-	mTexture = LLUI::sImageProvider->getUIImageByID(image_id);
+	mTexture = LLUI::getUIImageByID(image_id);
 }
 
 
@@ -114,17 +141,17 @@ void LLViewBorder::drawOnePixelLines()
 {
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
-	LLColor4 top_color = mHighlightLight;
-	LLColor4 bottom_color = mHighlightLight;
+	LLColor4 top_color = mHighlightLight.get();
+	LLColor4 bottom_color = mHighlightLight.get();
 	switch( mBevel )
 	{
 	case BEVEL_OUT:
-		top_color		= mHighlightLight;
-		bottom_color	= mShadowDark;
+		top_color		= mHighlightLight.get();
+		bottom_color	= mShadowDark.get();
 		break;
 	case BEVEL_IN:
-		top_color		= mShadowDark;
-		bottom_color	= mHighlightLight;
+		top_color		= mShadowDark.get();
+		bottom_color	= mHighlightLight.get();
 		break;
 	case BEVEL_NONE:
 		// use defaults
@@ -163,31 +190,36 @@ void LLViewBorder::drawTwoPixelLines()
 	
 	LLColor4 focus_color = gFocusMgr.getFocusColor();
 
-	F32* top_in_color		= mShadowDark.mV;
-	F32* top_out_color		= mShadowDark.mV;
-	F32* bottom_in_color	= mShadowDark.mV;
-	F32* bottom_out_color	= mShadowDark.mV;
+	LLColor4 top_in_color;
+	LLColor4 top_out_color;
+	LLColor4 bottom_in_color;
+	LLColor4 bottom_out_color;
+
 	switch( mBevel )
 	{
 	case BEVEL_OUT:
-		top_in_color		= mHighlightLight.mV;
-		top_out_color		= mHighlightDark.mV;
-		bottom_in_color		= mShadowLight.mV;
-		bottom_out_color	= mShadowDark.mV;
+		top_in_color		= mHighlightLight.get();
+		top_out_color		= mHighlightDark.get();
+		bottom_in_color		= mShadowLight.get();
+		bottom_out_color	= mShadowDark.get();
 		break;
 	case BEVEL_IN:
-		top_in_color		= mShadowDark.mV;
-		top_out_color		= mShadowLight.mV;
-		bottom_in_color		= mHighlightDark.mV;
-		bottom_out_color	= mHighlightLight.mV;
+		top_in_color		= mShadowDark.get();
+		top_out_color		= mShadowLight.get();
+		bottom_in_color		= mHighlightDark.get();
+		bottom_out_color	= mHighlightLight.get();
 		break;
 	case BEVEL_BRIGHT:
-		top_in_color		= mHighlightLight.mV;
-		top_out_color		= mHighlightLight.mV;
-		bottom_in_color		= mHighlightLight.mV;
-		bottom_out_color	= mHighlightLight.mV;
+		top_in_color		= mHighlightLight.get();
+		top_out_color		= mHighlightLight.get();
+		bottom_in_color		= mHighlightLight.get();
+		bottom_out_color	= mHighlightLight.get();
 		break;
 	case BEVEL_NONE:
+		top_in_color		= mShadowDark.get();
+		top_out_color		= mShadowDark.get();
+		bottom_in_color		= mShadowDark.get();
+		bottom_out_color	= mShadowDark.get();
 		// use defaults
 		break;
 	default:
@@ -196,8 +228,8 @@ void LLViewBorder::drawTwoPixelLines()
 
 	if( mHasKeyboardFocus )
 	{
-		top_out_color = focus_color.mV;
-		bottom_out_color = focus_color.mV;
+		top_out_color = focus_color;
+		bottom_out_color = focus_color;
 	}
 
 	S32 left	= 0;
@@ -206,19 +238,19 @@ void LLViewBorder::drawTwoPixelLines()
 	S32 bottom	= 0;
 
 	// draw borders
-	gGL.color3fv( top_out_color );
+	gGL.color3fv( top_out_color.mV );
 	gl_line_2d(left, bottom, left, top-1);
 	gl_line_2d(left, top-1, right, top-1);
 
-	gGL.color3fv( top_in_color );
+	gGL.color3fv( top_in_color.mV );
 	gl_line_2d(left+1, bottom+1, left+1, top-2);
 	gl_line_2d(left+1, top-2, right-1, top-2);
 
-	gGL.color3fv( bottom_out_color );
+	gGL.color3fv( bottom_out_color.mV );
 	gl_line_2d(right-1, top-1, right-1, bottom);
 	gl_line_2d(left, bottom, right, bottom);
 
-	gGL.color3fv( bottom_in_color );
+	gGL.color3fv( bottom_in_color.mV );
 	gl_line_2d(right-2, top-2, right-2, bottom+1);
 	gl_line_2d(left+1, bottom+1, right-1, bottom+1);
 }
@@ -302,26 +334,3 @@ BOOL LLViewBorder::getBevelFromAttribute(LLXMLNodePtr node, LLViewBorder::EBevel
 	return FALSE;
 }
 
-
-// static
-LLView* LLViewBorder::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
-	std::string name("view_border");
-	node->getAttributeString("name", name);
-
-	LLViewBorder::EBevel bevel_style = LLViewBorder::BEVEL_IN;
-	getBevelFromAttribute(node, bevel_style);
-
-	S32 border_thickness = 1;
-	node->getAttributeS32("border_thickness", border_thickness);
-
-	LLViewBorder* border = new LLViewBorder(name, 
-									LLRect(), 
-									bevel_style,
-									LLViewBorder::STYLE_LINE,
-									border_thickness);
-
-	border->initFromXML(node, parent);
-	
-	return border;
-}
diff --git a/indra/llui/llviewborder.h b/indra/llui/llviewborder.h
index a40e6534a8..37e13fb181 100644
--- a/indra/llui/llviewborder.h
+++ b/indra/llui/llviewborder.h
@@ -35,15 +35,41 @@
 
 #include "llview.h"
 
-
 class LLViewBorder : public LLView
 {
 public:
-	enum EBevel { BEVEL_IN, BEVEL_OUT, BEVEL_BRIGHT, BEVEL_NONE };
-	enum EStyle { STYLE_LINE, STYLE_TEXTURE };
-
-	LLViewBorder( const std::string& name, const LLRect& rect, EBevel bevel = BEVEL_OUT, EStyle style = STYLE_LINE, S32 width = 1 );
-
+	typedef enum e_bevel { BEVEL_IN, BEVEL_OUT, BEVEL_BRIGHT, BEVEL_NONE } EBevel ;
+	typedef enum e_style { STYLE_LINE, STYLE_TEXTURE } EStyle;
+
+	struct BevelValues
+	:	public LLInitParam::TypeValuesHelper<LLViewBorder::EBevel, BevelValues>
+	{
+		static void declareValues();
+	};
+
+	struct StyleValues
+	:	public LLInitParam::TypeValuesHelper<LLViewBorder::EStyle, StyleValues>
+	{
+		static void declareValues();
+	};
+
+	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	{
+		Optional<EBevel, BevelValues>	bevel_type;
+		Optional<EStyle, StyleValues>	render_style;	
+		Optional<S32>					border_thickness;
+
+		Optional<LLUIColor>		highlight_light_color,
+								highlight_dark_color,
+								shadow_light_color,
+								shadow_dark_color;
+
+		Params();
+	};
+protected:
+	LLViewBorder(const Params&);
+	friend class LLUICtrlFactory;
+public:
 	virtual void setValue(const LLSD& val) { setRect(LLRect(val)); }
 
 	virtual BOOL isCtrl() const { return FALSE; }
@@ -51,7 +77,6 @@ public:
 	// llview functionality
 	virtual void draw();
 	
-	static  LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
 	static BOOL getBevelFromAttribute(LLXMLNodePtr node, LLViewBorder::EBevel& bevel_style);
 
 	void		setBorderWidth(S32 width)			{ mBorderWidth = width; }
@@ -63,8 +88,8 @@ public:
 				  				   const LLColor4& highlight_light, const LLColor4& highlight_dark );
 	void		setTexture( const class LLUUID &image_id );
 
-	LLColor4	getHighlightLight() {return mHighlightLight;}
-	LLColor4	getShadowDark() {return mHighlightDark;}
+	LLColor4	getHighlightLight() {return mHighlightLight.get();}
+	LLColor4	getShadowDark() {return mHighlightDark.get();}
 
 	EStyle		getStyle() const { return mStyle; }
 
@@ -77,14 +102,14 @@ private:
 	void		drawTextureTrapezoid( F32 degrees, S32 width, S32 length, F32 start_x, F32 start_y );
 
 	EBevel		mBevel;
-	const EStyle mStyle;
-	LLColor4	mHighlightLight;
-	LLColor4	mHighlightDark;
-	LLColor4	mShadowLight;
-	LLColor4	mShadowDark;
-	LLColor4	mBackgroundColor;
+	EStyle		mStyle;
+	LLUIColor	mHighlightLight;
+	LLUIColor	mHighlightDark;
+	LLUIColor	mShadowLight;
+	LLUIColor	mShadowDark;
+	LLUIColor	mBackgroundColor;
 	S32			mBorderWidth;
-	LLUIImagePtr	mTexture;
+	LLPointer<LLUIImage>	mTexture;
 	BOOL		mHasKeyboardFocus;
 };
 
diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp
new file mode 100644
index 0000000000..4107289e85
--- /dev/null
+++ b/indra/llui/llviewmodel.cpp
@@ -0,0 +1,163 @@
+/**
+ * @file   llviewmodel.cpp
+ * @author Nat Goodspeed
+ * @date   2008-08-08
+ * @brief  Implementation for llviewmodel.
+ * 
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llviewmodel.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+///
+LLViewModel::LLViewModel()
+ : mDirty(false)
+{
+}
+
+/// Instantiate an LLViewModel with an existing data value
+LLViewModel::LLViewModel(const LLSD& value)
+  : mDirty(false)
+{
+    setValue(value);
+}
+
+/// Update the stored value
+void LLViewModel::setValue(const LLSD& value)
+{
+    mValue = value;
+    mDirty = true;
+}
+
+LLSD LLViewModel::getValue() const
+{
+    return mValue;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+///
+LLTextViewModel::LLTextViewModel()
+  : LLViewModel(false),
+	mUpdateFromDisplay(false)
+{
+}
+
+/// Instantiate an LLViewModel with an existing data value
+LLTextViewModel::LLTextViewModel(const LLSD& value)
+  : LLViewModel(value),
+	mUpdateFromDisplay(false)
+{
+}
+
+/// Update the stored value
+void LLTextViewModel::setValue(const LLSD& value)
+{
+	LLViewModel::setValue(value);
+    mDisplay = utf8str_to_wstring(value.asString());
+    // mDisplay and mValue agree
+    mUpdateFromDisplay = false;
+}
+
+void LLTextViewModel::setDisplay(const LLWString& value)
+{
+    // This is the strange way to alter the value. Normally we'd setValue()
+    // and do the utf8str_to_wstring() to get the corresponding mDisplay
+    // value. But a text editor might want to edit the display string
+    // directly, then convert back to UTF8 on commit.
+    mDisplay = value;
+    mDirty = true;
+    // Don't immediately convert to UTF8 -- do it lazily -- we expect many
+    // more setDisplay() calls than getValue() calls. Just flag that it needs
+    // doing.
+    mUpdateFromDisplay = true;
+}
+
+LLSD LLTextViewModel::getValue() const
+{
+    // Has anyone called setDisplay() since the last setValue()? If so, have
+    // to convert mDisplay back to UTF8.
+    if (mUpdateFromDisplay)
+    {
+        // The fact that we're lazily updating fields in this object should be
+        // transparent to clients, which is why this method is left
+        // conventionally const. Nor do we particularly want to make these
+        // members mutable. Just cast away constness in this one place.
+        LLTextViewModel* nthis = const_cast<LLTextViewModel*>(this);
+        nthis->mUpdateFromDisplay = false;
+        nthis->mValue = wstring_to_utf8str(mDisplay);
+    }
+    return LLViewModel::getValue();
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+LLListViewModel::LLListViewModel(const LLSD& values)
+  : LLViewModel()
+{
+}
+
+void LLListViewModel::addColumn(const LLSD& column, EAddPosition pos)
+{
+}
+
+void LLListViewModel::clearColumns()
+{
+}
+
+void LLListViewModel::setColumnLabel(const std::string& column, const std::string& label)
+{
+}
+
+LLScrollListItem* LLListViewModel::addElement(const LLSD& value, EAddPosition pos,
+                                         void* userdata)
+{
+    return NULL;
+}
+
+LLScrollListItem* LLListViewModel::addSimpleElement(const std::string& value, EAddPosition pos,
+                                               const LLSD& id)
+{
+    return NULL;
+}
+
+void LLListViewModel::clearRows()
+{
+}
+
+void LLListViewModel::sortByColumn(const std::string& name, bool ascending)
+{
+}
diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h
new file mode 100644
index 0000000000..c8a9b52cca
--- /dev/null
+++ b/indra/llui/llviewmodel.h
@@ -0,0 +1,219 @@
+/**
+ * @file   llviewmodel.h
+ * @author Nat Goodspeed
+ * @date   2008-08-08
+ * @brief  Define "View Model" classes intended to store data values for use
+ *         by LLUICtrl subclasses. The phrase is borrowed from Microsoft
+ *         terminology, in which "View Model" means the storage object
+ *         underlying a specific widget object -- as in our case -- rather
+ *         than the business "model" object underlying the overall "view"
+ *         presented by the collection of widgets.
+ * 
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLVIEWMODEL_H)
+#define LL_LLVIEWMODEL_H
+
+#include "llpointer.h"
+#include "llsd.h"
+#include "llrefcount.h"
+#include "stdenums.h"
+#include "llstring.h"
+#include <string>
+
+class LLScrollListItem;
+
+class LLViewModel;
+class LLTextViewModel;
+class LLListViewModel;
+// Because LLViewModel is derived from LLRefCount, always pass, store
+// and return LLViewModelPtr rather than plain LLViewModel*.
+typedef LLPointer<LLViewModel> LLViewModelPtr;
+typedef LLPointer<LLTextViewModel> LLTextViewModelPtr;
+typedef LLPointer<LLListViewModel> LLListViewModelPtr;
+
+/**
+ * LLViewModel stores a scalar LLSD data item, the current display value of a
+ * scalar LLUICtrl widget. LLViewModel subclasses are used to store data
+ * collections used for aggregate widgets. LLViewModel is ref-counted because
+ * -- for multiple skins -- we may have distinct widgets sharing the same
+ * LLViewModel data. This way, the LLViewModel is quietly deleted when the
+ * last referencing widget is destroyed.
+ */
+class LLViewModel: public LLRefCount
+{
+public:
+    LLViewModel();
+    /// Instantiate an LLViewModel with an existing data value
+    LLViewModel(const LLSD& value);
+
+    /// Update the stored value
+    virtual void setValue(const LLSD& value);
+    /// Get the stored value, in appropriate type.
+    virtual LLSD getValue() const;
+
+    /// Has the value been changed since last time we checked?
+    bool isDirty() const { return mDirty; }
+    /// Once the value has been saved to a file, or otherwise consumed by the
+    /// app, we no longer need to enable the Save button
+    void resetDirty() { mDirty = false; }
+	// 
+    void setDirty() { mDirty = true; }
+
+protected:
+    LLSD mValue;
+    bool mDirty;
+};
+
+/**
+ * LLTextViewModel stores a value displayed as text. 
+ */
+class LLTextViewModel: public LLViewModel
+{
+public:
+    LLTextViewModel();
+    /// Instantiate an LLViewModel with an existing data value
+    LLTextViewModel(const LLSD& value);
+	
+	// LLViewModel functions
+    virtual void setValue(const LLSD& value);
+    virtual LLSD getValue() const;
+
+	// New functions
+    /// Get the stored value in string form
+    LLWString getDisplay() const { return mDisplay; }
+    /**
+     * Set the display string directly (see LLTextEditor). What the user is
+     * editing is actually the LLWString value rather than the underlying
+     * UTF-8 value.
+     */
+    void setDisplay(const LLWString& value);
+	
+private:
+    /// To avoid converting every widget's stored value from LLSD to LLWString
+    /// every frame, cache the converted value
+    LLWString mDisplay;
+    /// As the user edits individual characters (setDisplay()), defer
+    /// LLWString-to-UTF8 conversions until s/he's done.
+    bool mUpdateFromDisplay;
+};
+
+/**
+ * LLListViewModel stores a list of data items. The semantics are borrowed
+ * from LLScrollListCtrl.
+ */
+class LLListViewModel: public LLViewModel
+{
+public:
+    LLListViewModel() {}
+    LLListViewModel(const LLSD& values);
+
+    virtual void addColumn(const LLSD& column, EAddPosition pos = ADD_BOTTOM);
+    virtual void clearColumns();
+    virtual void setColumnLabel(const std::string& column, const std::string& label);
+    virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM,
+                                         void* userdata = NULL);
+    virtual LLScrollListItem* addSimpleElement(const std::string& value, EAddPosition pos,
+                                               const LLSD& id);
+    virtual void clearRows();
+    virtual void sortByColumn(const std::string& name, bool ascending);
+};
+
+//namespace LLViewModel
+//{
+//	class Value
+//	{
+//	public:
+//		Value(const LLSD& value = LLSD());
+//
+//		LLSD getValue() const { return mValue; }
+//		void setValue(const LLSD& value) { mValue = value; }
+//
+//		bool isAvailable() const { return false; }
+//		bool isReadOnly() const { return false; }
+//
+//		bool undo() { return false; }
+//		bool redo() { return false; }
+//
+//	    /// Has the value been changed since last time we checked?
+//		bool isDirty() const { return mDirty; }
+//		/// Once the value has been saved to a file, or otherwise consumed by the
+//		/// app, we no longer need to enable the Save button
+//		void resetDirty() { mDirty = false; }
+//		// 
+//		void setDirty() { mDirty = true; }
+//
+//	protected:
+//		LLSD	mValue;
+//		bool mDirty;
+//	};
+//
+//	class Numeric : public Value
+//	{
+//	public:
+//		Numeric(S32 value = 0);
+//		Numeric(F32 value);
+//
+//		F32 getPrecision();
+//		F32 getMin();
+//		F32 getMax();
+//
+//		void increment();
+//		void decrement();
+//	};
+//
+//	class MultipleValues : public Value
+//	{
+//		class Selector
+//		{};
+//
+//		MultipleValues();
+//		virtual S32 numElements();
+//	};
+//
+//	class Tuple : public MultipleValues
+//	{
+//		Tuple(S32 size);
+//		LLSD getValue(S32 which) const;
+//		void setValue(S32 which, const LLSD& value);
+//	};
+//
+//	class List : public MultipleValues
+//	{
+//		List();
+//
+//		void add(const ValueModel& value);
+//		bool remove(const Selector& item);
+//
+//		void setSortElement(const Selector& element);
+//		void sort();
+//	};
+//
+//};
+#endif /* ! defined(LL_LLVIEWMODEL_H) */
diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h
index e87795f9a3..98d9bf8796 100644
--- a/indra/llui/llviewquery.h
+++ b/indra/llui/llviewquery.h
@@ -35,7 +35,7 @@
 
 #include <list>	
 
-#include "llmemory.h"
+#include "llsingleton.h"
 #include "llui.h"
 
 class LLView;
-- 
cgit v1.2.3


From 5da967dc744f35d5270c7cb0b8b23b993ecda3e1 Mon Sep 17 00:00:00 2001
From: Steven Bennetts <steve@lindenlab.com>
Date: Fri, 8 May 2009 07:58:49 +0000
Subject: merge skinning-7 -r 119501-119577 -> viewer-2.0.0-1  *NOTE: This
 overlaps a little with the skinning-7 -> skinning-8 merge of 119500-119692 --
 James ignore-dead-branch

---
 indra/llui/llui.cpp    |  6 +++---
 indra/llui/llui.h      |  6 +++---
 indra/llui/lluiimage.h |  2 +-
 indra/llui/llview.cpp  | 11 +++++++++--
 indra/llui/llview.h    | 52 +++++++++++++++++++++++++-------------------------
 5 files changed, 42 insertions(+), 35 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index dfe435d2e3..1cb6972370 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1930,7 +1930,7 @@ LLLocalClipRect::LLLocalClipRect(const LLRect &rect, BOOL enabled)
 
 namespace LLInitParam
 {
-	TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLUIColor& value, ParamDescriptor::validation_func_t func)
+	TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func)
 	:	super_t(descriptor, name, value, func),
 		red("red"),
 		green("green"),
@@ -1960,7 +1960,7 @@ namespace LLInitParam
 		declare("blue", LLColor4::blue);
 	}
 
-	TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLFontGL*const value, ParamDescriptor::validation_func_t func)
+	TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL*const value, ParamDescriptor::validation_func_t func)
 	:	super_t(descriptor, name, value, func),
 		name("", std::string("")),
 		size("size", std::string("")),
@@ -1991,7 +1991,7 @@ namespace LLInitParam
 		return mData.mValue;
 	}
 
-	TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLRect& value, ParamDescriptor::validation_func_t func)
+	TypedParam<LLRect>::TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func)
 	:	super_t(descriptor, name, value, func),
 		left("left"),
 		top("top"),
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index b5a42bce13..18aa1aa143 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -706,7 +706,7 @@ namespace LLInitParam
 						width,
 						height;
 
-		TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLRect& value, ParamDescriptor::validation_func_t func);
+		TypedParam(BlockDescriptor& descriptor, const char* name, const LLRect& value, ParamDescriptor::validation_func_t func);
 
 		LLRect getValueFromBlock() const;
 	};
@@ -729,7 +729,7 @@ namespace LLInitParam
 		Optional<F32> alpha;
 		Optional<std::string> control;
 
-		TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLUIColor& value, ParamDescriptor::validation_func_t func);
+		TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func);
 		LLUIColor getValueFromBlock() const;
 	};
 
@@ -743,7 +743,7 @@ namespace LLInitParam
 		Optional<std::string> size;
 		Optional<std::string> style;
 
-		TypedParam(BlockDescriptor& descriptor, const std::string& name, const LLFontGL* const value, ParamDescriptor::validation_func_t func);
+		TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func);
 		const LLFontGL* getValueFromBlock() const;
 	};
 
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
index cd660a0954..ae43b50172 100644
--- a/indra/llui/lluiimage.h
+++ b/indra/llui/lluiimage.h
@@ -94,7 +94,7 @@ namespace LLInitParam
 	public:
 		Optional<std::string> name;
 
-		TypedParam(BlockDescriptor& descriptor, const std::string& name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func)
+		TypedParam(BlockDescriptor& descriptor, const char* name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func)
 		:	super_t(descriptor, name, value, func)
 		{
 		}
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 462fd16b60..536d0c23f8 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -2341,7 +2341,14 @@ void LLView::initFromParams(const LLView::Params& params)
 
 void LLView::parseFollowsFlags(const LLView::Params& params)
 {
-	if (params.follows.string.isProvided())
+	// preserve follows flags set by code if user did not override
+	if (!params.follows.isProvided()) 
+	{
+		return;
+	}
+
+	// interpret either string or bitfield version of follows
+	if (params.follows.string.isChosen())
 	{
 		setFollows(FOLLOWS_NONE);
 
@@ -2378,7 +2385,7 @@ void LLView::parseFollowsFlags(const LLView::Params& params)
 			++token_iter;
 		}
 	}
-	else if (params.follows.flags.isProvided())
+	else if (params.follows.flags.isChosen())
 	{
 		setFollows(params.follows.flags);
 	}
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 69ae7dd993..85e190c7d2 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -154,41 +154,41 @@ public:
 
 	struct Params : public LLInitParam::Block<Params>
 	{
-		Mandatory<std::string>	name;
-
-		Optional<bool>			enabled,
-								visible;
-		Optional<bool>			mouse_opaque;
-		Optional<bool>			use_bounding_rect;
-		Optional<S32>			tab_group,
-								default_tab_group;
-		Optional<std::string>	tool_tip;
-
-		Optional<S32>			sound_flags;
-		Optional<bool>			serializable;
-		Optional<Follows>		follows;
-		Optional<std::string>	hover_cursor;
+		Mandatory<std::string>		name;
+
+		Optional<bool>				enabled,
+									visible;
+		Optional<bool>				mouse_opaque;
+		Optional<bool>				use_bounding_rect;
+		Optional<S32>				tab_group,
+									default_tab_group;
+		Optional<std::string>		tool_tip;
+
+		Optional<S32>				sound_flags;
+		Optional<bool>				serializable;
+		Optional<Follows>			follows;
+		Optional<std::string>		hover_cursor;
 		
 		// font params
 		Optional<const LLFontGL*>	font;
 		Optional<LLFontGL::HAlign>	font_halign;
 		Optional<LLFontGL::VAlign>	font_valign;
 
-		Optional<std::string>	layout;
-		Optional<LLRect>		rect;
-		Optional<S32>			top_delta,
-								bottom_delta,
-								right_delta,
-								left_delta;
-								
-		Optional<bool>			center_horiz,
-								center_vert;
+		Optional<std::string>		layout;
+		Optional<LLRect>			rect;
+		Optional<S32>				top_delta,
+									bottom_delta,
+									right_delta,
+									left_delta;
+									
+		Optional<bool>				center_horiz,
+									center_vert;
 
 		// these are nested attributes for LLLayoutPanel
 		//FIXME: get parent context involved in parsing traversal
-		Deprecated				user_resize,
-								auto_resize,
-								needs_translate;
+		Deprecated					user_resize,
+									auto_resize,
+									needs_translate;
 
 		Params();
 	};
-- 
cgit v1.2.3


From 3800c0df910c83e987184d541b868168fc2b5bec Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 8 May 2009 21:08:08 +0000
Subject: svn merge -r114679:114681
 svn+ssh://svn.lindenlab.com/svn/linden/branches/event-system/event-system-7
 svn+ssh://svn.lindenlab.com/svn/linden/branches/event-system/event-system-8

---
 indra/llui/llbutton.cpp          | 16 ++++----
 indra/llui/llbutton.h            | 16 ++++----
 indra/llui/llmenugl.cpp          |  2 +
 indra/llui/llmenugl.h            |  8 ++--
 indra/llui/llmultislider.h       |  4 +-
 indra/llui/llmultisliderctrl.cpp |  4 +-
 indra/llui/llmultisliderctrl.h   |  4 +-
 indra/llui/llnotifications.cpp   | 23 +++++------
 indra/llui/llnotifications.h     | 87 +++++++++++++++++-----------------------
 indra/llui/llslider.h            |  4 +-
 indra/llui/llsliderctrl.cpp      |  4 +-
 indra/llui/llsliderctrl.h        |  4 +-
 indra/llui/llui.h                |  4 +-
 indra/llui/lluictrl.cpp          |  4 +-
 indra/llui/lluictrl.h            | 18 ++++-----
 indra/llui/llview.cpp            |  2 +
 16 files changed, 96 insertions(+), 108 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 1f6cd6ddf9..cdd364797c 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -240,37 +240,37 @@ void LLButton::onCommit()
 	LLUICtrl::onCommit();
 }
 
-boost::signals::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
 {
 	return mCommitSignal.connect(cb);
 }
-boost::signals::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
 {
 	return mMouseDownSignal.connect(cb);
 }
-boost::signals::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
 {
 	return mMouseUpSignal.connect(cb);
 }
-boost::signals::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
 {
 	return mHeldDownSignal.connect(cb);
 }
 
 // *TODO: Deprecate (for backwards compatability only)
-boost::signals::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
+boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
 {
 	return setClickedCallback(boost::bind(cb, data));
 }
-boost::signals::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
+boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
 {
 	return setMouseDownCallback(boost::bind(cb, data));
 }
-boost::signals::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
+boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
 {
 	return setMouseUpCallback(boost::bind(cb, data));
 }
-boost::signals::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data )
+boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data )
 {
 	return setHeldDownCallback(boost::bind(cb, data));
 }
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index f146ef9dc2..99f4b94805 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -150,17 +150,17 @@ public:
 	void			setUnselectedLabelColor( const LLColor4& c )		{ mUnselectedLabelColor = c; }
 	void			setSelectedLabelColor( const LLColor4& c )			{ mSelectedLabelColor = c; }
 
-	boost::signals::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button
-	boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
-	boost::signals::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON
+	boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button
+	boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
+	boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON
 	// Passes a 'count' parameter in the commit param payload, i.e. param["count"])
-	boost::signals::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button
+	boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button
 	
 	// *TODO: Deprecate (for backwards compatability only)
-	boost::signals::connection setClickedCallback( button_callback_t cb, void* data );
-	boost::signals::connection setMouseDownCallback( button_callback_t cb, void* data );
-	boost::signals::connection setMouseUpCallback( button_callback_t cb, void* data );
-	boost::signals::connection setHeldDownCallback( button_callback_t cb, void* data );
+	boost::signals2::connection setClickedCallback( button_callback_t cb, void* data );
+	boost::signals2::connection setMouseDownCallback( button_callback_t cb, void* data );
+	boost::signals2::connection setMouseUpCallback( button_callback_t cb, void* data );
+	boost::signals2::connection setHeldDownCallback( button_callback_t cb, void* data );
 		
 	void			setHeldDownDelay( F32 seconds, S32 frames = 0)		{ mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; }
 	
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index a3588d9dae..fc2e6e163b 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -65,6 +65,8 @@
 #include <set>
 #include <boost/tokenizer.hpp>
 
+using namespace LLOldEvents;
+
 // static
 LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
 
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 3cb76efce0..ffaecc2c15 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -285,12 +285,12 @@ public:
 	
 	//virtual void draw();
 	
-	boost::signals::connection setClickCallback( const commit_signal_t::slot_type& cb )
+	boost::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb )
 	{
 		return setCommitCallback(cb);
 	}
 	
-	boost::signals::connection setEnableCallback( const enable_signal_t::slot_type& cb )
+	boost::signals2::connection setEnableCallback( const enable_signal_t::slot_type& cb )
 	{
 		return mEnableSignal.connect(cb);
 	}
@@ -335,7 +335,7 @@ public:
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
 	
-	boost::signals::connection setCheckCallback( const enable_signal_t::slot_type& cb )
+	boost::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb )
 	{
 		return mCheckSignal.connect(cb);
 	}
@@ -823,7 +823,7 @@ private:
 
 // *TODO: Eliminate
 // For backwards compatability only; generally just use boost::bind
-class view_listener_t : public boost::signals::trackable
+class view_listener_t : public boost::signals2::trackable
 {
 public:
 	virtual bool handleEvent(const LLSD& userdata) = 0;
diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h
index 9c01b528a7..89d44eaa87 100644
--- a/indra/llui/llmultislider.h
+++ b/indra/llui/llmultislider.h
@@ -78,8 +78,8 @@ public:
 	/*virtual*/ void	setValue(const LLSD& value);
 	/*virtual*/ LLSD	getValue() const		{ return mValue; }
 
-	boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ) { return mMouseDownSignal.connect(cb); }
-	boost::signals::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb )   { return mMouseUpSignal.connect(cb); }
+	boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ) { return mMouseDownSignal.connect(cb); }
+	boost::signals2::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb )   { return mMouseUpSignal.connect(cb); }
 
 	bool			findUnusedValue(F32& initVal);
 	const std::string&	addSlider();
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index 14584e6df5..bc981a9b57 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -460,12 +460,12 @@ void LLMultiSliderCtrl::setPrecision(S32 precision)
 	updateText();
 }
 
-boost::signals::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLMultiSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
 {
 	return mMultiSlider->setMouseDownCallback( cb );
 }
 
-boost::signals::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLMultiSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
 {
 	return mMultiSlider->setMouseUpCallback( cb );
 }
diff --git a/indra/llui/llmultisliderctrl.h b/indra/llui/llmultisliderctrl.h
index 85ba77b7df..4855ed4926 100644
--- a/indra/llui/llmultisliderctrl.h
+++ b/indra/llui/llmultisliderctrl.h
@@ -115,8 +115,8 @@ public:
 	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
 	void			setDisabledLabelColor(const LLColor4& c)	{ mTextDisabledColor = c; }
 
-	boost::signals::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
-	boost::signals::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
+	boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
+	boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
 
 	virtual void	onTabInto();
 
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 34ff21268e..569112aef1 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -685,7 +685,7 @@ std::string LLNotification::getURL() const
 // =========================================================
 // LLNotificationChannel implementation
 // ---
-void LLNotificationChannelBase::connectChanged(const LLStandardSignal::slot_type& slot)
+LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListener& slot)
 {
 	// when someone wants to connect to a channel, we first throw them
 	// all of the notifications that are already in the channel
@@ -693,23 +693,23 @@ void LLNotificationChannelBase::connectChanged(const LLStandardSignal::slot_type
 	// only about new notifications
 	for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
 	{
-		slot.get_slot_function()(LLSD().insert("sigtype", "load").insert("id", (*it)->id()));
+		slot(LLSD().insert("sigtype", "load").insert("id", (*it)->id()));
 	}
 	// and then connect the signal so that all future notifications will also be
 	// forwarded.
-	mChanged.connect(slot);
+	return mChanged.connect(slot);
 }
 
-void LLNotificationChannelBase::connectPassedFilter(const LLStandardSignal::slot_type& slot)
+LLBoundListener LLNotificationChannelBase::connectPassedFilterImpl(const LLEventListener& slot)
 {
 	// these two filters only fire for notifications added after the current one, because
 	// they don't participate in the hierarchy.
-	mPassedFilter.connect(slot);
+	return mPassedFilter.connect(slot);
 }
 
-void LLNotificationChannelBase::connectFailedFilter(const LLStandardSignal::slot_type& slot)
+LLBoundListener LLNotificationChannelBase::connectFailedFilterImpl(const LLEventListener& slot)
 {
-	mFailedFilter.connect(slot);
+	return mFailedFilter.connect(slot);
 }
 
 // external call, conforms to our standard signature
@@ -867,8 +867,7 @@ mParent(parent)
 	else
 	{
 		LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent);
-		LLStandardSignal::slot_type f = boost::bind(&LLNotificationChannelBase::updateItem, this, _1);
-		p->connectChanged(f);
+		p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
 	}
 }
 
@@ -1065,11 +1064,11 @@ void LLNotifications::createDefaultChannels()
 
 	// connect action methods to these channels
 	LLNotifications::instance().getChannel("Expiration")->
-		connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
+        connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
 	LLNotifications::instance().getChannel("Unique")->
-		connectChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
+        connectChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
 	LLNotifications::instance().getChannel("Unique")->
-		connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
+        connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
 	LLNotifications::instance().getChannel("Ignore")->
 		connectFailedFilter(&handleIgnoredNotification);
 }
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index de86f5daa2..5c8d146e0c 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -91,13 +91,14 @@
 
 #include <boost/utility.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/signal.hpp>
+#include <boost/enable_shared_from_this.hpp>
 #include <boost/type_traits.hpp>
 
 // we want to minimize external dependencies, but this one is important
 #include "llsd.h"
 
 // and we need this to manage the notification callbacks
+#include "llevents.h"
 #include "llfunctorregistry.h"
 #include "llui.h"
 #include "llmemory.h"
@@ -105,36 +106,6 @@
 class LLNotification;
 typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
 
-/*****************************************************************************
-*   Signal and handler declarations
-*   Using a single handler signature means that we can have a common handler
-*   type, rather than needing a distinct one for each different handler.
-*****************************************************************************/
-
-/**
- * A boost::signals Combiner that stops the first time a handler returns true
- * We need this because we want to have our handlers return bool, so that
- * we have the option to cause a handler to stop further processing. The
- * default handler fails when the signal returns a value but has no slots.
- */
-struct LLStopWhenHandled
-{
-    typedef bool result_type;
-
-    template<typename InputIterator>
-    result_type operator()(InputIterator first, InputIterator last) const
-    {
-        for (InputIterator si = first; si != last; ++si)
-		{
-            if (*si)
-			{
-                return true;
-			}
-		}
-        return false;
-    }
-};
-
 	
 typedef enum e_notification_priority
 {
@@ -145,27 +116,11 @@ typedef enum e_notification_priority
 	NOTIFICATION_PRIORITY_CRITICAL
 } ENotificationPriority;
 
-/**
- * We want to have a standard signature for all signals; this way,
- * we can easily document a protocol for communicating across
- * dlls and into scripting languages someday.
- * we want to return a bool to indicate whether the signal has been
- * handled and should NOT be passed on to other listeners.
- * Return true to stop further handling of the signal, and false
- * to continue.
- * We take an LLSD because this way the contents of the signal
- * are independent of the API used to communicate it.
- * It is const ref because then there's low cost to pass it;
- * if you only need to inspect it, it's very cheap.
- */
-
 typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
 
 typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
 typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
 
-typedef boost::signal<bool(const LLSD&), LLStopWhenHandled>  LLStandardSignal;
-
 // context data that can be looked up via a notification's payload by the display logic
 // derive from this class to implement specific contexts
 class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
@@ -713,7 +668,7 @@ typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
 // all of the built-in tests should attach to the "Visible" channel
 //
 class LLNotificationChannelBase :
-	public boost::signals::trackable
+	public LLEventTrackable
 {
 	LOG_CLASS(LLNotificationChannelBase);
 public:
@@ -723,15 +678,45 @@ public:
 	virtual ~LLNotificationChannelBase() {}
 	// you can also connect to a Channel, so you can be notified of
 	// changes to this channel
-	virtual void connectChanged(const LLStandardSignal::slot_type& slot);
-	virtual void connectPassedFilter(const LLStandardSignal::slot_type& slot);
-	virtual void connectFailedFilter(const LLStandardSignal::slot_type& slot);
+	template <typename LISTENER>
+    LLBoundListener connectChanged(const LISTENER& slot)
+    {
+        // Examine slot to see if it binds an LLEventTrackable subclass, or a
+        // boost::shared_ptr to something, or a boost::weak_ptr to something.
+        // Call this->connectChangedImpl() to actually connect it.
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectPassedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectFailedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
+                                              this,
+                                              _1));
+    }
 
 	// use this when items change or to add a new one
 	bool updateItem(const LLSD& payload);
 	const LLNotificationFilter& getFilter() { return mFilter; }
 
 protected:
+    LLBoundListener connectChangedImpl(const LLEventListener& slot);
+    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
+    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
+
 	LLNotificationSet mItems;
 	LLStandardSignal mChanged;
 	LLStandardSignal mPassedFilter;
diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h
index 39c55afd8c..dad65fcce0 100644
--- a/indra/llui/llslider.h
+++ b/indra/llui/llslider.h
@@ -67,8 +67,8 @@ public:
 	virtual void	setMinValue(F32 min_value) { LLF32UICtrl::setMinValue(min_value); updateThumbRect(); }
 	virtual void	setMaxValue(F32 max_value) { LLF32UICtrl::setMaxValue(max_value); updateThumbRect(); }
 
-	boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ) { return mMouseDownSignal.connect(cb); }
-	boost::signals::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb )   { return mMouseUpSignal.connect(cb); }
+	boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ) { return mMouseDownSignal.connect(cb); }
+	boost::signals2::connection setMouseUpCallback(	const commit_signal_t::slot_type& cb )   { return mMouseUpSignal.connect(cb); }
 
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index d5053478a6..2c8aed6196 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -375,12 +375,12 @@ void LLSliderCtrl::setPrecision(S32 precision)
 	updateText();
 }
 
-boost::signals::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLSliderCtrl::setSliderMouseDownCallback( const commit_signal_t::slot_type& cb )
 {
 	return mSlider->setMouseDownCallback( cb );
 }
 
-boost::signals::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
+boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit_signal_t::slot_type& cb )
 {
 	return mSlider->setMouseUpCallback( cb );
 }
diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h
index 0bcb1ccc9b..5bdbbfcbcc 100644
--- a/indra/llui/llsliderctrl.h
+++ b/indra/llui/llsliderctrl.h
@@ -111,8 +111,8 @@ public:
 	void			setLabelColor(const LLColor4& c)			{ mTextEnabledColor = c; }
 	void			setDisabledLabelColor(const LLColor4& c)	{ mTextDisabledColor = c; }
 
-	boost::signals::connection setSliderMouseDownCallback(	const commit_signal_t::slot_type& cb );
-	boost::signals::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
+	boost::signals2::connection setSliderMouseDownCallback(	const commit_signal_t::slot_type& cb );
+	boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb );
 
 	/*virtual*/ void	onTabInto();
 
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 18aa1aa143..71396e10d9 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -45,7 +45,7 @@
 #include "lluiimage.h"		// *TODO: break this dependency, need to add #include "lluiimage.h" to all widgets that hold an Optional<LLUIImage*> in their paramblocks
 #include "llinitparam.h"
 #include "llregistry.h"
-#include <boost/signal.hpp>
+#include <boost/signals2.hpp>
 #include "lllazyvalue.h"
 
 // LLUIFactory
@@ -576,7 +576,7 @@ public:
 class LLCallbackRegistry
 {
 public:
-	typedef boost::signal<void()> callback_signal_t;
+	typedef boost::signals2::signal<void()> callback_signal_t;
 	
 	void registerCallback(const callback_signal_t::slot_type& slot)
 	{
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index da0db0424a..99811809a8 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -749,11 +749,11 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const
 }
 
 // *TODO: Deprecate; for backwards compatability only:
-boost::signals::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
+boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
 {
 	return setCommitCallback( boost::bind(cb, _1, data));
 }
-boost::signals::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
+boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
 {
 	return mValidateSignal.connect(boost::bind(cb, _2));
 }
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index e82102d531..6d310dca22 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -74,16 +74,16 @@ protected:
 };
 
 class LLUICtrl
-	: public LLView, public LLFocusableElement, public boost::signals::trackable
+	: public LLView, public LLFocusableElement, public boost::signals2::trackable
 {
 public:
 
 
 	typedef boost::function<void (LLUICtrl* ctrl, const LLSD& param)> commit_callback_t;
-	typedef boost::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t;
+	typedef boost::signals2::signal<void (LLUICtrl* ctrl, const LLSD& param)> commit_signal_t;
 	
 	typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t;
-	typedef boost::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t;
+	typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t;
 	
 	struct CallbackParam : public LLInitParam::Block<CallbackParam>
 	{
@@ -217,12 +217,12 @@ public:
 
 	LLUICtrl*		getParentUICtrl() const;
 
-	boost::signals::connection setCommitCallback( const commit_signal_t::slot_type& cb ) { return mCommitSignal.connect(cb); }
-	boost::signals::connection setValidateCallback( const enable_signal_t::slot_type& cb ) { return mValidateSignal.connect(cb); }
+	boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ) { return mCommitSignal.connect(cb); }
+	boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ) { return mValidateSignal.connect(cb); }
 	
 	// *TODO: Deprecate; for backwards compatability only:
-	boost::signals::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data);	
-	boost::signals::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb );
+	boost::signals2::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data);	
+	boost::signals2::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb );
 	
 	LLUICtrl* findRootMostFocusRoot();
 
@@ -250,9 +250,9 @@ protected:
     LLViewModelPtr  mViewModel;
 
 	LLControlVariable* mControlVariable;
-	boost::signals::connection mControlConnection;
+	boost::signals2::connection mControlConnection;
 	LLControlVariable* mEnabledControlVariable;
-	boost::signals::connection mEnabledControlConnection;
+	boost::signals2::connection mEnabledControlConnection;
 
 private:
 
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 536d0c23f8..0a28075ed6 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -56,6 +56,8 @@
 #include "lltexteditor.h"
 #include "lltextbox.h"
 
+using namespace LLOldEvents;
+
 BOOL	LLView::sDebugRects = FALSE;
 BOOL	LLView::sDebugKeys = FALSE;
 S32		LLView::sDepth = 0;
-- 
cgit v1.2.3


From 01d390825a5d9ba37715b80cd0aa7aede022dcec Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 22 May 2009 23:27:16 +0000
Subject: DEV-27646 dll linkage for login module. Ok, finally got this to a
 point where it doesn't break the build and I can check in. llcommon can be
 built as a shared library (disabled but can be enabled with cmake cache var
 LLCOMMON_LINK_SHARED.

reviewed by Mani on tuesday (I still need to get his suggested changes
re-reviewed)
---
 indra/llui/llfunctorregistry.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra/llui')

diff --git a/indra/llui/llfunctorregistry.cpp b/indra/llui/llfunctorregistry.cpp
index 0c5b1655b1..5f9644f258 100644
--- a/indra/llui/llfunctorregistry.cpp
+++ b/indra/llui/llfunctorregistry.cpp
@@ -31,6 +31,7 @@
  * $/LicenseInfo$
  **/
 
+#include "linden_common.h"
 #include "llfunctorregistry.h"
 
 // This is a default functor always resident in the system.
-- 
cgit v1.2.3


From 429bd9b55c54164d133276ed5b1fd54e565eb1b4 Mon Sep 17 00:00:00 2001
From: brad kittenbrink <brad@lindenlab.com>
Date: Wed, 8 Jul 2009 12:07:31 -0700
Subject: Added LLNotificationsListener to hook LLNotifications to the event
 system according to
 https://wiki.lindenlab.com/wiki/Incremental_Viewer_Automation/Event_API
 reviewed by palmer.

---
 indra/llui/CMakeLists.txt              |  378 ++--
 indra/llui/llnotifications.cpp         | 3005 ++++++++++++++++----------------
 indra/llui/llnotifications.h           | 1823 +++++++++----------
 indra/llui/llnotificationslistener.cpp |   28 +
 indra/llui/llnotificationslistener.h   |   31 +
 5 files changed, 2666 insertions(+), 2599 deletions(-)
 create mode 100644 indra/llui/llnotificationslistener.cpp
 create mode 100644 indra/llui/llnotificationslistener.h

(limited to 'indra/llui')

diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 117e8e28ab..a6a5ef1f92 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -1,188 +1,190 @@
-# -*- cmake -*-
-
-project(llui)
-
-include(00-Common)
-include(LLAudio)
-include(LLCommon)
-include(LLImage)
-include(LLMath)
-include(LLMessage)
-include(LLRender)
-include(LLWindow)
-include(LLVFS)
-include(LLXML)
-
-include_directories(
-    ${LLAUDIO_INCLUDE_DIRS}
-    ${LLCOMMON_INCLUDE_DIRS}
-    ${LLIMAGE_INCLUDE_DIRS}
-    ${LLMATH_INCLUDE_DIRS}
-    ${LLMESSAGE_INCLUDE_DIRS}
-    ${LLRENDER_INCLUDE_DIRS}
-    ${LLWINDOW_INCLUDE_DIRS}
-    ${LLVFS_INCLUDE_DIRS}
-    ${LLXML_INCLUDE_DIRS}
-    )
-
-set(llui_SOURCE_FILES
-    llalertdialog.cpp
-    llbutton.cpp
-    llcheckboxctrl.cpp
-    llclipboard.cpp
-    llcombobox.cpp
-    llconsole.cpp
-    llcontainerview.cpp
-    llctrlselectioninterface.cpp
-    lldraghandle.cpp
-    lleditmenuhandler.cpp
-    llf32uictrl.cpp
-    llfloater.cpp
-    llfloaterreg.cpp
-    llflyoutbutton.cpp 
-    llfocusmgr.cpp
-    llfunctorregistry.cpp
-    lliconctrl.cpp
-    llinitparam.cpp
-    llkeywords.cpp
-    lllayoutstack.cpp
-    lllineeditor.cpp
-    llmenugl.cpp
-    llmodaldialog.cpp
-    llmultifloater.cpp 
-    llmultislider.cpp
-    llmultisliderctrl.cpp
-    llnotifications.cpp
-    llpanel.cpp
-    llprogressbar.cpp
-    llradiogroup.cpp
-    llresizebar.cpp
-    llresizehandle.cpp
-    llresmgr.cpp
-    llscrollbar.cpp
-    llscrollcontainer.cpp
-    llscrollingpanellist.cpp
-    llscrolllistcell.cpp
-    llscrolllistcolumn.cpp
-    llscrolllistctrl.cpp
-    llscrolllistitem.cpp
-    llsdparam.cpp
-    llsearcheditor.cpp 
-    llslider.cpp
-    llsliderctrl.cpp
-    llspinctrl.cpp
-    llstatbar.cpp
-    llstatgraph.cpp
-    llstatview.cpp
-    llstyle.cpp
-    lltabcontainer.cpp
-    lltextbox.cpp
-    lltexteditor.cpp
-    lltextparser.cpp
-    lltrans.cpp
-    llui.cpp
-    lluicolortable.cpp
-    lluictrl.cpp
-    lluictrlfactory.cpp
-    lluiimage.cpp
-    lluistring.cpp
-    llundo.cpp
-    llviewborder.cpp
-    llviewmodel.cpp
-    llview.cpp
-    llviewquery.cpp
-    )
-    
-set(llui_HEADER_FILES
-    CMakeLists.txt
-
-    llalertdialog.h
-    llbutton.h
-    llcallbackmap.h
-    llcheckboxctrl.h
-    llclipboard.h
-    llcombobox.h
-    llconsole.h
-    llcontainerview.h
-    llctrlselectioninterface.h
-    lldraghandle.h
-    lleditmenuhandler.h
-    llf32uictrl.h
-    llfloater.h
-    llfloaterreg.h
-    llflyoutbutton.h 
-    llfocusmgr.h
-    llfunctorregistry.h
-    llhtmlhelp.h
-    lliconctrl.h
-    llinitparam.h
-    llkeywords.h
-    lllayoutstack.h
-    lllazyvalue.h
-    lllineeditor.h
-    llmenugl.h
-    llmodaldialog.h
-    llmultifloater.h 
-    llmultisliderctrl.h
-    llmultislider.h
-    llnotifications.h
-    llpanel.h
-    llprogressbar.h
-    llradiogroup.h
-    llregistry.h
-    llresizebar.h
-    llresizehandle.h
-    llresmgr.h
-    llsearcheditor.h 
-    llscrollbar.h
-    llscrollcontainer.h
-    llscrollingpanellist.h
-    llscrolllistcell.h
-    llscrolllistcolumn.h
-    llscrolllistctrl.h
-    llscrolllistitem.h
-    llsdparam.h
-    llsliderctrl.h
-    llslider.h
-    llspinctrl.h
-    llstatbar.h
-    llstatgraph.h
-    llstatview.h
-    llstyle.h
-    lltabcontainer.h
-    lltextbox.h
-    lltexteditor.h
-    lltextparser.h
-    lltrans.h
-    lluicolortable.h
-    lluiconstants.h
-    lluictrlfactory.h
-    lluictrl.h
-    lluifwd.h
-    llui.h
-    lluiimage.h
-    lluistring.h
-    llundo.h
-    llviewborder.h
-    llviewmodel.h
-    llview.h
-    llviewquery.h
-    )
-
-set_source_files_properties(${llui_HEADER_FILES}
-                            PROPERTIES HEADER_FILE_ONLY TRUE)
-
-list(APPEND llui_SOURCE_FILES ${llui_HEADER_FILES})
-
-add_library (llui ${llui_SOURCE_FILES})
-# Libraries on which this library depends, needed for Linux builds
-# Sort by high-level to low-level
-target_link_libraries(llui
-    llrender
-    llwindow
-    llimage
-    llvfs       # ugh, just for LLDir
-    llxml
-    llcommon    # must be after llimage, llwindow, llrender
-    llmath
-    )
+# -*- cmake -*-
+
+project(llui)
+
+include(00-Common)
+include(LLAudio)
+include(LLCommon)
+include(LLImage)
+include(LLMath)
+include(LLMessage)
+include(LLRender)
+include(LLWindow)
+include(LLVFS)
+include(LLXML)
+
+include_directories(
+    ${LLAUDIO_INCLUDE_DIRS}
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLIMAGE_INCLUDE_DIRS}
+    ${LLMATH_INCLUDE_DIRS}
+    ${LLMESSAGE_INCLUDE_DIRS}
+    ${LLRENDER_INCLUDE_DIRS}
+    ${LLWINDOW_INCLUDE_DIRS}
+    ${LLVFS_INCLUDE_DIRS}
+    ${LLXML_INCLUDE_DIRS}
+    )
+
+set(llui_SOURCE_FILES
+    llalertdialog.cpp
+    llbutton.cpp
+    llcheckboxctrl.cpp
+    llclipboard.cpp
+    llcombobox.cpp
+    llconsole.cpp
+    llcontainerview.cpp
+    llctrlselectioninterface.cpp
+    lldraghandle.cpp
+    lleditmenuhandler.cpp
+    llf32uictrl.cpp
+    llfloater.cpp
+    llfloaterreg.cpp
+    llflyoutbutton.cpp 
+    llfocusmgr.cpp
+    llfunctorregistry.cpp
+    lliconctrl.cpp
+    llinitparam.cpp
+    llkeywords.cpp
+    lllayoutstack.cpp
+    lllineeditor.cpp
+    llmenugl.cpp
+    llmodaldialog.cpp
+    llmultifloater.cpp 
+    llmultislider.cpp
+    llmultisliderctrl.cpp
+    llnotifications.cpp
+    llnotificationslistener.cpp
+    llpanel.cpp
+    llprogressbar.cpp
+    llradiogroup.cpp
+    llresizebar.cpp
+    llresizehandle.cpp
+    llresmgr.cpp
+    llscrollbar.cpp
+    llscrollcontainer.cpp
+    llscrollingpanellist.cpp
+    llscrolllistcell.cpp
+    llscrolllistcolumn.cpp
+    llscrolllistctrl.cpp
+    llscrolllistitem.cpp
+    llsdparam.cpp
+    llsearcheditor.cpp 
+    llslider.cpp
+    llsliderctrl.cpp
+    llspinctrl.cpp
+    llstatbar.cpp
+    llstatgraph.cpp
+    llstatview.cpp
+    llstyle.cpp
+    lltabcontainer.cpp
+    lltextbox.cpp
+    lltexteditor.cpp
+    lltextparser.cpp
+    lltrans.cpp
+    llui.cpp
+    lluicolortable.cpp
+    lluictrl.cpp
+    lluictrlfactory.cpp
+    lluiimage.cpp
+    lluistring.cpp
+    llundo.cpp
+    llviewborder.cpp
+    llviewmodel.cpp
+    llview.cpp
+    llviewquery.cpp
+    )
+    
+set(llui_HEADER_FILES
+    CMakeLists.txt
+
+    llalertdialog.h
+    llbutton.h
+    llcallbackmap.h
+    llcheckboxctrl.h
+    llclipboard.h
+    llcombobox.h
+    llconsole.h
+    llcontainerview.h
+    llctrlselectioninterface.h
+    lldraghandle.h
+    lleditmenuhandler.h
+    llf32uictrl.h
+    llfloater.h
+    llfloaterreg.h
+    llflyoutbutton.h 
+    llfocusmgr.h
+    llfunctorregistry.h
+    llhtmlhelp.h
+    lliconctrl.h
+    llinitparam.h
+    llkeywords.h
+    lllayoutstack.h
+    lllazyvalue.h
+    lllineeditor.h
+    llmenugl.h
+    llmodaldialog.h
+    llmultifloater.h 
+    llmultisliderctrl.h
+    llmultislider.h
+    llnotifications.h
+    llnotificationslistener.h
+    llpanel.h
+    llprogressbar.h
+    llradiogroup.h
+    llregistry.h
+    llresizebar.h
+    llresizehandle.h
+    llresmgr.h
+    llsearcheditor.h 
+    llscrollbar.h
+    llscrollcontainer.h
+    llscrollingpanellist.h
+    llscrolllistcell.h
+    llscrolllistcolumn.h
+    llscrolllistctrl.h
+    llscrolllistitem.h
+    llsdparam.h
+    llsliderctrl.h
+    llslider.h
+    llspinctrl.h
+    llstatbar.h
+    llstatgraph.h
+    llstatview.h
+    llstyle.h
+    lltabcontainer.h
+    lltextbox.h
+    lltexteditor.h
+    lltextparser.h
+    lltrans.h
+    lluicolortable.h
+    lluiconstants.h
+    lluictrlfactory.h
+    lluictrl.h
+    lluifwd.h
+    llui.h
+    lluiimage.h
+    lluistring.h
+    llundo.h
+    llviewborder.h
+    llviewmodel.h
+    llview.h
+    llviewquery.h
+    )
+
+set_source_files_properties(${llui_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llui_SOURCE_FILES ${llui_HEADER_FILES})
+
+add_library (llui ${llui_SOURCE_FILES})
+# Libraries on which this library depends, needed for Linux builds
+# Sort by high-level to low-level
+target_link_libraries(llui
+    llrender
+    llwindow
+    llimage
+    llvfs       # ugh, just for LLDir
+    llxml
+    llcommon    # must be after llimage, llwindow, llrender
+    llmath
+    )
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 50fee41029..ec92e57b6e 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1,1501 +1,1504 @@
-/**
-* @file llnotifications.cpp
-* @brief Non-UI queue manager for keeping a prioritized list of notifications
-*
-* $LicenseInfo:firstyear=2008&license=viewergpl$
-* 
-* Copyright (c) 2008-2009, Linden Research, Inc.
-* 
-* Second Life Viewer Source Code
-* The source code in this file ("Source Code") is provided by Linden Lab
-* to you under the terms of the GNU General Public License, version 2.0
-* ("GPL"), unless you have obtained a separate licensing agreement
-* ("Other License"), formally executed by you and Linden Lab.  Terms of
-* the GPL can be found in doc/GPL-license.txt in this distribution, or
-* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
-* 
-* There are special exceptions to the terms and conditions of the GPL as
-* it is applied to this Source Code. View the full text of the exception
-* in the file doc/FLOSS-exception.txt in this software distribution, or
-* online at
-* http://secondlifegrid.net/programs/open_source/licensing/flossexception
-* 
-* By copying, modifying or distributing this software, you acknowledge
-* that you have read and understood your obligations described above,
-* and agree to abide by those obligations.
-* 
-* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-* COMPLETENESS OR PERFORMANCE.
-* $/LicenseInfo$
-*/
-
-#include "linden_common.h"
-
-#include "llnotifications.h"
-
-#include "lluictrl.h"
-#include "lluictrlfactory.h"
-#include "lldir.h"
-#include "llsdserialize.h"
-#include "lltrans.h"
-
-#include <algorithm>
-#include <boost/regex.hpp>
-
-
-const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
-
-// local channel for notification history
-class LLNotificationHistoryChannel : public LLNotificationChannel
-{
-	LOG_CLASS(LLNotificationHistoryChannel);
-public:
-	LLNotificationHistoryChannel(const std::string& filename) : 
-		LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()),
-		mFileName(filename)
-	{
-		connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1));
-		loadPersistentNotifications();
-	}
-
-private:
-	bool historyHandler(const LLSD& payload)
-	{
-		// we ignore "load" messages, but rewrite the persistence file on any other
-		std::string sigtype = payload["sigtype"];
-		if (sigtype != "load")
-		{
-			savePersistentNotifications();
-		}
-		return false;
-	}
-
-	// The history channel gets all notifications except those that have been cancelled
-	static bool historyFilter(LLNotificationPtr pNotification)
-	{
-		return !pNotification->isCancelled();
-	}
-
-	void savePersistentNotifications()
-	{
-		llinfos << "Saving open notifications to " << mFileName << llendl;
-
-		llofstream notify_file(mFileName.c_str());
-		if (!notify_file.is_open()) 
-		{
-			llwarns << "Failed to open " << mFileName << llendl;
-			return;
-		}
-
-		LLSD output;
-		output["version"] = NOTIFICATION_PERSIST_VERSION;
-		LLSD& data = output["data"];
-
-		for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
-		{
-			if (!LLNotifications::instance().templateExists((*it)->getName())) continue;
-
-			// only store notifications flagged as persisting
-			LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName());
-			if (!templatep->mPersist) continue;
-
-			data.append((*it)->asLLSD());
-		}
-
-		LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
-		formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
-	}
-
-	void loadPersistentNotifications()
-	{
-		llinfos << "Loading open notifications from " << mFileName << llendl;
-
-		llifstream notify_file(mFileName.c_str());
-		if (!notify_file.is_open()) 
-		{
-			llwarns << "Failed to open " << mFileName << llendl;
-			return;
-		}
-
-		LLSD input;
-		LLPointer<LLSDParser> parser = new LLSDXMLParser();
-		if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
-		{
-			llwarns << "Failed to parse open notifications" << llendl;
-			return;
-		}
-
-		if (input.isUndefined()) return;
-		std::string version = input["version"];
-		if (version != NOTIFICATION_PERSIST_VERSION)
-		{
-			llwarns << "Bad open notifications version: " << version << llendl;
-			return;
-		}
-		LLSD& data = input["data"];
-		if (data.isUndefined()) return;
-
-		LLNotifications& instance = LLNotifications::instance();
-		for (LLSD::array_const_iterator notification_it = data.beginArray();
-			notification_it != data.endArray();
-			++notification_it)
-		{
-			instance.add(LLNotificationPtr(new LLNotification(*notification_it)));
-		}
-	}
-
-	//virtual
-	void onDelete(LLNotificationPtr pNotification)
-	{
-		// we want to keep deleted notifications in our log
-		mItems.insert(pNotification);
-		
-		return;
-	}
-	
-private:
-	std::string mFileName;
-};
-
-bool filterIgnoredNotifications(LLNotificationPtr notification)
-{
-	// filter everything if we are to ignore ALL
-	if(LLNotifications::instance().getIgnoreAllNotifications())
-	{
-		return false;
-	}
-
-	LLNotificationFormPtr form = notification->getForm();
-	// Check to see if the user wants to ignore this alert
-	if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
-	{
-		return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName());
-	}
-
-	return true;
-}
-
-bool handleIgnoredNotification(const LLSD& payload)
-{
-	if (payload["sigtype"].asString() == "add")
-	{
-		LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
-		if (!pNotif) return false;
-
-		LLNotificationFormPtr form = pNotif->getForm();
-		LLSD response;
-		switch(form->getIgnoreType())
-		{
-		case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE:
-			response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
-			break;
-		case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
-			response = LLUI::sSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName());
-			break;
-		case LLNotificationForm::IGNORE_SHOW_AGAIN:
-			break;
-		default:
-			return false;
-		}
-		pNotif->setIgnored(true);
-		pNotif->respond(response);
-		return true; 	// don't process this item any further
-	}
-	return false;
-}
-
-namespace LLNotificationFilters
-{
-	// a sample filter
-	bool includeEverything(LLNotificationPtr p)
-	{
-		return true;
-	}
-};
-
-LLNotificationForm::LLNotificationForm()
-:	mFormData(LLSD::emptyArray()),
-	mIgnore(IGNORE_NO)
-{
-}
-
-
-LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node) 
-:	mFormData(LLSD::emptyArray()),
-	mIgnore(IGNORE_NO)
-{
-	if (!xml_node->hasName("form"))
-	{
-		llwarns << "Bad xml node for form: " << xml_node->getName() << llendl;
-	}
-	LLXMLNodePtr child = xml_node->getFirstChild();
-	while(child)
-	{
-		child = LLNotifications::instance().checkForXMLTemplate(child);
-
-		LLSD item_entry;
-		std::string element_name = child->getName()->mString;
-
-		if (element_name == "ignore" )
-		{
-			bool save_option = false;
-			child->getAttribute_bool("save_option", save_option);
-			if (!save_option)
-			{
-				mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
-			}
-			else
-			{
-				// remember last option chosen by user and automatically respond with that in the future
-				mIgnore = IGNORE_WITH_LAST_RESPONSE;
-				LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
-			}
-			child->getAttributeString("text", mIgnoreMsg);
-			BOOL show_notification = TRUE;
-			LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
-		}
-		else
-		{
-			// flatten xml form entry into single LLSD map with type==name
-			item_entry["type"] = element_name;
-			const LLXMLAttribList::iterator attrib_end = child->mAttributes.end();
-			for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin();
-				attrib_it != attrib_end;
-				++attrib_it)
-			{
-				item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue();
-			}
-			item_entry["value"] = child->getTextContents();
-			mFormData.append(item_entry);
-		}
-
-		child = child->getNextSibling();
-	}
-}
-
-LLNotificationForm::LLNotificationForm(const LLSD& sd)
-{
-	if (sd.isArray())
-	{
-		mFormData = sd;
-	}
-	else
-	{
-		llwarns << "Invalid form data " << sd << llendl;
-		mFormData = LLSD::emptyArray();
-	}
-}
-
-LLSD LLNotificationForm::asLLSD() const
-{ 
-	return mFormData; 
-}
-
-LLSD LLNotificationForm::getElement(const std::string& element_name)
-{
-	for (LLSD::array_const_iterator it = mFormData.beginArray();
-		it != mFormData.endArray();
-		++it)
-	{
-		if ((*it)["name"].asString() == element_name) return (*it);
-	}
-	return LLSD();
-}
-
-
-bool LLNotificationForm::hasElement(const std::string& element_name)
-{
-	for (LLSD::array_const_iterator it = mFormData.beginArray();
-		it != mFormData.endArray();
-		++it)
-	{
-		if ((*it)["name"].asString() == element_name) return true;
-	}
-	return false;
-}
-
-void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value)
-{
-	LLSD element;
-	element["type"] = type;
-	element["name"] = name;
-	element["text"] = name;
-	element["value"] = value;
-	element["index"] = mFormData.size();
-	mFormData.append(element);
-}
-
-void LLNotificationForm::append(const LLSD& sub_form)
-{
-	if (sub_form.isArray())
-	{
-		for (LLSD::array_const_iterator it = sub_form.beginArray();
-			it != sub_form.endArray();
-			++it)
-		{
-			mFormData.append(*it);
-		}
-	}
-}
-
-void LLNotificationForm::formatElements(const LLSD& substitutions)
-{
-	for (LLSD::array_iterator it = mFormData.beginArray();
-		it != mFormData.endArray();
-		++it)
-	{
-		// format "text" component of each form element
-		if ((*it).has("text"))
-		{
-			std::string text = (*it)["text"].asString();
-			LLStringUtil::format(text, substitutions);
-			(*it)["text"] = text;
-		}
-		if ((*it)["type"].asString() == "text" && (*it).has("value"))
-		{
-			std::string value = (*it)["value"].asString();
-			LLStringUtil::format(value, substitutions);
-			(*it)["value"] = value;
-		}
-	}
-}
-
-std::string LLNotificationForm::getDefaultOption()
-{
-	for (LLSD::array_const_iterator it = mFormData.beginArray();
-		it != mFormData.endArray();
-		++it)
-	{
-		if ((*it)["default"]) return (*it)["name"].asString();
-	}
-	return "";
-}
-
-LLNotificationTemplate::LLNotificationTemplate() :
-	mExpireSeconds(0),
-	mExpireOption(-1),
-	mURLOption(-1),
-    mURLOpenExternally(-1),
-	mUnique(false),
-	mPriority(NOTIFICATION_PRIORITY_NORMAL)
-{
-	mForm = LLNotificationFormPtr(new LLNotificationForm()); 
-}
-
-LLNotification::LLNotification(const LLNotification::Params& p) : 
-	mTimestamp(p.timestamp), 
-	mSubstitutions(p.substitutions),
-	mPayload(p.payload),
-	mExpiresAt(0),
-	mTemporaryResponder(false),
-	mRespondedTo(false),
-	mPriority(p.priority),
-	mCancelled(false),
-	mIgnored(false)
-{
-	if (p.functor.name.isChosen())
-	{
-		mResponseFunctorName = p.functor.name;
-	}
-	else if (p.functor.function.isChosen())
-	{
-		mResponseFunctorName = LLUUID::generateNewID().asString();
-		LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function());
-
-		mTemporaryResponder = true;
-	}
-
-	mId.generate();
-	init(p.name, p.form_elements);
-}
-
-
-LLNotification::LLNotification(const LLSD& sd) :
-	mTemporaryResponder(false),
-	mRespondedTo(false),
-	mCancelled(false),
-	mIgnored(false)
-{ 
-	mId.generate();
-	mSubstitutions = sd["substitutions"];
-	mPayload = sd["payload"]; 
-	mTimestamp = sd["time"]; 
-	mExpiresAt = sd["expiry"];
-	mPriority = (ENotificationPriority)sd["priority"].asInteger();
-	mResponseFunctorName = sd["responseFunctor"].asString();
-	std::string templatename = sd["name"].asString();
-	init(templatename, LLSD());
-	// replace form with serialized version
-	mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"]));
-}
-
-
-LLSD LLNotification::asLLSD()
-{
-	LLSD output;
-	output["name"] = mTemplatep->mName;
-	output["form"] = getForm()->asLLSD();
-	output["substitutions"] = mSubstitutions;
-	output["payload"] = mPayload;
-	output["time"] = mTimestamp;
-	output["expiry"] = mExpiresAt;
-	output["priority"] = (S32)mPriority;
-	output["responseFunctor"] = mResponseFunctorName;
-	return output;
-}
-
-void LLNotification::update()
-{
-	LLNotifications::instance().update(shared_from_this());
-}
-
-void LLNotification::updateFrom(LLNotificationPtr other)
-{
-	// can only update from the same notification type
-	if (mTemplatep != other->mTemplatep) return;
-
-	// NOTE: do NOT change the ID, since it is the key to
-	// this given instance, just update all the metadata
-	//mId = other->mId;
-
-	mPayload = other->mPayload;
-	mSubstitutions = other->mSubstitutions;
-	mTimestamp = other->mTimestamp;
-	mExpiresAt = other->mExpiresAt;
-	mCancelled = other->mCancelled;
-	mIgnored = other->mIgnored;
-	mPriority = other->mPriority;
-	mForm = other->mForm;
-	mResponseFunctorName = other->mResponseFunctorName;
-	mRespondedTo = other->mRespondedTo;
-	mTemporaryResponder = other->mTemporaryResponder;
-
-	update();
-}
-
-const LLNotificationFormPtr LLNotification::getForm()
-{
-	return mForm;
-}
-
-void LLNotification::cancel()
-{
-	mCancelled = true;
-}
-
-LLSD LLNotification::getResponseTemplate(EResponseTemplateType type)
-{
-	LLSD response = LLSD::emptyMap();
-	for (S32 element_idx = 0;
-		element_idx < mForm->getNumElements();
-		++element_idx)
-	{
-		LLSD element = mForm->getElement(element_idx);
-		if (element.has("name"))
-		{
-			response[element["name"].asString()] = element["value"];
-		}
-
-		if ((type == WITH_DEFAULT_BUTTON) 
-			&& element["default"].asBoolean())
-		{
-			response[element["name"].asString()] = true;
-		}
-	}
-	return response;
-}
-
-//static
-S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response)
-{
-	LLNotificationForm form(notification["form"]);
-
-	for (S32 element_idx = 0;
-		element_idx < form.getNumElements();
-		++element_idx)
-	{
-		LLSD element = form.getElement(element_idx);
-
-		// only look at buttons
-		if (element["type"].asString() == "button" 
-			&& response[element["name"].asString()].asBoolean())
-		{
-			return element["index"].asInteger();
-		}
-	}
-
-	return -1;
-}
-
-//static
-std::string LLNotification::getSelectedOptionName(const LLSD& response)
-{
-	for (LLSD::map_const_iterator response_it = response.beginMap();
-		response_it != response.endMap();
-		++response_it)
-	{
-		if (response_it->second.isBoolean() && response_it->second.asBoolean())
-		{
-			return response_it->first;
-		}
-	}
-	return "";
-}
-
-
-void LLNotification::respond(const LLSD& response)
-{
-	mRespondedTo = true;
-	// look up the functor
-	LLNotificationFunctorRegistry::ResponseFunctor functor = 
-		LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
-	// and then call it
-	functor(asLLSD(), response);
-	
-	if (mTemporaryResponder)
-	{
-		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
-		mResponseFunctorName = "";
-		mTemporaryResponder = false;
-	}
-
-	if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
-	{
-		BOOL show_notification = mIgnored ? FALSE : TRUE;
-		LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification);
-		if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
-		{
-			LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
-		}
-	}
-
-	update();
-}
-
-void LLNotification::setIgnored(bool ignore)
-{
-	mIgnored = ignore;
-}
-
-void LLNotification::setResponseFunctor(std::string const &responseFunctorName)
-{
-	if (mTemporaryResponder)
-		// get rid of the old one
-		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
-	mResponseFunctorName = responseFunctorName;
-	mTemporaryResponder = false;
-}
-
-bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
-{
-	for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); 
-		required_fields_it != required_fields.end();
-		required_fields_it++)
-	{
-		std::string required_field_name = *required_fields_it;
-		if( ! getPayload().has(required_field_name))
-		{
-			return false; // a required field was not found
-		}
-	}
-	return true; // all required fields were found
-}
-
-bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
-{
-	if (this->mTemplatep->mName != that->mTemplatep->mName) 
-	{
-		return false; // must have the same template name or forget it
-	}
-	if (this->mTemplatep->mUnique)
-	{
-		// highlander bit sez there can only be one of these
-		return
-			this->payloadContainsAll(that->mTemplatep->mUniqueContext) &&
-			that->payloadContainsAll(this->mTemplatep->mUniqueContext);
-	}
-	return false; 
-}
-
-void LLNotification::init(const std::string& template_name, const LLSD& form_elements)
-{
-	mTemplatep = LLNotifications::instance().getTemplate(template_name);
-	if (!mTemplatep) return;
-
-	// add default substitutions
-	const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs();
-	for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin();
-		 iter != default_args.end(); ++iter)
-	{
-		mSubstitutions[iter->first] = iter->second;
-	}
-	mSubstitutions["_URL"] = getURL();
-	mSubstitutions["_NAME"] = template_name;
-	// TODO: something like this so that a missing alert is sensible:
-	//mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions);
-
-	mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm));
-	mForm->append(form_elements);
-
-	// apply substitution to form labels
-	mForm->formatElements(mSubstitutions);
-
-	LLDate rightnow = LLDate::now();
-	if (mTemplatep->mExpireSeconds)
-	{
-		mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds);
-	}
-
-	if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED)
-	{
-		mPriority = mTemplatep->mPriority;
-	}
-}
-
-std::string LLNotification::summarize() const
-{
-	std::string s = "Notification(";
-	s += getName();
-	s += ") : ";
-	s += mTemplatep ? mTemplatep->mMessage : "";
-	// should also include timestamp and expiration time (but probably not payload)
-	return s;
-}
-
-std::string LLNotification::getMessage() const
-{
-	// all our callers cache this result, so it gives us more flexibility
-	// to do the substitution at call time rather than attempting to 
-	// cache it in the notification
-	if (!mTemplatep)
-		return std::string();
-
-	std::string message = mTemplatep->mMessage;
-	LLStringUtil::format(message, mSubstitutions);
-	return message;
-}
-
-std::string LLNotification::getLabel() const
-{
-	std::string label = mTemplatep->mLabel;
-	LLStringUtil::format(label, mSubstitutions);
-	return (mTemplatep ? label : "");
-}
-
-std::string LLNotification::getURL() const
-{
-	if (!mTemplatep)
-		return std::string();
-	std::string url = mTemplatep->mURL;
-	LLStringUtil::format(url, mSubstitutions);
-	return (mTemplatep ? url : "");
-}
-
-// =========================================================
-// LLNotificationChannel implementation
-// ---
-LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListener& slot)
-{
-	// when someone wants to connect to a channel, we first throw them
-	// all of the notifications that are already in the channel
-	// we use a special signal called "load" in case the channel wants to care
-	// only about new notifications
-	for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
-	{
-		slot(LLSD().insert("sigtype", "load").insert("id", (*it)->id()));
-	}
-	// and then connect the signal so that all future notifications will also be
-	// forwarded.
-	return mChanged.connect(slot);
-}
-
-LLBoundListener LLNotificationChannelBase::connectPassedFilterImpl(const LLEventListener& slot)
-{
-	// these two filters only fire for notifications added after the current one, because
-	// they don't participate in the hierarchy.
-	return mPassedFilter.connect(slot);
-}
-
-LLBoundListener LLNotificationChannelBase::connectFailedFilterImpl(const LLEventListener& slot)
-{
-	return mFailedFilter.connect(slot);
-}
-
-// external call, conforms to our standard signature
-bool LLNotificationChannelBase::updateItem(const LLSD& payload)
-{	
-	// first check to see if it's in the master list
-	LLNotificationPtr pNotification	 = LLNotifications::instance().find(payload["id"]);
-	if (!pNotification)
-		return false;	// not found
-	
-	return updateItem(payload, pNotification);
-}
-
-
-//FIX QUIT NOT WORKING
-
-
-// internal call, for use in avoiding lookup
-bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification)
-{	
-	std::string cmd = payload["sigtype"];
-	LLNotificationSet::iterator foundItem = mItems.find(pNotification);
-	bool wasFound = (foundItem != mItems.end());
-	bool passesFilter = mFilter(pNotification);
-	
-	// first, we offer the result of the filter test to the simple
-	// signals for pass/fail. One of these is guaranteed to be called.
-	// If either signal returns true, the change processing is NOT performed
-	// (so don't return true unless you know what you're doing!)
-	bool abortProcessing = false;
-	if (passesFilter)
-	{
-		abortProcessing = mPassedFilter(payload);
-	}
-	else
-	{
-		abortProcessing = mFailedFilter(payload);
-	}
-	
-	if (abortProcessing)
-	{
-		return true;
-	}
-	
-	if (cmd == "load")
-	{
-		// should be no reason we'd ever get a load if we already have it
-		// if passes filter send a load message, else do nothing
-		assert(!wasFound);
-		if (passesFilter)
-		{
-			// not in our list, add it and say so
-			mItems.insert(pNotification);
-			abortProcessing = mChanged(payload);
-			onLoad(pNotification);
-		}
-	}
-	else if (cmd == "change")
-	{
-		// if it passes filter now and was found, we just send a change message
-		// if it passes filter now and wasn't found, we have to add it
-		// if it doesn't pass filter and wasn't found, we do nothing
-		// if it doesn't pass filter and was found, we need to delete it
-		if (passesFilter)
-		{
-			if (wasFound)
-			{
-				// it already existed, so this is a change
-				// since it changed in place, all we have to do is resend the signal
-				abortProcessing = mChanged(payload);
-				onChange(pNotification);
-			}
-			else
-			{
-				// not in our list, add it and say so
-				mItems.insert(pNotification);
-				// our payload is const, so make a copy before changing it
-				LLSD newpayload = payload;
-				newpayload["sigtype"] = "add";
-				abortProcessing = mChanged(newpayload);
-				onChange(pNotification);
-			}
-		}
-		else
-		{
-			if (wasFound)
-			{
-				// it already existed, so this is a delete
-				mItems.erase(pNotification);
-				// our payload is const, so make a copy before changing it
-				LLSD newpayload = payload;
-				newpayload["sigtype"] = "delete";
-				abortProcessing = mChanged(newpayload);
-				onChange(pNotification);
-			}
-			// didn't pass, not on our list, do nothing
-		}
-	}
-	else if (cmd == "add")
-	{
-		// should be no reason we'd ever get an add if we already have it
-		// if passes filter send an add message, else do nothing
-		assert(!wasFound);
-		if (passesFilter)
-		{
-			// not in our list, add it and say so
-			mItems.insert(pNotification);
-			abortProcessing = mChanged(payload);
-			onAdd(pNotification);
-		}
-	}
-	else if (cmd == "delete")
-	{
-		// if we have it in our list, pass on the delete, then delete it, else do nothing
-		if (wasFound)
-		{
-			abortProcessing = mChanged(payload);
-			mItems.erase(pNotification);
-			onDelete(pNotification);
-		}
-	}
-	return abortProcessing;
-}
-
-/* static */
-LLNotificationChannelPtr LLNotificationChannel::buildChannel(const std::string& name, 
-															 const std::string& parent,
-															 LLNotificationFilter filter, 
-															 LLNotificationComparator comparator)
-{
-	// note: this is not a leak; notifications are self-registering.
-	// This factory helps to prevent excess deletions by making sure all smart
-	// pointers to notification channels come from the same source
-	new LLNotificationChannel(name, parent, filter, comparator);
-	return LLNotifications::instance().getChannel(name);
-}
-
-
-LLNotificationChannel::LLNotificationChannel(const std::string& name, 
-											 const std::string& parent,
-											 LLNotificationFilter filter, 
-											 LLNotificationComparator comparator) : 
-LLNotificationChannelBase(filter, comparator),
-mName(name),
-mParent(parent)
-{
-	// store myself in the channel map
-	LLNotifications::instance().addChannel(LLNotificationChannelPtr(this));
-	// bind to notification broadcast
-	if (parent.empty())
-	{
-		LLNotifications::instance().connectChanged(
-			boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
-	}
-	else
-	{
-		LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent);
-		p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
-	}
-}
-
-
-void LLNotificationChannel::setComparator(LLNotificationComparator comparator) 
-{ 
-	mComparator = comparator; 
-	LLNotificationSet s2(mComparator);
-	s2.insert(mItems.begin(), mItems.end());
-	mItems.swap(s2);
-	
-	// notify clients that we've been resorted
-	mChanged(LLSD().insert("sigtype", "sort")); 
-}
-
-bool LLNotificationChannel::isEmpty() const
-{
-	return mItems.empty();
-}
-
-LLNotificationChannel::Iterator LLNotificationChannel::begin()
-{
-	return mItems.begin();
-}
-
-LLNotificationChannel::Iterator LLNotificationChannel::end()
-{
-	return mItems.end();
-}
-
-std::string LLNotificationChannel::summarize()
-{
-	std::string s("Channel '");
-	s += mName;
-	s += "'\n  ";
-	for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it)
-	{
-		s += (*it)->summarize();
-		s += "\n  ";
-	}
-	return s;
-}
-
-
-// ---
-// END OF LLNotificationChannel implementation
-// =========================================================
-
-
-// =========================================================
-// LLNotifications implementation
-// ---
-LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
-															   LLNotificationComparators::orderByUUID()),
-									mIgnoreAllNotifications(false)
-{
-	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
-}
-
-
-// The expiration channel gets all notifications that are cancelled
-bool LLNotifications::expirationFilter(LLNotificationPtr pNotification)
-{
-	return pNotification->isCancelled() || pNotification->isRespondedTo();
-}
-
-bool LLNotifications::expirationHandler(const LLSD& payload)
-{
-	if (payload["sigtype"].asString() != "delete")
-	{
-		// anything added to this channel actually should be deleted from the master
-		cancel(find(payload["id"]));
-		return true;	// don't process this item any further
-	}
-	return false;
-}
-
-bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
-{
-	if (!pNotif->hasUniquenessConstraints())
-	{
-		return true;
-	}
-
-	// checks against existing unique notifications
-	for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
-		existing_it != mUniqueNotifications.end();
-		++existing_it)
-	{
-		LLNotificationPtr existing_notification = existing_it->second;
-		if (pNotif != existing_notification 
-			&& pNotif->isEquivalentTo(existing_notification))
-		{
-			return false;
-		}
-	}
-
-	return true;
-}
-
-bool LLNotifications::uniqueHandler(const LLSD& payload)
-{
-	LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
-	if (pNotif && pNotif->hasUniquenessConstraints()) 
-	{
-		if (payload["sigtype"].asString() == "add")
-		{
-			// not a duplicate according to uniqueness criteria, so we keep it
-			// and store it for future uniqueness checks
-			mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
-		}
-		else if (payload["sigtype"].asString() == "delete")
-		{
-			mUniqueNotifications.erase(pNotif->getName());
-		}
-	}
-
-	return false;
-}
-
-bool LLNotifications::failedUniquenessTest(const LLSD& payload)
-{
-	LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
-	
-	if (!pNotif || !pNotif->hasUniquenessConstraints())
-	{
-		return false;
-	}
-
-	// checks against existing unique notifications
-	for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
-		existing_it != mUniqueNotifications.end();
-		++existing_it)
-	{
-		LLNotificationPtr existing_notification = existing_it->second;
-		if (pNotif != existing_notification 
-			&& pNotif->isEquivalentTo(existing_notification))
-		{
-			// copy notification instance data over to oldest instance
-			// of this unique notification and update it
-			existing_notification->updateFrom(pNotif);
-			// then delete the new one
-			pNotif->cancel();
-		}
-	}
-
-	return false;
-}
-
-
-void LLNotifications::addChannel(LLNotificationChannelPtr pChan)
-{
-	mChannels[pChan->getName()] = pChan;
-}
-
-LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName)
-{
-	ChannelMap::iterator p = mChannels.find(channelName);
-	if(p == mChannels.end())
-	{
-		llerrs << "Did not find channel named " << channelName << llendl;
-	}
-	return p->second;
-}
-
-
-// this function is called once at construction time, after the object is constructed.
-void LLNotifications::initSingleton()
-{
-	loadTemplates();
-	createDefaultChannels();
-}
-
-void LLNotifications::createDefaultChannels()
-{
-	// now construct the various channels AFTER loading the notifications,
-	// because the history channel is going to rewrite the stored notifications file
-	LLNotificationChannel::buildChannel("Expiration", "",
-		boost::bind(&LLNotifications::expirationFilter, this, _1));
-	LLNotificationChannel::buildChannel("Unexpired", "",
-		!boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
-	LLNotificationChannel::buildChannel("Unique", "Unexpired",
-		boost::bind(&LLNotifications::uniqueFilter, this, _1));
-	LLNotificationChannel::buildChannel("Ignore", "Unique",
-		filterIgnoredNotifications);
-	LLNotificationChannel::buildChannel("Visible", "Ignore",
-		&LLNotificationFilters::includeEverything);
-
-	// create special history channel
-	//std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
-	// use ^^^ when done debugging notifications serialization
-	std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" );
-	// this isn't a leak, don't worry about the empty "new"
-	new LLNotificationHistoryChannel(notifications_log_file);
-
-	// connect action methods to these channels
-	LLNotifications::instance().getChannel("Expiration")->
-        connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
-	LLNotifications::instance().getChannel("Unique")->
-        connectChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
-	LLNotifications::instance().getChannel("Unique")->
-        connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
-	LLNotifications::instance().getChannel("Ignore")->
-		connectFailedFilter(&handleIgnoredNotification);
-}
-
-bool LLNotifications::addTemplate(const std::string &name, 
-								  LLNotificationTemplatePtr theTemplate)
-{
-	if (mTemplates.count(name))
-	{
-		llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl;
-		return false;
-	}
-	mTemplates[name] = theTemplate;
-	return true;
-}
-
-LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name)
-{
-	if (mTemplates.count(name))
-	{
-		return mTemplates[name];
-	}
-	else
-	{
-		return mTemplates["MissingAlert"];
-	}
-}
-
-bool LLNotifications::templateExists(const std::string& name)
-{
-	return (mTemplates.count(name) != 0);
-}
-
-void LLNotifications::clearTemplates()
-{
-	mTemplates.clear();
-}
-
-void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
-{
-	LLNotificationPtr temp_notify(new LLNotification(params));
-	LLSD response = temp_notify->getResponseTemplate();
-	LLSD selected_item = temp_notify->getForm()->getElement(option);
-	
-	if (selected_item.isUndefined())
-	{
-		llwarns << "Invalid option" << option << " for notification " << (std::string)params.name << llendl;
-		return;
-	}
-	response[selected_item["name"].asString()] = true;
-
-	temp_notify->respond(response);
-}
-
-LLNotifications::TemplateNames LLNotifications::getTemplateNames() const
-{
-	TemplateNames names;
-	for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it)
-	{
-		names.push_back(it->first);
-	}
-	return names;
-}
-
-typedef std::map<std::string, std::string> StringMap;
-void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
-{
-	//llwarns << "replaceSubstitutionStrings" << llendl;
-	// walk the list of attributes looking for replacements
-	for (LLXMLAttribList::iterator it=node->mAttributes.begin();
-		 it != node->mAttributes.end(); ++it)
-	{
-		std::string value = it->second->getValue();
-		if (value[0] == '$')
-		{
-			value.erase(0, 1);	// trim off the $
-			std::string replacement;
-			StringMap::const_iterator found = replacements.find(value);
-			if (found != replacements.end())
-			{
-				replacement = found->second;
-				//llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
-
-				it->second->setValue(replacement);
-			}
-			else
-			{
-				llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
-			}
-		}
-	}
-	
-	// now walk the list of children and call this recursively.
-	for (LLXMLNodePtr child = node->getFirstChild(); 
-		 child.notNull(); child = child->getNextSibling())
-	{
-		replaceSubstitutionStrings(child, replacements);
-	}
-}
-
-// private to this file
-// returns true if the template request was invalid and there's nothing else we
-// can do with this node, false if you should keep processing (it may have
-// replaced the contents of the node referred to)
-LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item)
-{
-	if (item->hasName("usetemplate"))
-	{
-		std::string replacementName;
-		if (item->getAttributeString("name", replacementName))
-		{
-			StringMap replacements;
-			for (LLXMLAttribList::const_iterator it=item->mAttributes.begin(); 
-				 it != item->mAttributes.end(); ++it)
-			{
-				replacements[it->second->getName()->mString] = it->second->getValue();
-			}
-			if (mXmlTemplates.count(replacementName))
-			{
-				item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]);
-				
-				// walk the nodes looking for $(substitution) here and replace
-				replaceSubstitutionStrings(item, replacements);
-			}
-			else
-			{
-				llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl;
-			}
-		}
-	}
-	return item;
-}
-
-bool LLNotifications::loadTemplates()
-{
-	const std::string xml_filename = "notifications.xml";
-	LLXMLNodePtr root;
-	
-	BOOL success  = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
-	
-	if (!success || root.isNull() || !root->hasName( "notifications" ))
-	{
-		llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl;
-		return false;
-	}
-	
-	clearTemplates();
-	
-	for (LLXMLNodePtr item = root->getFirstChild();
-		 item.notNull(); item = item->getNextSibling())
-	{
-		// we do this FIRST so that item can be changed if we 
-		// encounter a usetemplate -- we just replace the
-		// current xml node and keep processing
-		item = checkForXMLTemplate(item);
-		
-		if (item->hasName("global"))
-		{
-			std::string global_name;
-			if (item->getAttributeString("name", global_name))
-			{
-				mGlobalStrings[global_name] = item->getTextContents();
-			}
-			continue;
-		}
-		
-		if (item->hasName("template"))
-		{
-			// store an xml template; templates must have a single node (can contain
-			// other nodes)
-			std::string name;
-			item->getAttributeString("name", name);
-			LLXMLNodePtr ptr = item->getFirstChild();
-			mXmlTemplates[name] = ptr;
-			continue;
-		}
-		
-		if (!item->hasName("notification"))
-		{
-            llwarns << "Unexpected entity " << item->getName()->mString << 
-                       " found in " << xml_filename << llendl;
-			continue;
-		}
-		
-		// now we know we have a notification entry, so let's build it
-		LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate());
-
-		if (!item->getAttributeString("name", pTemplate->mName))
-		{
-			llwarns << "Unable to parse notification with no name" << llendl;
-			continue;
-		}
-		
-		//llinfos << "Parsing " << pTemplate->mName << llendl;
-		
-		pTemplate->mMessage = item->getTextContents();
-		pTemplate->mDefaultFunctor = pTemplate->mName;
-		item->getAttributeString("type", pTemplate->mType);
-		item->getAttributeString("icon", pTemplate->mIcon);
-		item->getAttributeString("label", pTemplate->mLabel);
-		item->getAttributeU32("duration", pTemplate->mExpireSeconds);
-		item->getAttributeU32("expireOption", pTemplate->mExpireOption);
-
-		std::string priority;
-		item->getAttributeString("priority", priority);
-		pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
-		if (!priority.empty())
-		{
-			if (priority == "low")      pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW;
-			if (priority == "normal")   pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
-			if (priority == "high")     pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH;
-			if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL;
-		}
-		
-		item->getAttributeString("functor", pTemplate->mDefaultFunctor);
-
-		BOOL persist = false;
-		item->getAttributeBOOL("persist", persist);
-		pTemplate->mPersist = persist;
-		
-		std::string sound;
-		item->getAttributeString("sound", sound);
-		if (!sound.empty())
-		{
-			// test for bad sound effect name / missing effect
-			if (LLUI::sSettingGroups["config"]->controlExists(sound))
-			{
-				pTemplate->mSoundEffect = 
-					LLUUID(LLUI::sSettingGroups["config"]->getString(sound));
-			}
-			else
-			{
-				llwarns << "Unknown sound effect control name " << sound
-					<< llendl;
-			}
-		}
-
-		for (LLXMLNodePtr child = item->getFirstChild();
-			 !child.isNull(); child = child->getNextSibling())
-		{
-			child = checkForXMLTemplate(child);
-			
-			// <url>
-			if (child->hasName("url"))
-			{
-				pTemplate->mURL = child->getTextContents();
-				child->getAttributeU32("option", pTemplate->mURLOption);
-				child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
-			}
-			
-            if (child->hasName("unique"))
-            {
-                pTemplate->mUnique = true;
-                for (LLXMLNodePtr formitem = child->getFirstChild();
-                     !formitem.isNull(); formitem = formitem->getNextSibling())
-                {
-                    if (formitem->hasName("context"))
-                    {
-                        std::string key;
-                        formitem->getAttributeString("key", key);
-                        pTemplate->mUniqueContext.push_back(key);
-                        //llwarns << "adding " << key << " to unique context" << llendl;
-                    }
-                    else
-                    {
-                        llwarns << "'unique' has unrecognized subelement " 
-                        << formitem->getName()->mString << llendl;
-                    }
-                }
-            }
-            
-			// <form>
-			if (child->hasName("form"))
-			{
-                pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child));
-			}
-		}
-		addTemplate(pTemplate->mName, pTemplate);
-	}
-	
-	//std::ostringstream ostream;
-	//root->writeToOstream(ostream, "\n  ");
-	//llwarns << ostream.str() << llendl;
-	
-	return true;
-}
-
-// Add a simple notification (from XUI)
-void LLNotifications::addFromCallback(const LLSD& name)
-{
-	add(LLNotification::Params().name(name.asString()));	
-}
-
-// we provide a couple of simple add notification functions so that it's reasonable to create notifications in one line
-LLNotificationPtr LLNotifications::add(const std::string& name, 
-										const LLSD& substitutions, 
-										const LLSD& payload)
-{
-	LLNotification::Params::Functor functor_p;
-	functor_p.name = name;
-	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
-}
-
-LLNotificationPtr LLNotifications::add(const std::string& name, 
-										const LLSD& substitutions, 
-										const LLSD& payload, 
-										const std::string& functor_name)
-{
-	LLNotification::Params::Functor functor_p;
-	functor_p.name = functor_name;
-	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
-}
-
-LLNotificationPtr LLNotifications::add(const std::string& name, 
-										const LLSD& substitutions, 
-										const LLSD& payload, 
-										LLNotificationFunctorRegistry::ResponseFunctor functor)
-{
-	LLNotification::Params::Functor functor_p;
-	functor_p.function = functor;
-	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
-}
-
-// generalized add function that takes a parameter block object for more complex instantiations
-LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
-{
-	LLNotificationPtr pNotif(new LLNotification(p));
-	add(pNotif);
-	return pNotif;
-}
-
-
-void LLNotifications::add(const LLNotificationPtr pNotif)
-{
-	// first see if we already have it -- if so, that's a problem
-	LLNotificationSet::iterator it=mItems.find(pNotif);
-	if (it != mItems.end())
-	{
-		llerrs << "Notification added a second time to the master notification channel." << llendl;
-	}
-
-	updateItem(LLSD().insert("sigtype", "add").insert("id", pNotif->id()), pNotif);
-}
-
-void LLNotifications::cancel(LLNotificationPtr pNotif)
-{
-	LLNotificationSet::iterator it=mItems.find(pNotif);
-	if (it == mItems.end())
-	{
-		llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl;
-	}
-	updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif);
-	pNotif->cancel();
-}
-
-void LLNotifications::update(const LLNotificationPtr pNotif)
-{
-	LLNotificationSet::iterator it=mItems.find(pNotif);
-	if (it != mItems.end())
-	{
-		updateItem(LLSD().insert("sigtype", "change").insert("id", pNotif->id()), pNotif);
-	}
-}
-
-
-LLNotificationPtr LLNotifications::find(LLUUID uuid)
-{
-	LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid));
-	LLNotificationSet::iterator it=mItems.find(target);
-	if (it == mItems.end())
-	{
-		llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl;
-		return LLNotificationPtr((LLNotification*)NULL);
-	}
-	else
-	{
-		return *it;
-	}
-}
-
-void LLNotifications::forEachNotification(NotificationProcess process)
-{
-	std::for_each(mItems.begin(), mItems.end(), process);
-}
-
-std::string LLNotifications::getGlobalString(const std::string& key) const
-{
-	GlobalStringMap::const_iterator it = mGlobalStrings.find(key);
-	if (it != mGlobalStrings.end())
-	{
-		return it->second;
-	}
-	else
-	{
-		// if we don't have the key as a global, return the key itself so that the error
-		// is self-diagnosing.
-		return key;
-	}
-}
-
-void LLNotifications::setIgnoreAllNotifications(bool setting)
-{
-	mIgnoreAllNotifications = setting; 
-}
-bool LLNotifications::getIgnoreAllNotifications()
-{
-	return mIgnoreAllNotifications; 
-}
-													
-// ---
-// END OF LLNotifications implementation
-// =========================================================
-
-std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
-{
-	s << notification.summarize();
-	return s;
-}
-
+/**
+* @file llnotifications.cpp
+* @brief Non-UI queue manager for keeping a prioritized list of notifications
+*
+* $LicenseInfo:firstyear=2008&license=viewergpl$
+* 
+* Copyright (c) 2008-2009, Linden Research, Inc.
+* 
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab.  Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+* 
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+* 
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+* 
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#include "linden_common.h"
+
+#include "llnotifications.h"
+
+#include "lluictrl.h"
+#include "lluictrlfactory.h"
+#include "lldir.h"
+#include "llsdserialize.h"
+#include "lltrans.h"
+#include "llnotificationslistener.h"
+
+#include <algorithm>
+#include <boost/regex.hpp>
+
+
+const std::string NOTIFICATION_PERSIST_VERSION = "0.93";
+
+// local channel for notification history
+class LLNotificationHistoryChannel : public LLNotificationChannel
+{
+	LOG_CLASS(LLNotificationHistoryChannel);
+public:
+	LLNotificationHistoryChannel(const std::string& filename) : 
+		LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()),
+		mFileName(filename)
+	{
+		connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1));
+		loadPersistentNotifications();
+	}
+
+private:
+	bool historyHandler(const LLSD& payload)
+	{
+		// we ignore "load" messages, but rewrite the persistence file on any other
+		std::string sigtype = payload["sigtype"];
+		if (sigtype != "load")
+		{
+			savePersistentNotifications();
+		}
+		return false;
+	}
+
+	// The history channel gets all notifications except those that have been cancelled
+	static bool historyFilter(LLNotificationPtr pNotification)
+	{
+		return !pNotification->isCancelled();
+	}
+
+	void savePersistentNotifications()
+	{
+		llinfos << "Saving open notifications to " << mFileName << llendl;
+
+		llofstream notify_file(mFileName.c_str());
+		if (!notify_file.is_open()) 
+		{
+			llwarns << "Failed to open " << mFileName << llendl;
+			return;
+		}
+
+		LLSD output;
+		output["version"] = NOTIFICATION_PERSIST_VERSION;
+		LLSD& data = output["data"];
+
+		for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
+		{
+			if (!LLNotifications::instance().templateExists((*it)->getName())) continue;
+
+			// only store notifications flagged as persisting
+			LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName());
+			if (!templatep->mPersist) continue;
+
+			data.append((*it)->asLLSD());
+		}
+
+		LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+		formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY);
+	}
+
+	void loadPersistentNotifications()
+	{
+		llinfos << "Loading open notifications from " << mFileName << llendl;
+
+		llifstream notify_file(mFileName.c_str());
+		if (!notify_file.is_open()) 
+		{
+			llwarns << "Failed to open " << mFileName << llendl;
+			return;
+		}
+
+		LLSD input;
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+		if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0)
+		{
+			llwarns << "Failed to parse open notifications" << llendl;
+			return;
+		}
+
+		if (input.isUndefined()) return;
+		std::string version = input["version"];
+		if (version != NOTIFICATION_PERSIST_VERSION)
+		{
+			llwarns << "Bad open notifications version: " << version << llendl;
+			return;
+		}
+		LLSD& data = input["data"];
+		if (data.isUndefined()) return;
+
+		LLNotifications& instance = LLNotifications::instance();
+		for (LLSD::array_const_iterator notification_it = data.beginArray();
+			notification_it != data.endArray();
+			++notification_it)
+		{
+			instance.add(LLNotificationPtr(new LLNotification(*notification_it)));
+		}
+	}
+
+	//virtual
+	void onDelete(LLNotificationPtr pNotification)
+	{
+		// we want to keep deleted notifications in our log
+		mItems.insert(pNotification);
+		
+		return;
+	}
+	
+private:
+	std::string mFileName;
+};
+
+bool filterIgnoredNotifications(LLNotificationPtr notification)
+{
+	// filter everything if we are to ignore ALL
+	if(LLNotifications::instance().getIgnoreAllNotifications())
+	{
+		return false;
+	}
+
+	LLNotificationFormPtr form = notification->getForm();
+	// Check to see if the user wants to ignore this alert
+	if (form->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+	{
+		return LLUI::sSettingGroups["ignores"]->getBOOL(notification->getName());
+	}
+
+	return true;
+}
+
+bool handleIgnoredNotification(const LLSD& payload)
+{
+	if (payload["sigtype"].asString() == "add")
+	{
+		LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
+		if (!pNotif) return false;
+
+		LLNotificationFormPtr form = pNotif->getForm();
+		LLSD response;
+		switch(form->getIgnoreType())
+		{
+		case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE:
+			response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
+			break;
+		case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
+			response = LLUI::sSettingGroups["ignores"]->getLLSD("Default" + pNotif->getName());
+			break;
+		case LLNotificationForm::IGNORE_SHOW_AGAIN:
+			break;
+		default:
+			return false;
+		}
+		pNotif->setIgnored(true);
+		pNotif->respond(response);
+		return true; 	// don't process this item any further
+	}
+	return false;
+}
+
+namespace LLNotificationFilters
+{
+	// a sample filter
+	bool includeEverything(LLNotificationPtr p)
+	{
+		return true;
+	}
+};
+
+LLNotificationForm::LLNotificationForm()
+:	mFormData(LLSD::emptyArray()),
+	mIgnore(IGNORE_NO)
+{
+}
+
+
+LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node) 
+:	mFormData(LLSD::emptyArray()),
+	mIgnore(IGNORE_NO)
+{
+	if (!xml_node->hasName("form"))
+	{
+		llwarns << "Bad xml node for form: " << xml_node->getName() << llendl;
+	}
+	LLXMLNodePtr child = xml_node->getFirstChild();
+	while(child)
+	{
+		child = LLNotifications::instance().checkForXMLTemplate(child);
+
+		LLSD item_entry;
+		std::string element_name = child->getName()->mString;
+
+		if (element_name == "ignore" )
+		{
+			bool save_option = false;
+			child->getAttribute_bool("save_option", save_option);
+			if (!save_option)
+			{
+				mIgnore = IGNORE_WITH_DEFAULT_RESPONSE;
+			}
+			else
+			{
+				// remember last option chosen by user and automatically respond with that in the future
+				mIgnore = IGNORE_WITH_LAST_RESPONSE;
+				LLUI::sSettingGroups["ignores"]->declareLLSD(std::string("Default") + name, "", std::string("Default response for notification " + name));
+			}
+			child->getAttributeString("text", mIgnoreMsg);
+			BOOL show_notification = TRUE;
+			LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Ignore notification with this name", TRUE);
+		}
+		else
+		{
+			// flatten xml form entry into single LLSD map with type==name
+			item_entry["type"] = element_name;
+			const LLXMLAttribList::iterator attrib_end = child->mAttributes.end();
+			for(LLXMLAttribList::iterator attrib_it = child->mAttributes.begin();
+				attrib_it != attrib_end;
+				++attrib_it)
+			{
+				item_entry[std::string(attrib_it->second->getName()->mString)] = attrib_it->second->getValue();
+			}
+			item_entry["value"] = child->getTextContents();
+			mFormData.append(item_entry);
+		}
+
+		child = child->getNextSibling();
+	}
+}
+
+LLNotificationForm::LLNotificationForm(const LLSD& sd)
+{
+	if (sd.isArray())
+	{
+		mFormData = sd;
+	}
+	else
+	{
+		llwarns << "Invalid form data " << sd << llendl;
+		mFormData = LLSD::emptyArray();
+	}
+}
+
+LLSD LLNotificationForm::asLLSD() const
+{ 
+	return mFormData; 
+}
+
+LLSD LLNotificationForm::getElement(const std::string& element_name)
+{
+	for (LLSD::array_const_iterator it = mFormData.beginArray();
+		it != mFormData.endArray();
+		++it)
+	{
+		if ((*it)["name"].asString() == element_name) return (*it);
+	}
+	return LLSD();
+}
+
+
+bool LLNotificationForm::hasElement(const std::string& element_name)
+{
+	for (LLSD::array_const_iterator it = mFormData.beginArray();
+		it != mFormData.endArray();
+		++it)
+	{
+		if ((*it)["name"].asString() == element_name) return true;
+	}
+	return false;
+}
+
+void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value)
+{
+	LLSD element;
+	element["type"] = type;
+	element["name"] = name;
+	element["text"] = name;
+	element["value"] = value;
+	element["index"] = mFormData.size();
+	mFormData.append(element);
+}
+
+void LLNotificationForm::append(const LLSD& sub_form)
+{
+	if (sub_form.isArray())
+	{
+		for (LLSD::array_const_iterator it = sub_form.beginArray();
+			it != sub_form.endArray();
+			++it)
+		{
+			mFormData.append(*it);
+		}
+	}
+}
+
+void LLNotificationForm::formatElements(const LLSD& substitutions)
+{
+	for (LLSD::array_iterator it = mFormData.beginArray();
+		it != mFormData.endArray();
+		++it)
+	{
+		// format "text" component of each form element
+		if ((*it).has("text"))
+		{
+			std::string text = (*it)["text"].asString();
+			LLStringUtil::format(text, substitutions);
+			(*it)["text"] = text;
+		}
+		if ((*it)["type"].asString() == "text" && (*it).has("value"))
+		{
+			std::string value = (*it)["value"].asString();
+			LLStringUtil::format(value, substitutions);
+			(*it)["value"] = value;
+		}
+	}
+}
+
+std::string LLNotificationForm::getDefaultOption()
+{
+	for (LLSD::array_const_iterator it = mFormData.beginArray();
+		it != mFormData.endArray();
+		++it)
+	{
+		if ((*it)["default"]) return (*it)["name"].asString();
+	}
+	return "";
+}
+
+LLNotificationTemplate::LLNotificationTemplate() :
+	mExpireSeconds(0),
+	mExpireOption(-1),
+	mURLOption(-1),
+    mURLOpenExternally(-1),
+	mUnique(false),
+	mPriority(NOTIFICATION_PRIORITY_NORMAL)
+{
+	mForm = LLNotificationFormPtr(new LLNotificationForm()); 
+}
+
+LLNotification::LLNotification(const LLNotification::Params& p) : 
+	mTimestamp(p.timestamp), 
+	mSubstitutions(p.substitutions),
+	mPayload(p.payload),
+	mExpiresAt(0),
+	mTemporaryResponder(false),
+	mRespondedTo(false),
+	mPriority(p.priority),
+	mCancelled(false),
+	mIgnored(false)
+{
+	if (p.functor.name.isChosen())
+	{
+		mResponseFunctorName = p.functor.name;
+	}
+	else if (p.functor.function.isChosen())
+	{
+		mResponseFunctorName = LLUUID::generateNewID().asString();
+		LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, p.functor.function());
+
+		mTemporaryResponder = true;
+	}
+
+	mId.generate();
+	init(p.name, p.form_elements);
+}
+
+
+LLNotification::LLNotification(const LLSD& sd) :
+	mTemporaryResponder(false),
+	mRespondedTo(false),
+	mCancelled(false),
+	mIgnored(false)
+{ 
+	mId.generate();
+	mSubstitutions = sd["substitutions"];
+	mPayload = sd["payload"]; 
+	mTimestamp = sd["time"]; 
+	mExpiresAt = sd["expiry"];
+	mPriority = (ENotificationPriority)sd["priority"].asInteger();
+	mResponseFunctorName = sd["responseFunctor"].asString();
+	std::string templatename = sd["name"].asString();
+	init(templatename, LLSD());
+	// replace form with serialized version
+	mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"]));
+}
+
+
+LLSD LLNotification::asLLSD()
+{
+	LLSD output;
+	output["name"] = mTemplatep->mName;
+	output["form"] = getForm()->asLLSD();
+	output["substitutions"] = mSubstitutions;
+	output["payload"] = mPayload;
+	output["time"] = mTimestamp;
+	output["expiry"] = mExpiresAt;
+	output["priority"] = (S32)mPriority;
+	output["responseFunctor"] = mResponseFunctorName;
+	return output;
+}
+
+void LLNotification::update()
+{
+	LLNotifications::instance().update(shared_from_this());
+}
+
+void LLNotification::updateFrom(LLNotificationPtr other)
+{
+	// can only update from the same notification type
+	if (mTemplatep != other->mTemplatep) return;
+
+	// NOTE: do NOT change the ID, since it is the key to
+	// this given instance, just update all the metadata
+	//mId = other->mId;
+
+	mPayload = other->mPayload;
+	mSubstitutions = other->mSubstitutions;
+	mTimestamp = other->mTimestamp;
+	mExpiresAt = other->mExpiresAt;
+	mCancelled = other->mCancelled;
+	mIgnored = other->mIgnored;
+	mPriority = other->mPriority;
+	mForm = other->mForm;
+	mResponseFunctorName = other->mResponseFunctorName;
+	mRespondedTo = other->mRespondedTo;
+	mTemporaryResponder = other->mTemporaryResponder;
+
+	update();
+}
+
+const LLNotificationFormPtr LLNotification::getForm()
+{
+	return mForm;
+}
+
+void LLNotification::cancel()
+{
+	mCancelled = true;
+}
+
+LLSD LLNotification::getResponseTemplate(EResponseTemplateType type)
+{
+	LLSD response = LLSD::emptyMap();
+	for (S32 element_idx = 0;
+		element_idx < mForm->getNumElements();
+		++element_idx)
+	{
+		LLSD element = mForm->getElement(element_idx);
+		if (element.has("name"))
+		{
+			response[element["name"].asString()] = element["value"];
+		}
+
+		if ((type == WITH_DEFAULT_BUTTON) 
+			&& element["default"].asBoolean())
+		{
+			response[element["name"].asString()] = true;
+		}
+	}
+	return response;
+}
+
+//static
+S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response)
+{
+	LLNotificationForm form(notification["form"]);
+
+	for (S32 element_idx = 0;
+		element_idx < form.getNumElements();
+		++element_idx)
+	{
+		LLSD element = form.getElement(element_idx);
+
+		// only look at buttons
+		if (element["type"].asString() == "button" 
+			&& response[element["name"].asString()].asBoolean())
+		{
+			return element["index"].asInteger();
+		}
+	}
+
+	return -1;
+}
+
+//static
+std::string LLNotification::getSelectedOptionName(const LLSD& response)
+{
+	for (LLSD::map_const_iterator response_it = response.beginMap();
+		response_it != response.endMap();
+		++response_it)
+	{
+		if (response_it->second.isBoolean() && response_it->second.asBoolean())
+		{
+			return response_it->first;
+		}
+	}
+	return "";
+}
+
+
+void LLNotification::respond(const LLSD& response)
+{
+	mRespondedTo = true;
+	// look up the functor
+	LLNotificationFunctorRegistry::ResponseFunctor functor = 
+		LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
+	// and then call it
+	functor(asLLSD(), response);
+	
+	if (mTemporaryResponder)
+	{
+		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
+		mResponseFunctorName = "";
+		mTemporaryResponder = false;
+	}
+
+	if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+	{
+		BOOL show_notification = mIgnored ? FALSE : TRUE;
+		LLUI::sSettingGroups["ignores"]->setBOOL(getName(), show_notification);
+		if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
+		{
+			LLUI::sSettingGroups["ignores"]->setLLSD("Default" + getName(), response);
+		}
+	}
+
+	update();
+}
+
+void LLNotification::setIgnored(bool ignore)
+{
+	mIgnored = ignore;
+}
+
+void LLNotification::setResponseFunctor(std::string const &responseFunctorName)
+{
+	if (mTemporaryResponder)
+		// get rid of the old one
+		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
+	mResponseFunctorName = responseFunctorName;
+	mTemporaryResponder = false;
+}
+
+bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
+{
+	for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); 
+		required_fields_it != required_fields.end();
+		required_fields_it++)
+	{
+		std::string required_field_name = *required_fields_it;
+		if( ! getPayload().has(required_field_name))
+		{
+			return false; // a required field was not found
+		}
+	}
+	return true; // all required fields were found
+}
+
+bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
+{
+	if (this->mTemplatep->mName != that->mTemplatep->mName) 
+	{
+		return false; // must have the same template name or forget it
+	}
+	if (this->mTemplatep->mUnique)
+	{
+		// highlander bit sez there can only be one of these
+		return
+			this->payloadContainsAll(that->mTemplatep->mUniqueContext) &&
+			that->payloadContainsAll(this->mTemplatep->mUniqueContext);
+	}
+	return false; 
+}
+
+void LLNotification::init(const std::string& template_name, const LLSD& form_elements)
+{
+	mTemplatep = LLNotifications::instance().getTemplate(template_name);
+	if (!mTemplatep) return;
+
+	// add default substitutions
+	const LLStringUtil::format_map_t& default_args = LLTrans::getDefaultArgs();
+	for (LLStringUtil::format_map_t::const_iterator iter = default_args.begin();
+		 iter != default_args.end(); ++iter)
+	{
+		mSubstitutions[iter->first] = iter->second;
+	}
+	mSubstitutions["_URL"] = getURL();
+	mSubstitutions["_NAME"] = template_name;
+	// TODO: something like this so that a missing alert is sensible:
+	//mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions);
+
+	mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm));
+	mForm->append(form_elements);
+
+	// apply substitution to form labels
+	mForm->formatElements(mSubstitutions);
+
+	LLDate rightnow = LLDate::now();
+	if (mTemplatep->mExpireSeconds)
+	{
+		mExpiresAt = LLDate(rightnow.secondsSinceEpoch() + mTemplatep->mExpireSeconds);
+	}
+
+	if (mPriority == NOTIFICATION_PRIORITY_UNSPECIFIED)
+	{
+		mPriority = mTemplatep->mPriority;
+	}
+}
+
+std::string LLNotification::summarize() const
+{
+	std::string s = "Notification(";
+	s += getName();
+	s += ") : ";
+	s += mTemplatep ? mTemplatep->mMessage : "";
+	// should also include timestamp and expiration time (but probably not payload)
+	return s;
+}
+
+std::string LLNotification::getMessage() const
+{
+	// all our callers cache this result, so it gives us more flexibility
+	// to do the substitution at call time rather than attempting to 
+	// cache it in the notification
+	if (!mTemplatep)
+		return std::string();
+
+	std::string message = mTemplatep->mMessage;
+	LLStringUtil::format(message, mSubstitutions);
+	return message;
+}
+
+std::string LLNotification::getLabel() const
+{
+	std::string label = mTemplatep->mLabel;
+	LLStringUtil::format(label, mSubstitutions);
+	return (mTemplatep ? label : "");
+}
+
+std::string LLNotification::getURL() const
+{
+	if (!mTemplatep)
+		return std::string();
+	std::string url = mTemplatep->mURL;
+	LLStringUtil::format(url, mSubstitutions);
+	return (mTemplatep ? url : "");
+}
+
+// =========================================================
+// LLNotificationChannel implementation
+// ---
+LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListener& slot)
+{
+	// when someone wants to connect to a channel, we first throw them
+	// all of the notifications that are already in the channel
+	// we use a special signal called "load" in case the channel wants to care
+	// only about new notifications
+	for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it)
+	{
+		slot(LLSD().insert("sigtype", "load").insert("id", (*it)->id()));
+	}
+	// and then connect the signal so that all future notifications will also be
+	// forwarded.
+	return mChanged.connect(slot);
+}
+
+LLBoundListener LLNotificationChannelBase::connectPassedFilterImpl(const LLEventListener& slot)
+{
+	// these two filters only fire for notifications added after the current one, because
+	// they don't participate in the hierarchy.
+	return mPassedFilter.connect(slot);
+}
+
+LLBoundListener LLNotificationChannelBase::connectFailedFilterImpl(const LLEventListener& slot)
+{
+	return mFailedFilter.connect(slot);
+}
+
+// external call, conforms to our standard signature
+bool LLNotificationChannelBase::updateItem(const LLSD& payload)
+{	
+	// first check to see if it's in the master list
+	LLNotificationPtr pNotification	 = LLNotifications::instance().find(payload["id"]);
+	if (!pNotification)
+		return false;	// not found
+	
+	return updateItem(payload, pNotification);
+}
+
+
+//FIX QUIT NOT WORKING
+
+
+// internal call, for use in avoiding lookup
+bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification)
+{	
+	std::string cmd = payload["sigtype"];
+	LLNotificationSet::iterator foundItem = mItems.find(pNotification);
+	bool wasFound = (foundItem != mItems.end());
+	bool passesFilter = mFilter(pNotification);
+	
+	// first, we offer the result of the filter test to the simple
+	// signals for pass/fail. One of these is guaranteed to be called.
+	// If either signal returns true, the change processing is NOT performed
+	// (so don't return true unless you know what you're doing!)
+	bool abortProcessing = false;
+	if (passesFilter)
+	{
+		abortProcessing = mPassedFilter(payload);
+	}
+	else
+	{
+		abortProcessing = mFailedFilter(payload);
+	}
+	
+	if (abortProcessing)
+	{
+		return true;
+	}
+	
+	if (cmd == "load")
+	{
+		// should be no reason we'd ever get a load if we already have it
+		// if passes filter send a load message, else do nothing
+		assert(!wasFound);
+		if (passesFilter)
+		{
+			// not in our list, add it and say so
+			mItems.insert(pNotification);
+			abortProcessing = mChanged(payload);
+			onLoad(pNotification);
+		}
+	}
+	else if (cmd == "change")
+	{
+		// if it passes filter now and was found, we just send a change message
+		// if it passes filter now and wasn't found, we have to add it
+		// if it doesn't pass filter and wasn't found, we do nothing
+		// if it doesn't pass filter and was found, we need to delete it
+		if (passesFilter)
+		{
+			if (wasFound)
+			{
+				// it already existed, so this is a change
+				// since it changed in place, all we have to do is resend the signal
+				abortProcessing = mChanged(payload);
+				onChange(pNotification);
+			}
+			else
+			{
+				// not in our list, add it and say so
+				mItems.insert(pNotification);
+				// our payload is const, so make a copy before changing it
+				LLSD newpayload = payload;
+				newpayload["sigtype"] = "add";
+				abortProcessing = mChanged(newpayload);
+				onChange(pNotification);
+			}
+		}
+		else
+		{
+			if (wasFound)
+			{
+				// it already existed, so this is a delete
+				mItems.erase(pNotification);
+				// our payload is const, so make a copy before changing it
+				LLSD newpayload = payload;
+				newpayload["sigtype"] = "delete";
+				abortProcessing = mChanged(newpayload);
+				onChange(pNotification);
+			}
+			// didn't pass, not on our list, do nothing
+		}
+	}
+	else if (cmd == "add")
+	{
+		// should be no reason we'd ever get an add if we already have it
+		// if passes filter send an add message, else do nothing
+		assert(!wasFound);
+		if (passesFilter)
+		{
+			// not in our list, add it and say so
+			mItems.insert(pNotification);
+			abortProcessing = mChanged(payload);
+			onAdd(pNotification);
+		}
+	}
+	else if (cmd == "delete")
+	{
+		// if we have it in our list, pass on the delete, then delete it, else do nothing
+		if (wasFound)
+		{
+			abortProcessing = mChanged(payload);
+			mItems.erase(pNotification);
+			onDelete(pNotification);
+		}
+	}
+	return abortProcessing;
+}
+
+/* static */
+LLNotificationChannelPtr LLNotificationChannel::buildChannel(const std::string& name, 
+															 const std::string& parent,
+															 LLNotificationFilter filter, 
+															 LLNotificationComparator comparator)
+{
+	// note: this is not a leak; notifications are self-registering.
+	// This factory helps to prevent excess deletions by making sure all smart
+	// pointers to notification channels come from the same source
+	new LLNotificationChannel(name, parent, filter, comparator);
+	return LLNotifications::instance().getChannel(name);
+}
+
+
+LLNotificationChannel::LLNotificationChannel(const std::string& name, 
+											 const std::string& parent,
+											 LLNotificationFilter filter, 
+											 LLNotificationComparator comparator) : 
+LLNotificationChannelBase(filter, comparator),
+mName(name),
+mParent(parent)
+{
+	// store myself in the channel map
+	LLNotifications::instance().addChannel(LLNotificationChannelPtr(this));
+	// bind to notification broadcast
+	if (parent.empty())
+	{
+		LLNotifications::instance().connectChanged(
+			boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
+	}
+	else
+	{
+		LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent);
+		p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
+	}
+}
+
+
+void LLNotificationChannel::setComparator(LLNotificationComparator comparator) 
+{ 
+	mComparator = comparator; 
+	LLNotificationSet s2(mComparator);
+	s2.insert(mItems.begin(), mItems.end());
+	mItems.swap(s2);
+	
+	// notify clients that we've been resorted
+	mChanged(LLSD().insert("sigtype", "sort")); 
+}
+
+bool LLNotificationChannel::isEmpty() const
+{
+	return mItems.empty();
+}
+
+LLNotificationChannel::Iterator LLNotificationChannel::begin()
+{
+	return mItems.begin();
+}
+
+LLNotificationChannel::Iterator LLNotificationChannel::end()
+{
+	return mItems.end();
+}
+
+std::string LLNotificationChannel::summarize()
+{
+	std::string s("Channel '");
+	s += mName;
+	s += "'\n  ";
+	for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it)
+	{
+		s += (*it)->summarize();
+		s += "\n  ";
+	}
+	return s;
+}
+
+
+// ---
+// END OF LLNotificationChannel implementation
+// =========================================================
+
+
+// =========================================================
+// LLNotifications implementation
+// ---
+LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
+															   LLNotificationComparators::orderByUUID()),
+									mIgnoreAllNotifications(false)
+{
+	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
+
+    mListener.reset(new LLNotificationsListener(*this));
+}
+
+
+// The expiration channel gets all notifications that are cancelled
+bool LLNotifications::expirationFilter(LLNotificationPtr pNotification)
+{
+	return pNotification->isCancelled() || pNotification->isRespondedTo();
+}
+
+bool LLNotifications::expirationHandler(const LLSD& payload)
+{
+	if (payload["sigtype"].asString() != "delete")
+	{
+		// anything added to this channel actually should be deleted from the master
+		cancel(find(payload["id"]));
+		return true;	// don't process this item any further
+	}
+	return false;
+}
+
+bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
+{
+	if (!pNotif->hasUniquenessConstraints())
+	{
+		return true;
+	}
+
+	// checks against existing unique notifications
+	for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
+		existing_it != mUniqueNotifications.end();
+		++existing_it)
+	{
+		LLNotificationPtr existing_notification = existing_it->second;
+		if (pNotif != existing_notification 
+			&& pNotif->isEquivalentTo(existing_notification))
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+bool LLNotifications::uniqueHandler(const LLSD& payload)
+{
+	LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
+	if (pNotif && pNotif->hasUniquenessConstraints()) 
+	{
+		if (payload["sigtype"].asString() == "add")
+		{
+			// not a duplicate according to uniqueness criteria, so we keep it
+			// and store it for future uniqueness checks
+			mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
+		}
+		else if (payload["sigtype"].asString() == "delete")
+		{
+			mUniqueNotifications.erase(pNotif->getName());
+		}
+	}
+
+	return false;
+}
+
+bool LLNotifications::failedUniquenessTest(const LLSD& payload)
+{
+	LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
+	
+	if (!pNotif || !pNotif->hasUniquenessConstraints())
+	{
+		return false;
+	}
+
+	// checks against existing unique notifications
+	for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
+		existing_it != mUniqueNotifications.end();
+		++existing_it)
+	{
+		LLNotificationPtr existing_notification = existing_it->second;
+		if (pNotif != existing_notification 
+			&& pNotif->isEquivalentTo(existing_notification))
+		{
+			// copy notification instance data over to oldest instance
+			// of this unique notification and update it
+			existing_notification->updateFrom(pNotif);
+			// then delete the new one
+			pNotif->cancel();
+		}
+	}
+
+	return false;
+}
+
+
+void LLNotifications::addChannel(LLNotificationChannelPtr pChan)
+{
+	mChannels[pChan->getName()] = pChan;
+}
+
+LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName)
+{
+	ChannelMap::iterator p = mChannels.find(channelName);
+	if(p == mChannels.end())
+	{
+		llerrs << "Did not find channel named " << channelName << llendl;
+	}
+	return p->second;
+}
+
+
+// this function is called once at construction time, after the object is constructed.
+void LLNotifications::initSingleton()
+{
+	loadTemplates();
+	createDefaultChannels();
+}
+
+void LLNotifications::createDefaultChannels()
+{
+	// now construct the various channels AFTER loading the notifications,
+	// because the history channel is going to rewrite the stored notifications file
+	LLNotificationChannel::buildChannel("Expiration", "",
+		boost::bind(&LLNotifications::expirationFilter, this, _1));
+	LLNotificationChannel::buildChannel("Unexpired", "",
+		!boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
+	LLNotificationChannel::buildChannel("Unique", "Unexpired",
+		boost::bind(&LLNotifications::uniqueFilter, this, _1));
+	LLNotificationChannel::buildChannel("Ignore", "Unique",
+		filterIgnoredNotifications);
+	LLNotificationChannel::buildChannel("Visible", "Ignore",
+		&LLNotificationFilters::includeEverything);
+
+	// create special history channel
+	//std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" );
+	// use ^^^ when done debugging notifications serialization
+	std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" );
+	// this isn't a leak, don't worry about the empty "new"
+	new LLNotificationHistoryChannel(notifications_log_file);
+
+	// connect action methods to these channels
+	LLNotifications::instance().getChannel("Expiration")->
+        connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1));
+	LLNotifications::instance().getChannel("Unique")->
+        connectChanged(boost::bind(&LLNotifications::uniqueHandler, this, _1));
+	LLNotifications::instance().getChannel("Unique")->
+        connectFailedFilter(boost::bind(&LLNotifications::failedUniquenessTest, this, _1));
+	LLNotifications::instance().getChannel("Ignore")->
+		connectFailedFilter(&handleIgnoredNotification);
+}
+
+bool LLNotifications::addTemplate(const std::string &name, 
+								  LLNotificationTemplatePtr theTemplate)
+{
+	if (mTemplates.count(name))
+	{
+		llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl;
+		return false;
+	}
+	mTemplates[name] = theTemplate;
+	return true;
+}
+
+LLNotificationTemplatePtr LLNotifications::getTemplate(const std::string& name)
+{
+	if (mTemplates.count(name))
+	{
+		return mTemplates[name];
+	}
+	else
+	{
+		return mTemplates["MissingAlert"];
+	}
+}
+
+bool LLNotifications::templateExists(const std::string& name)
+{
+	return (mTemplates.count(name) != 0);
+}
+
+void LLNotifications::clearTemplates()
+{
+	mTemplates.clear();
+}
+
+void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
+{
+	LLNotificationPtr temp_notify(new LLNotification(params));
+	LLSD response = temp_notify->getResponseTemplate();
+	LLSD selected_item = temp_notify->getForm()->getElement(option);
+	
+	if (selected_item.isUndefined())
+	{
+		llwarns << "Invalid option" << option << " for notification " << (std::string)params.name << llendl;
+		return;
+	}
+	response[selected_item["name"].asString()] = true;
+
+	temp_notify->respond(response);
+}
+
+LLNotifications::TemplateNames LLNotifications::getTemplateNames() const
+{
+	TemplateNames names;
+	for (TemplateMap::const_iterator it = mTemplates.begin(); it != mTemplates.end(); ++it)
+	{
+		names.push_back(it->first);
+	}
+	return names;
+}
+
+typedef std::map<std::string, std::string> StringMap;
+void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements)
+{
+	//llwarns << "replaceSubstitutionStrings" << llendl;
+	// walk the list of attributes looking for replacements
+	for (LLXMLAttribList::iterator it=node->mAttributes.begin();
+		 it != node->mAttributes.end(); ++it)
+	{
+		std::string value = it->second->getValue();
+		if (value[0] == '$')
+		{
+			value.erase(0, 1);	// trim off the $
+			std::string replacement;
+			StringMap::const_iterator found = replacements.find(value);
+			if (found != replacements.end())
+			{
+				replacement = found->second;
+				//llwarns << "replaceSubstituionStrings: value: " << value << " repl: " << replacement << llendl;
+
+				it->second->setValue(replacement);
+			}
+			else
+			{
+				llwarns << "replaceSubstituionStrings FAILURE: value: " << value << " repl: " << replacement << llendl;
+			}
+		}
+	}
+	
+	// now walk the list of children and call this recursively.
+	for (LLXMLNodePtr child = node->getFirstChild(); 
+		 child.notNull(); child = child->getNextSibling())
+	{
+		replaceSubstitutionStrings(child, replacements);
+	}
+}
+
+// private to this file
+// returns true if the template request was invalid and there's nothing else we
+// can do with this node, false if you should keep processing (it may have
+// replaced the contents of the node referred to)
+LLXMLNodePtr LLNotifications::checkForXMLTemplate(LLXMLNodePtr item)
+{
+	if (item->hasName("usetemplate"))
+	{
+		std::string replacementName;
+		if (item->getAttributeString("name", replacementName))
+		{
+			StringMap replacements;
+			for (LLXMLAttribList::const_iterator it=item->mAttributes.begin(); 
+				 it != item->mAttributes.end(); ++it)
+			{
+				replacements[it->second->getName()->mString] = it->second->getValue();
+			}
+			if (mXmlTemplates.count(replacementName))
+			{
+				item=LLXMLNode::replaceNode(item, mXmlTemplates[replacementName]);
+				
+				// walk the nodes looking for $(substitution) here and replace
+				replaceSubstitutionStrings(item, replacements);
+			}
+			else
+			{
+				llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl;
+			}
+		}
+	}
+	return item;
+}
+
+bool LLNotifications::loadTemplates()
+{
+	const std::string xml_filename = "notifications.xml";
+	LLXMLNodePtr root;
+	
+	BOOL success  = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
+	
+	if (!success || root.isNull() || !root->hasName( "notifications" ))
+	{
+		llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl;
+		return false;
+	}
+	
+	clearTemplates();
+	
+	for (LLXMLNodePtr item = root->getFirstChild();
+		 item.notNull(); item = item->getNextSibling())
+	{
+		// we do this FIRST so that item can be changed if we 
+		// encounter a usetemplate -- we just replace the
+		// current xml node and keep processing
+		item = checkForXMLTemplate(item);
+		
+		if (item->hasName("global"))
+		{
+			std::string global_name;
+			if (item->getAttributeString("name", global_name))
+			{
+				mGlobalStrings[global_name] = item->getTextContents();
+			}
+			continue;
+		}
+		
+		if (item->hasName("template"))
+		{
+			// store an xml template; templates must have a single node (can contain
+			// other nodes)
+			std::string name;
+			item->getAttributeString("name", name);
+			LLXMLNodePtr ptr = item->getFirstChild();
+			mXmlTemplates[name] = ptr;
+			continue;
+		}
+		
+		if (!item->hasName("notification"))
+		{
+            llwarns << "Unexpected entity " << item->getName()->mString << 
+                       " found in " << xml_filename << llendl;
+			continue;
+		}
+		
+		// now we know we have a notification entry, so let's build it
+		LLNotificationTemplatePtr pTemplate(new LLNotificationTemplate());
+
+		if (!item->getAttributeString("name", pTemplate->mName))
+		{
+			llwarns << "Unable to parse notification with no name" << llendl;
+			continue;
+		}
+		
+		//llinfos << "Parsing " << pTemplate->mName << llendl;
+		
+		pTemplate->mMessage = item->getTextContents();
+		pTemplate->mDefaultFunctor = pTemplate->mName;
+		item->getAttributeString("type", pTemplate->mType);
+		item->getAttributeString("icon", pTemplate->mIcon);
+		item->getAttributeString("label", pTemplate->mLabel);
+		item->getAttributeU32("duration", pTemplate->mExpireSeconds);
+		item->getAttributeU32("expireOption", pTemplate->mExpireOption);
+
+		std::string priority;
+		item->getAttributeString("priority", priority);
+		pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
+		if (!priority.empty())
+		{
+			if (priority == "low")      pTemplate->mPriority = NOTIFICATION_PRIORITY_LOW;
+			if (priority == "normal")   pTemplate->mPriority = NOTIFICATION_PRIORITY_NORMAL;
+			if (priority == "high")     pTemplate->mPriority = NOTIFICATION_PRIORITY_HIGH;
+			if (priority == "critical") pTemplate->mPriority = NOTIFICATION_PRIORITY_CRITICAL;
+		}
+		
+		item->getAttributeString("functor", pTemplate->mDefaultFunctor);
+
+		BOOL persist = false;
+		item->getAttributeBOOL("persist", persist);
+		pTemplate->mPersist = persist;
+		
+		std::string sound;
+		item->getAttributeString("sound", sound);
+		if (!sound.empty())
+		{
+			// test for bad sound effect name / missing effect
+			if (LLUI::sSettingGroups["config"]->controlExists(sound))
+			{
+				pTemplate->mSoundEffect = 
+					LLUUID(LLUI::sSettingGroups["config"]->getString(sound));
+			}
+			else
+			{
+				llwarns << "Unknown sound effect control name " << sound
+					<< llendl;
+			}
+		}
+
+		for (LLXMLNodePtr child = item->getFirstChild();
+			 !child.isNull(); child = child->getNextSibling())
+		{
+			child = checkForXMLTemplate(child);
+			
+			// <url>
+			if (child->hasName("url"))
+			{
+				pTemplate->mURL = child->getTextContents();
+				child->getAttributeU32("option", pTemplate->mURLOption);
+				child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
+			}
+			
+            if (child->hasName("unique"))
+            {
+                pTemplate->mUnique = true;
+                for (LLXMLNodePtr formitem = child->getFirstChild();
+                     !formitem.isNull(); formitem = formitem->getNextSibling())
+                {
+                    if (formitem->hasName("context"))
+                    {
+                        std::string key;
+                        formitem->getAttributeString("key", key);
+                        pTemplate->mUniqueContext.push_back(key);
+                        //llwarns << "adding " << key << " to unique context" << llendl;
+                    }
+                    else
+                    {
+                        llwarns << "'unique' has unrecognized subelement " 
+                        << formitem->getName()->mString << llendl;
+                    }
+                }
+            }
+            
+			// <form>
+			if (child->hasName("form"))
+			{
+                pTemplate->mForm = LLNotificationFormPtr(new LLNotificationForm(pTemplate->mName, child));
+			}
+		}
+		addTemplate(pTemplate->mName, pTemplate);
+	}
+	
+	//std::ostringstream ostream;
+	//root->writeToOstream(ostream, "\n  ");
+	//llwarns << ostream.str() << llendl;
+	
+	return true;
+}
+
+// Add a simple notification (from XUI)
+void LLNotifications::addFromCallback(const LLSD& name)
+{
+	add(LLNotification::Params().name(name.asString()));	
+}
+
+// we provide a couple of simple add notification functions so that it's reasonable to create notifications in one line
+LLNotificationPtr LLNotifications::add(const std::string& name, 
+										const LLSD& substitutions, 
+										const LLSD& payload)
+{
+	LLNotification::Params::Functor functor_p;
+	functor_p.name = name;
+	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
+}
+
+LLNotificationPtr LLNotifications::add(const std::string& name, 
+										const LLSD& substitutions, 
+										const LLSD& payload, 
+										const std::string& functor_name)
+{
+	LLNotification::Params::Functor functor_p;
+	functor_p.name = functor_name;
+	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
+}
+
+LLNotificationPtr LLNotifications::add(const std::string& name, 
+										const LLSD& substitutions, 
+										const LLSD& payload, 
+										LLNotificationFunctorRegistry::ResponseFunctor functor)
+{
+	LLNotification::Params::Functor functor_p;
+	functor_p.function = functor;
+	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
+}
+
+// generalized add function that takes a parameter block object for more complex instantiations
+LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
+{
+	LLNotificationPtr pNotif(new LLNotification(p));
+	add(pNotif);
+	return pNotif;
+}
+
+
+void LLNotifications::add(const LLNotificationPtr pNotif)
+{
+	// first see if we already have it -- if so, that's a problem
+	LLNotificationSet::iterator it=mItems.find(pNotif);
+	if (it != mItems.end())
+	{
+		llerrs << "Notification added a second time to the master notification channel." << llendl;
+	}
+
+	updateItem(LLSD().insert("sigtype", "add").insert("id", pNotif->id()), pNotif);
+}
+
+void LLNotifications::cancel(LLNotificationPtr pNotif)
+{
+	LLNotificationSet::iterator it=mItems.find(pNotif);
+	if (it == mItems.end())
+	{
+		llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl;
+	}
+	updateItem(LLSD().insert("sigtype", "delete").insert("id", pNotif->id()), pNotif);
+	pNotif->cancel();
+}
+
+void LLNotifications::update(const LLNotificationPtr pNotif)
+{
+	LLNotificationSet::iterator it=mItems.find(pNotif);
+	if (it != mItems.end())
+	{
+		updateItem(LLSD().insert("sigtype", "change").insert("id", pNotif->id()), pNotif);
+	}
+}
+
+
+LLNotificationPtr LLNotifications::find(LLUUID uuid)
+{
+	LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid));
+	LLNotificationSet::iterator it=mItems.find(target);
+	if (it == mItems.end())
+	{
+		llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl;
+		return LLNotificationPtr((LLNotification*)NULL);
+	}
+	else
+	{
+		return *it;
+	}
+}
+
+void LLNotifications::forEachNotification(NotificationProcess process)
+{
+	std::for_each(mItems.begin(), mItems.end(), process);
+}
+
+std::string LLNotifications::getGlobalString(const std::string& key) const
+{
+	GlobalStringMap::const_iterator it = mGlobalStrings.find(key);
+	if (it != mGlobalStrings.end())
+	{
+		return it->second;
+	}
+	else
+	{
+		// if we don't have the key as a global, return the key itself so that the error
+		// is self-diagnosing.
+		return key;
+	}
+}
+
+void LLNotifications::setIgnoreAllNotifications(bool setting)
+{
+	mIgnoreAllNotifications = setting; 
+}
+bool LLNotifications::getIgnoreAllNotifications()
+{
+	return mIgnoreAllNotifications; 
+}
+													
+// ---
+// END OF LLNotifications implementation
+// =========================================================
+
+std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
+{
+	s << notification.summarize();
+	return s;
+}
+
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 512886790c..971d11db97 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -1,910 +1,913 @@
-/**
-* @file llnotifications.h
-* @brief Non-UI manager and support for keeping a prioritized list of notifications
-* @author Q (with assistance from Richard and Coco)
-*
-* $LicenseInfo:firstyear=2008&license=viewergpl$
-* 
-* Copyright (c) 2008-2009, Linden Research, Inc.
-* 
-* Second Life Viewer Source Code
-* The source code in this file ("Source Code") is provided by Linden Lab
-* to you under the terms of the GNU General Public License, version 2.0
-* ("GPL"), unless you have obtained a separate licensing agreement
-* ("Other License"), formally executed by you and Linden Lab.  Terms of
-* the GPL can be found in doc/GPL-license.txt in this distribution, or
-* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
-* 
-* There are special exceptions to the terms and conditions of the GPL as
-* it is applied to this Source Code. View the full text of the exception
-* in the file doc/FLOSS-exception.txt in this software distribution, or
-* online at
-* http://secondlifegrid.net/programs/open_source/licensing/flossexception
-* 
-* By copying, modifying or distributing this software, you acknowledge
-* that you have read and understood your obligations described above,
-* and agree to abide by those obligations.
-* 
-* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-* COMPLETENESS OR PERFORMANCE.
-* $/LicenseInfo$
-*/
-
-#ifndef LL_LLNOTIFICATIONS_H
-#define LL_LLNOTIFICATIONS_H
-
-/**
- * This system is intended to provide a singleton mechanism for adding
- * notifications to one of an arbitrary set of event channels.
- * 
- * Controlling JIRA: DEV-9061
- *
- * Every notification has (see code for full list):
- *  - a textual name, which is used to look up its template in the XML files
- *  - a payload, which is a block of LLSD
- *  - a channel, which is normally extracted from the XML files but
- *	  can be overridden.
- *  - a timestamp, used to order the notifications
- *  - expiration time -- if nonzero, specifies a time after which the
- *    notification will no longer be valid.
- *  - a callback name and a couple of status bits related to callbacks (see below)
- * 
- * There is a management class called LLNotifications, which is an LLSingleton.
- * The class maintains a collection of all of the notifications received
- * or processed during this session, and also manages the persistence
- * of those notifications that must be persisted.
- * 
- * We also have Channels. A channel is a view on a collection of notifications;
- * The collection is defined by a filter function that controls which
- * notifications are in the channel, and its ordering is controlled by 
- * a comparator. 
- *
- * There is a hierarchy of channels; notifications flow down from
- * the management class (LLNotifications, which itself inherits from
- * The channel base class) to the individual channels.
- * Any change to notifications (add, delete, modify) is 
- * automatically propagated through the channel hierarchy.
- * 
- * We provide methods for adding a new notification, for removing
- * one, and for managing channels. Channels are relatively cheap to construct
- * and maintain, so in general, human interfaces should use channels to
- * select and manage their lists of notifications.
- * 
- * We also maintain a collection of templates that are loaded from the 
- * XML file of template translations. The system supports substitution
- * of named variables from the payload into the XML file.
- * 
- * By default, only the "unknown message" template is built into the system.
- * It is not an error to add a notification that's not found in the 
- * template system, but it is logged.
- *
- */
-
-#include <string>
-#include <list>
-#include <vector>
-#include <map>
-#include <set>
-#include <iomanip>
-#include <sstream>
-
-#include <boost/utility.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/type_traits.hpp>
-
-// we want to minimize external dependencies, but this one is important
-#include "llsd.h"
-
-// and we need this to manage the notification callbacks
-#include "llevents.h"
-#include "llfunctorregistry.h"
-#include "llui.h"
-#include "llmemory.h"
-
-class LLNotification;
-typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
-
-	
-typedef enum e_notification_priority
-{
-	NOTIFICATION_PRIORITY_UNSPECIFIED,
-	NOTIFICATION_PRIORITY_LOW,
-	NOTIFICATION_PRIORITY_NORMAL,
-	NOTIFICATION_PRIORITY_HIGH,
-	NOTIFICATION_PRIORITY_CRITICAL
-} ENotificationPriority;
-
-typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
-
-typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
-typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
-
-// context data that can be looked up via a notification's payload by the display logic
-// derive from this class to implement specific contexts
-class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
-{
-public:
-	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
-	{
-	}
-
-	virtual ~LLNotificationContext() {}
-
-	LLSD asLLSD() const
-	{
-		return getKey();
-	}
-
-private:
-
-};
-
-// Contains notification form data, such as buttons and text fields along with
-// manipulator functions
-class LLNotificationForm
-{
-	LOG_CLASS(LLNotificationForm);
-
-public:
-	typedef enum e_ignore_type
-	{ 
-		IGNORE_NO,
-		IGNORE_WITH_DEFAULT_RESPONSE, 
-		IGNORE_WITH_LAST_RESPONSE, 
-		IGNORE_SHOW_AGAIN 
-	} EIgnoreType;
-
-	LLNotificationForm();
-	LLNotificationForm(const LLSD& sd);
-	LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
-
-	LLSD asLLSD() const;
-
-	S32 getNumElements() { return mFormData.size(); }
-	LLSD getElement(S32 index) { return mFormData.get(index); }
-	LLSD getElement(const std::string& element_name);
-	bool hasElement(const std::string& element_name);
-	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
-	void formatElements(const LLSD& substitutions);
-	// appends form elements from another form serialized as LLSD
-	void append(const LLSD& sub_form);
-	std::string getDefaultOption();
-
-	EIgnoreType getIgnoreType() { return mIgnore; }
-	std::string getIgnoreMessage() { return mIgnoreMsg; }
-
-private:
-	LLSD	mFormData;
-	EIgnoreType mIgnore;
-	std::string mIgnoreMsg;
-};
-
-typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
-
-// This is the class of object read from the XML file (notifications.xml, 
-// from the appropriate local language directory).
-struct LLNotificationTemplate
-{
-	LLNotificationTemplate();
-    // the name of the notification -- the key used to identify it
-    // Ideally, the key should follow variable naming rules 
-    // (no spaces or punctuation).
-    std::string mName;
-    // The type of the notification
-    // used to control which queue it's stored in
-    std::string mType;
-    // The text used to display the notification. Replaceable parameters
-    // are enclosed in square brackets like this [].
-    std::string mMessage;
-	// The label for the notification; used for 
-	// certain classes of notification (those with a window and a window title). 
-	// Also used when a notification pops up underneath the current one.
-	// Replaceable parameters can be used in the label.
-	std::string mLabel;
-	// The name of the icon image. This should include an extension.
-	std::string mIcon;
-    // This is the Highlander bit -- "There Can Be Only One"
-    // An outstanding notification with this bit set
-    // is updated by an incoming notification with the same name,
-    // rather than creating a new entry in the queue.
-    // (used for things like progress indications, or repeating warnings
-    // like "the grid is going down in N minutes")
-    bool mUnique;
-    // if we want to be unique only if a certain part of the payload is constant
-    // specify the field names for the payload. The notification will only be
-    // combined if all of the fields named in the context are identical in the
-    // new and the old notification; otherwise, the notification will be
-    // duplicated. This is to support suppressing duplicate offers from the same
-    // sender but still differentiating different offers. Example: Invitation to
-    // conference chat.
-    std::vector<std::string> mUniqueContext;
-    // If this notification expires automatically, this value will be 
-    // nonzero, and indicates the number of seconds for which the notification
-    // will be valid (a teleport offer, for example, might be valid for 
-    // 300 seconds). 
-    U32 mExpireSeconds;
-    // if the offer expires, one of the options is chosen automatically
-    // based on its "value" parameter. This controls which one. 
-    // If expireSeconds is specified, expireOption should also be specified.
-    U32 mExpireOption;
-    // if the notification contains a url, it's stored here (and replaced 
-    // into the message where [_URL] is found)
-    std::string mURL;
-    // if there's a URL in the message, this controls which option visits
-    // that URL. Obsolete this and eliminate the buttons for affected
-    // messages when we allow clickable URLs in the UI
-    U32 mURLOption;
-	
-	U32 mURLOpenExternally;
-	//This is a flag that tells if the url needs to open externally dispite 
-	//what the user setting is.
-	
-	// does this notification persist across sessions? if so, it will be
-	// serialized to disk on first receipt and read on startup
-	bool mPersist;
-	// This is the name of the default functor, if present, to be
-	// used for the notification's callback. It is optional, and used only if 
-	// the notification is constructed without an identified functor.
-	std::string mDefaultFunctor;
-	// The form data associated with a given notification (buttons, text boxes, etc)
-    LLNotificationFormPtr mForm;
-	// default priority for notifications of this type
-	ENotificationPriority mPriority;
-	// UUID of the audio file to be played when this notification arrives
-	// this is loaded as a name, but looked up to get the UUID upon template load.
-	// If null, it wasn't specified.
-	LLUUID mSoundEffect;
-};
-
-// we want to keep a map of these by name, and it's best to manage them
-// with smart pointers
-typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
-
-/**
- * @class LLNotification
- * @brief The object that expresses the details of a notification
- * 
- * We make this noncopyable because
- * we want to manage these through LLNotificationPtr, and only
- * ever create one instance of any given notification.
- * 
- * The enable_shared_from_this flag ensures that if we construct
- * a smart pointer from a notification, we'll always get the same
- * shared pointer.
- */
-class LLNotification  : 
-	boost::noncopyable,
-	public boost::enable_shared_from_this<LLNotification>
-{
-LOG_CLASS(LLNotification);
-friend class LLNotifications;
-
-public:
-	// parameter object used to instantiate a new notification
-	struct Params : public LLInitParam::Block<Params>
-	{
-		friend class LLNotification;
-	
-		Mandatory<std::string>					name;
-
-		// optional
-		Optional<LLSD>							substitutions;
-		Optional<LLSD>							payload;
-		Optional<ENotificationPriority>			priority;
-		Optional<LLSD>							form_elements;
-		Optional<LLDate>						timestamp;
-		Optional<LLNotificationContext*>		context;
-
-		struct Functor : public LLInitParam::Choice<Functor>
-		{
-			Alternative<std::string>										name;
-			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
-
-			Functor()
-			:	name("functor_name"),
-				function("functor")
-			{}
-		};
-		Optional<Functor>						functor;
-
-		Params()
-		:	name("name"),
-			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
-			timestamp("time_stamp")
-		{
-			timestamp = LLDate::now();
-		}
-
-		Params(const std::string& _name) 
-			:	name("name"),
-				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
-				timestamp("time_stamp")
-		{
-			functor.name = _name;
-			name = _name;
-			timestamp = LLDate::now();
-		}
-	};
-
-private:
-	
-	LLUUID mId;
-	LLSD mPayload;
-	LLSD mSubstitutions;
-	LLDate mTimestamp;
-	LLDate mExpiresAt;
-	bool mCancelled;
-	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
-	bool mIgnored;
-	ENotificationPriority mPriority;
-	LLNotificationFormPtr mForm;
-	
-	// a reference to the template
-	LLNotificationTemplatePtr mTemplatep;
-	
-	/*
-	 We want to be able to store and reload notifications so that they can survive
-	 a shutdown/restart of the client. So we can't simply pass in callbacks;
-	 we have to specify a callback mechanism that can be used by name rather than 
-	 by some arbitrary pointer -- and then people have to initialize callbacks 
-	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
-	 */
-	 std::string mResponseFunctorName;
-	
-	/*
-	 In cases where we want to specify an explict, non-persisted callback, 
-	 we store that in the callback registry under a dynamically generated
-	 key, and store the key in the notification, so we can still look it up
-	 using the same mechanism.
-	 */
-	bool mTemporaryResponder;
-
-	void init(const std::string& template_name, const LLSD& form_elements);
-
-	LLNotification(const Params& p);
-
-	// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
-	// for anything real!
-	LLNotification(LLUUID uuid) : mId(uuid) {}
-
-	void cancel();
-
-	bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
-
-public:
-
-	// constructor from a saved notification
-	LLNotification(const LLSD& sd);
-
-	void setResponseFunctor(std::string const &responseFunctorName);
-
-	typedef enum e_response_template_type
-	{
-		WITHOUT_DEFAULT_BUTTON,
-		WITH_DEFAULT_BUTTON
-	} EResponseTemplateType;
-
-	// return response LLSD filled in with default form contents and (optionally) the default button selected
-	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
-
-	// returns index of first button with value==TRUE
-	// usually this the button the user clicked on
-	// returns -1 if no button clicked (e.g. form has not been displayed)
-	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
-	// returns name of first button with value==TRUE
-	static std::string getSelectedOptionName(const LLSD& notification);
-
-	// after someone responds to a notification (usually by clicking a button,
-	// but sometimes by filling out a little form and THEN clicking a button),
-    // the result of the response (the name and value of the button clicked,
-	// plus any other data) should be packaged up as LLSD, then passed as a
-	// parameter to the notification's respond() method here. This will look up
-	// and call the appropriate responder.
-	//
-	// response is notification serialized as LLSD:
-	// ["name"] = notification name
-	// ["form"] = LLSD tree that includes form description and any prefilled form data
-	// ["response"] = form data filled in by user
-	// (including, but not limited to which button they clicked on)
-	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
-	//				["item_id"] (attached inventory item), etc.
-	// ["substitutions"] = string substitutions used to generate notification message
-    // from the template
-	// ["time"] = time at which notification was generated;
-	// ["expiry"] = time at which notification expires;
-	// ["responseFunctor"] = name of registered functor that handles responses to notification;
-	LLSD asLLSD();
-
-	void respond(const LLSD& sd);
-
-	void setIgnored(bool ignore);
-
-	bool isCancelled() const
-	{
-		return mCancelled;
-	}
-
-	bool isRespondedTo() const
-	{
-		return mRespondedTo;
-	}
-
-	bool isIgnored() const
-	{
-		return mIgnored;
-	}
-
-	const std::string& getName() const
-	{
-		return mTemplatep->mName;
-	}
-	
-	const LLUUID& id() const
-	{
-		return mId;
-	}
-	
-	const LLSD& getPayload() const
-	{
-		return mPayload;
-	}
-
-	const LLSD& getSubstitutions() const
-	{
-		return mSubstitutions;
-	}
-
-	const LLDate& getDate() const
-	{
-		return mTimestamp;
-	}
-
-	std::string getType() const
-	{
-		return (mTemplatep ? mTemplatep->mType : "");
-	}
-
-	std::string getMessage() const;
-	std::string getLabel() const;
-
-	std::string getURL() const;
-//	{
-//		return (mTemplatep ? mTemplatep->mURL : "");
-//	}
-
-	S32 getURLOption() const
-	{
-		return (mTemplatep ? mTemplatep->mURLOption : -1);
-	}
-    
-	S32 getURLOpenExternally() const
-	{
-		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
-	}
-	
-	const LLNotificationFormPtr getForm();
-
-	const LLDate getExpiration() const
-	{
-		return mExpiresAt;
-	}
-
-	ENotificationPriority getPriority() const
-	{
-		return mPriority;
-	}
-
-	const LLUUID getID() const
-	{
-		return mId;
-	}
-	
-	// comparing two notifications normally means comparing them by UUID (so we can look them
-	// up quickly this way)
-	bool operator<(const LLNotification& rhs) const
-	{
-		return mId < rhs.mId;
-	}
-
-	bool operator==(const LLNotification& rhs) const
-	{
-		return mId == rhs.mId;
-	}
-
-	bool operator!=(const LLNotification& rhs) const
-	{
-		return !operator==(rhs);
-	}
-
-	bool isSameObjectAs(const LLNotification* rhs) const
-	{
-		return this == rhs;
-	}
-	
-	// this object has been updated, so tell all our clients
-	void update();
-
-	void updateFrom(LLNotificationPtr other);
-	
-	// A fuzzy equals comparator.
-	// true only if both notifications have the same template and 
-	//     1) flagged as unique (there can be only one of these) OR 
-	//     2) all required payload fields of each also exist in the other.
-	bool isEquivalentTo(LLNotificationPtr that) const;
-	
-	// if the current time is greater than the expiration, the notification is expired
-	bool isExpired() const
-	{
-		if (mExpiresAt.secondsSinceEpoch() == 0)
-		{
-			return false;
-		}
-		
-		LLDate rightnow = LLDate::now();
-		return rightnow > mExpiresAt;
-	}
-	
-	std::string summarize() const;
-
-	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
-
-	virtual ~LLNotification() {}
-};
-
-std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
-
-namespace LLNotificationFilters
-{
-	// a sample filter
-	bool includeEverything(LLNotificationPtr p);
-
-	typedef enum e_comparison 
-	{ 
-		EQUAL, 
-		LESS, 
-		GREATER, 
-		LESS_EQUAL, 
-		GREATER_EQUAL 
-	} EComparison;
-
-	// generic filter functor that takes method or member variable reference
-	template<typename T>
-	struct filterBy
-	{
-		typedef boost::function<T (LLNotificationPtr)>	field_t;
-		typedef typename boost::remove_reference<T>::type		value_t;
-		
-		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
-			:	mField(field), 
-				mFilterValue(value),
-				mComparison(comparison)
-		{
-		}		
-		
-		bool operator()(LLNotificationPtr p)
-		{
-			switch(mComparison)
-			{
-			case EQUAL:
-				return mField(p) == mFilterValue;
-			case LESS:
-				return mField(p) < mFilterValue;
-			case GREATER:
-				return mField(p) > mFilterValue;
-			case LESS_EQUAL:
-				return mField(p) <= mFilterValue;
-			case GREATER_EQUAL:
-				return mField(p) >= mFilterValue;
-			default:
-				return false;
-			}
-		}
-
-		field_t mField;
-		value_t	mFilterValue;
-		EComparison mComparison;
-	};
-};
-
-namespace LLNotificationComparators
-{
-	typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
-
-	// generic order functor that takes method or member variable reference
-	template<typename T>
-	struct orderBy
-	{
-		typedef boost::function<T (LLNotificationPtr)> field_t;
-		orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
-		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
-		{
-			if (mDirection == ORDER_DECREASING)
-			{
-				return mField(lhs) > mField(rhs);
-			}
-			else
-			{
-				return mField(lhs) < mField(rhs);
-			}
-		}
-
-		field_t mField;
-		EDirection mDirection;
-	};
-
-	struct orderByUUID : public orderBy<const LLUUID&>
-	{
-		orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
-	};
-
-	struct orderByDate : public orderBy<const LLDate&>
-	{
-		orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
-	};
-};
-
-typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
-typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
-typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
-typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
-
-// ========================================================
-// Abstract base class (interface) for a channel; also used for the master container.
-// This lets us arrange channels into a call hierarchy.
-
-// We maintain a heirarchy of notification channels; events are always started at the top
-// and propagated through the hierarchy only if they pass a filter.
-// Any channel can be created with a parent. A null parent (empty string) means it's
-// tied to the root of the tree (the LLNotifications class itself).
-// The default hierarchy looks like this:
-//
-// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
-//                                                                          +-- Alerts
-//                                                                          +-- Notifications
-//
-// In general, new channels that want to only see notifications that pass through 
-// all of the built-in tests should attach to the "Visible" channel
-//
-class LLNotificationChannelBase :
-	public LLEventTrackable
-{
-	LOG_CLASS(LLNotificationChannelBase);
-public:
-	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
-		mFilter(filter), mItems(comp) 
-	{}
-	virtual ~LLNotificationChannelBase() {}
-	// you can also connect to a Channel, so you can be notified of
-	// changes to this channel
-	template <typename LISTENER>
-    LLBoundListener connectChanged(const LISTENER& slot)
-    {
-        // Examine slot to see if it binds an LLEventTrackable subclass, or a
-        // boost::shared_ptr to something, or a boost::weak_ptr to something.
-        // Call this->connectChangedImpl() to actually connect it.
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
-                                              this,
-                                              _1));
-    }
-    template <typename LISTENER>
-	LLBoundListener connectPassedFilter(const LISTENER& slot)
-    {
-        // see comments in connectChanged()
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
-                                              this,
-                                              _1));
-    }
-    template <typename LISTENER>
-	LLBoundListener connectFailedFilter(const LISTENER& slot)
-    {
-        // see comments in connectChanged()
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
-                                              this,
-                                              _1));
-    }
-
-	// use this when items change or to add a new one
-	bool updateItem(const LLSD& payload);
-	const LLNotificationFilter& getFilter() { return mFilter; }
-
-protected:
-    LLBoundListener connectChangedImpl(const LLEventListener& slot);
-    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
-    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
-
-	LLNotificationSet mItems;
-	LLStandardSignal mChanged;
-	LLStandardSignal mPassedFilter;
-	LLStandardSignal mFailedFilter;
-	
-	// these are action methods that subclasses can override to take action 
-	// on specific types of changes; the management of the mItems list is
-	// still handled by the generic handler.
-	virtual void onLoad(LLNotificationPtr p) {}
-	virtual void onAdd(LLNotificationPtr p) {}
-	virtual void onDelete(LLNotificationPtr p) {}
-	virtual void onChange(LLNotificationPtr p) {}
-
-	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
-	LLNotificationFilter mFilter;
-};
-
-// The type of the pointers that we're going to manage in the NotificationQueue system
-// Because LLNotifications is a singleton, we don't actually expect to ever 
-// destroy it, but if it becomes necessary to do so, the shared_ptr model
-// will ensure that we don't leak resources.
-class LLNotificationChannel;
-typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
-
-// manages a list of notifications
-// Note that if this is ever copied around, we might find ourselves with multiple copies
-// of a queue with notifications being added to different nonequivalent copies. So we 
-// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
-// 
-// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
-// do something like:
-//		LLNotificationChannel::buildChannel("name", "parent"...);
-// This returns an LLNotificationChannelPtr, which you can store, or
-// you can then retrieve the channel by using the registry:
-//		LLNotifications::instance().getChannel("name")...
-//
-class LLNotificationChannel : 
-	boost::noncopyable, 
-	public LLNotificationChannelBase
-{
-	LOG_CLASS(LLNotificationChannel);
-
-public:  
-	virtual ~LLNotificationChannel() {}
-	typedef LLNotificationSet::iterator Iterator;
-    
-	std::string getName() const { return mName; }
-	std::string getParentChannelName() { return mParent; }
-    
-    bool isEmpty() const;
-    
-    Iterator begin();
-    Iterator end();
-
-    // Channels have a comparator to control sort order;
-	// the default sorts by arrival date
-    void setComparator(LLNotificationComparator comparator);
-	
-	std::string summarize();
-
-	// factory method for constructing these channels; since they're self-registering,
-	// we want to make sure that you can't use new to make them
-	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
-						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
-						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
-	
-protected:
-    // Notification Channels have a filter, which determines which notifications
-	// will be added to this channel. 
-	// Channel filters cannot change.
-	// Channels have a protected constructor so you can't make smart pointers that don't 
-	// come from our internal reference; call NotificationChannel::build(args)
-	LLNotificationChannel(const std::string& name, const std::string& parent,
-						  LLNotificationFilter filter, LLNotificationComparator comparator);
-
-private:
-	std::string mName;
-	std::string mParent;
-	LLNotificationComparator mComparator;
-};
-
-
-
-class LLNotifications : 
-	public LLSingleton<LLNotifications>, 
-	public LLNotificationChannelBase
-{
-	LOG_CLASS(LLNotifications);
-
-	friend class LLSingleton<LLNotifications>;
-public:
-	// load notification descriptions from file; 
-	// OK to call more than once because it will reload
-	bool loadTemplates();  
-	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
-	
-	// Add a simple notification (from XUI)
-	void addFromCallback(const LLSD& name);
-	
-	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions = LLSD(), 
-						const LLSD& payload = LLSD());
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions, 
-						const LLSD& payload, 
-						const std::string& functor_name);
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions, 
-						const LLSD& payload, 
-						LLNotificationFunctorRegistry::ResponseFunctor functor);
-	LLNotificationPtr add(const LLNotification::Params& p);
-
-	void add(const LLNotificationPtr pNotif);
-	void cancel(LLNotificationPtr pNotif);
-	void update(const LLNotificationPtr pNotif);
-
-	LLNotificationPtr find(LLUUID uuid);
-	
-	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
-	
-	void forEachNotification(NotificationProcess process);
-
-	// This is all stuff for managing the templates
-	// take your template out
-	LLNotificationTemplatePtr getTemplate(const std::string& name);
-	
-	// get the whole collection
-	typedef std::vector<std::string> TemplateNames;
-	TemplateNames getTemplateNames() const;  // returns a list of notification names
-	
-	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
-
-	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
-	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
-
-	// test for existence
-	bool templateExists(const std::string& name);
-	// useful if you're reloading the file
-	void clearTemplates();   // erase all templates
-
-	void forceResponse(const LLNotification::Params& params, S32 option);
-
-	void createDefaultChannels();
-
-	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
-	ChannelMap mChannels;
-
-	void addChannel(LLNotificationChannelPtr pChan);
-	LLNotificationChannelPtr getChannel(const std::string& channelName);
-	
-	std::string getGlobalString(const std::string& key) const;
-
-	void setIgnoreAllNotifications(bool ignore);
-	bool getIgnoreAllNotifications();
-
-private:
-	// we're a singleton, so we don't have a public constructor
-	LLNotifications();
-	/*virtual*/ void initSingleton();
-	
-	void loadPersistentNotifications();
-
-	bool expirationFilter(LLNotificationPtr pNotification);
-	bool expirationHandler(const LLSD& payload);
-	bool uniqueFilter(LLNotificationPtr pNotification);
-	bool uniqueHandler(const LLSD& payload);
-	bool failedUniquenessTest(const LLSD& payload);
-	LLNotificationChannelPtr pHistoryChannel;
-	LLNotificationChannelPtr pExpirationChannel;
-	
-	// put your template in
-	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
-	TemplateMap mTemplates;
-
-	std::string mFileName;
-	
-	typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
-	XMLTemplateMap mXmlTemplates;
-
-	LLNotificationMap mUniqueNotifications;
-	
-	typedef std::map<std::string, std::string> GlobalStringMap;
-	GlobalStringMap mGlobalStrings;
-
-	bool mIgnoreAllNotifications;
-};
-
-
-#endif//LL_LLNOTIFICATIONS_H
-
+/**
+* @file llnotifications.h
+* @brief Non-UI manager and support for keeping a prioritized list of notifications
+* @author Q (with assistance from Richard and Coco)
+*
+* $LicenseInfo:firstyear=2008&license=viewergpl$
+* 
+* Copyright (c) 2008-2009, Linden Research, Inc.
+* 
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab.  Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+* 
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+* 
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+* 
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#ifndef LL_LLNOTIFICATIONS_H
+#define LL_LLNOTIFICATIONS_H
+
+/**
+ * This system is intended to provide a singleton mechanism for adding
+ * notifications to one of an arbitrary set of event channels.
+ * 
+ * Controlling JIRA: DEV-9061
+ *
+ * Every notification has (see code for full list):
+ *  - a textual name, which is used to look up its template in the XML files
+ *  - a payload, which is a block of LLSD
+ *  - a channel, which is normally extracted from the XML files but
+ *	  can be overridden.
+ *  - a timestamp, used to order the notifications
+ *  - expiration time -- if nonzero, specifies a time after which the
+ *    notification will no longer be valid.
+ *  - a callback name and a couple of status bits related to callbacks (see below)
+ * 
+ * There is a management class called LLNotifications, which is an LLSingleton.
+ * The class maintains a collection of all of the notifications received
+ * or processed during this session, and also manages the persistence
+ * of those notifications that must be persisted.
+ * 
+ * We also have Channels. A channel is a view on a collection of notifications;
+ * The collection is defined by a filter function that controls which
+ * notifications are in the channel, and its ordering is controlled by 
+ * a comparator. 
+ *
+ * There is a hierarchy of channels; notifications flow down from
+ * the management class (LLNotifications, which itself inherits from
+ * The channel base class) to the individual channels.
+ * Any change to notifications (add, delete, modify) is 
+ * automatically propagated through the channel hierarchy.
+ * 
+ * We provide methods for adding a new notification, for removing
+ * one, and for managing channels. Channels are relatively cheap to construct
+ * and maintain, so in general, human interfaces should use channels to
+ * select and manage their lists of notifications.
+ * 
+ * We also maintain a collection of templates that are loaded from the 
+ * XML file of template translations. The system supports substitution
+ * of named variables from the payload into the XML file.
+ * 
+ * By default, only the "unknown message" template is built into the system.
+ * It is not an error to add a notification that's not found in the 
+ * template system, but it is logged.
+ *
+ */
+
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+#include <set>
+#include <iomanip>
+#include <sstream>
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/type_traits.hpp>
+
+// we want to minimize external dependencies, but this one is important
+#include "llsd.h"
+
+// and we need this to manage the notification callbacks
+#include "llevents.h"
+#include "llfunctorregistry.h"
+#include "llui.h"
+#include "llmemory.h"
+
+class LLNotification;
+typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
+
+	
+typedef enum e_notification_priority
+{
+	NOTIFICATION_PRIORITY_UNSPECIFIED,
+	NOTIFICATION_PRIORITY_LOW,
+	NOTIFICATION_PRIORITY_NORMAL,
+	NOTIFICATION_PRIORITY_HIGH,
+	NOTIFICATION_PRIORITY_CRITICAL
+} ENotificationPriority;
+
+typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
+
+typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
+typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
+
+// context data that can be looked up via a notification's payload by the display logic
+// derive from this class to implement specific contexts
+class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
+{
+public:
+	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
+	{
+	}
+
+	virtual ~LLNotificationContext() {}
+
+	LLSD asLLSD() const
+	{
+		return getKey();
+	}
+
+private:
+
+};
+
+// Contains notification form data, such as buttons and text fields along with
+// manipulator functions
+class LLNotificationForm
+{
+	LOG_CLASS(LLNotificationForm);
+
+public:
+	typedef enum e_ignore_type
+	{ 
+		IGNORE_NO,
+		IGNORE_WITH_DEFAULT_RESPONSE, 
+		IGNORE_WITH_LAST_RESPONSE, 
+		IGNORE_SHOW_AGAIN 
+	} EIgnoreType;
+
+	LLNotificationForm();
+	LLNotificationForm(const LLSD& sd);
+	LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
+
+	LLSD asLLSD() const;
+
+	S32 getNumElements() { return mFormData.size(); }
+	LLSD getElement(S32 index) { return mFormData.get(index); }
+	LLSD getElement(const std::string& element_name);
+	bool hasElement(const std::string& element_name);
+	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
+	void formatElements(const LLSD& substitutions);
+	// appends form elements from another form serialized as LLSD
+	void append(const LLSD& sub_form);
+	std::string getDefaultOption();
+
+	EIgnoreType getIgnoreType() { return mIgnore; }
+	std::string getIgnoreMessage() { return mIgnoreMsg; }
+
+private:
+	LLSD	mFormData;
+	EIgnoreType mIgnore;
+	std::string mIgnoreMsg;
+};
+
+typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
+
+// This is the class of object read from the XML file (notifications.xml, 
+// from the appropriate local language directory).
+struct LLNotificationTemplate
+{
+	LLNotificationTemplate();
+    // the name of the notification -- the key used to identify it
+    // Ideally, the key should follow variable naming rules 
+    // (no spaces or punctuation).
+    std::string mName;
+    // The type of the notification
+    // used to control which queue it's stored in
+    std::string mType;
+    // The text used to display the notification. Replaceable parameters
+    // are enclosed in square brackets like this [].
+    std::string mMessage;
+	// The label for the notification; used for 
+	// certain classes of notification (those with a window and a window title). 
+	// Also used when a notification pops up underneath the current one.
+	// Replaceable parameters can be used in the label.
+	std::string mLabel;
+	// The name of the icon image. This should include an extension.
+	std::string mIcon;
+    // This is the Highlander bit -- "There Can Be Only One"
+    // An outstanding notification with this bit set
+    // is updated by an incoming notification with the same name,
+    // rather than creating a new entry in the queue.
+    // (used for things like progress indications, or repeating warnings
+    // like "the grid is going down in N minutes")
+    bool mUnique;
+    // if we want to be unique only if a certain part of the payload is constant
+    // specify the field names for the payload. The notification will only be
+    // combined if all of the fields named in the context are identical in the
+    // new and the old notification; otherwise, the notification will be
+    // duplicated. This is to support suppressing duplicate offers from the same
+    // sender but still differentiating different offers. Example: Invitation to
+    // conference chat.
+    std::vector<std::string> mUniqueContext;
+    // If this notification expires automatically, this value will be 
+    // nonzero, and indicates the number of seconds for which the notification
+    // will be valid (a teleport offer, for example, might be valid for 
+    // 300 seconds). 
+    U32 mExpireSeconds;
+    // if the offer expires, one of the options is chosen automatically
+    // based on its "value" parameter. This controls which one. 
+    // If expireSeconds is specified, expireOption should also be specified.
+    U32 mExpireOption;
+    // if the notification contains a url, it's stored here (and replaced 
+    // into the message where [_URL] is found)
+    std::string mURL;
+    // if there's a URL in the message, this controls which option visits
+    // that URL. Obsolete this and eliminate the buttons for affected
+    // messages when we allow clickable URLs in the UI
+    U32 mURLOption;
+	
+	U32 mURLOpenExternally;
+	//This is a flag that tells if the url needs to open externally dispite 
+	//what the user setting is.
+	
+	// does this notification persist across sessions? if so, it will be
+	// serialized to disk on first receipt and read on startup
+	bool mPersist;
+	// This is the name of the default functor, if present, to be
+	// used for the notification's callback. It is optional, and used only if 
+	// the notification is constructed without an identified functor.
+	std::string mDefaultFunctor;
+	// The form data associated with a given notification (buttons, text boxes, etc)
+    LLNotificationFormPtr mForm;
+	// default priority for notifications of this type
+	ENotificationPriority mPriority;
+	// UUID of the audio file to be played when this notification arrives
+	// this is loaded as a name, but looked up to get the UUID upon template load.
+	// If null, it wasn't specified.
+	LLUUID mSoundEffect;
+};
+
+// we want to keep a map of these by name, and it's best to manage them
+// with smart pointers
+typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
+
+/**
+ * @class LLNotification
+ * @brief The object that expresses the details of a notification
+ * 
+ * We make this noncopyable because
+ * we want to manage these through LLNotificationPtr, and only
+ * ever create one instance of any given notification.
+ * 
+ * The enable_shared_from_this flag ensures that if we construct
+ * a smart pointer from a notification, we'll always get the same
+ * shared pointer.
+ */
+class LLNotification  : 
+	boost::noncopyable,
+	public boost::enable_shared_from_this<LLNotification>
+{
+LOG_CLASS(LLNotification);
+friend class LLNotifications;
+
+public:
+	// parameter object used to instantiate a new notification
+	struct Params : public LLInitParam::Block<Params>
+	{
+		friend class LLNotification;
+	
+		Mandatory<std::string>					name;
+
+		// optional
+		Optional<LLSD>							substitutions;
+		Optional<LLSD>							payload;
+		Optional<ENotificationPriority>			priority;
+		Optional<LLSD>							form_elements;
+		Optional<LLDate>						timestamp;
+		Optional<LLNotificationContext*>		context;
+
+		struct Functor : public LLInitParam::Choice<Functor>
+		{
+			Alternative<std::string>										name;
+			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
+
+			Functor()
+			:	name("functor_name"),
+				function("functor")
+			{}
+		};
+		Optional<Functor>						functor;
+
+		Params()
+		:	name("name"),
+			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+			timestamp("time_stamp")
+		{
+			timestamp = LLDate::now();
+		}
+
+		Params(const std::string& _name) 
+			:	name("name"),
+				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+				timestamp("time_stamp")
+		{
+			functor.name = _name;
+			name = _name;
+			timestamp = LLDate::now();
+		}
+	};
+
+private:
+	
+	LLUUID mId;
+	LLSD mPayload;
+	LLSD mSubstitutions;
+	LLDate mTimestamp;
+	LLDate mExpiresAt;
+	bool mCancelled;
+	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
+	bool mIgnored;
+	ENotificationPriority mPriority;
+	LLNotificationFormPtr mForm;
+	
+	// a reference to the template
+	LLNotificationTemplatePtr mTemplatep;
+	
+	/*
+	 We want to be able to store and reload notifications so that they can survive
+	 a shutdown/restart of the client. So we can't simply pass in callbacks;
+	 we have to specify a callback mechanism that can be used by name rather than 
+	 by some arbitrary pointer -- and then people have to initialize callbacks 
+	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
+	 */
+	 std::string mResponseFunctorName;
+	
+	/*
+	 In cases where we want to specify an explict, non-persisted callback, 
+	 we store that in the callback registry under a dynamically generated
+	 key, and store the key in the notification, so we can still look it up
+	 using the same mechanism.
+	 */
+	bool mTemporaryResponder;
+
+	void init(const std::string& template_name, const LLSD& form_elements);
+
+	LLNotification(const Params& p);
+
+	// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
+	// for anything real!
+	LLNotification(LLUUID uuid) : mId(uuid) {}
+
+	void cancel();
+
+	bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
+
+public:
+
+	// constructor from a saved notification
+	LLNotification(const LLSD& sd);
+
+	void setResponseFunctor(std::string const &responseFunctorName);
+
+	typedef enum e_response_template_type
+	{
+		WITHOUT_DEFAULT_BUTTON,
+		WITH_DEFAULT_BUTTON
+	} EResponseTemplateType;
+
+	// return response LLSD filled in with default form contents and (optionally) the default button selected
+	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
+
+	// returns index of first button with value==TRUE
+	// usually this the button the user clicked on
+	// returns -1 if no button clicked (e.g. form has not been displayed)
+	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
+	// returns name of first button with value==TRUE
+	static std::string getSelectedOptionName(const LLSD& notification);
+
+	// after someone responds to a notification (usually by clicking a button,
+	// but sometimes by filling out a little form and THEN clicking a button),
+    // the result of the response (the name and value of the button clicked,
+	// plus any other data) should be packaged up as LLSD, then passed as a
+	// parameter to the notification's respond() method here. This will look up
+	// and call the appropriate responder.
+	//
+	// response is notification serialized as LLSD:
+	// ["name"] = notification name
+	// ["form"] = LLSD tree that includes form description and any prefilled form data
+	// ["response"] = form data filled in by user
+	// (including, but not limited to which button they clicked on)
+	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
+	//				["item_id"] (attached inventory item), etc.
+	// ["substitutions"] = string substitutions used to generate notification message
+    // from the template
+	// ["time"] = time at which notification was generated;
+	// ["expiry"] = time at which notification expires;
+	// ["responseFunctor"] = name of registered functor that handles responses to notification;
+	LLSD asLLSD();
+
+	void respond(const LLSD& sd);
+
+	void setIgnored(bool ignore);
+
+	bool isCancelled() const
+	{
+		return mCancelled;
+	}
+
+	bool isRespondedTo() const
+	{
+		return mRespondedTo;
+	}
+
+	bool isIgnored() const
+	{
+		return mIgnored;
+	}
+
+	const std::string& getName() const
+	{
+		return mTemplatep->mName;
+	}
+	
+	const LLUUID& id() const
+	{
+		return mId;
+	}
+	
+	const LLSD& getPayload() const
+	{
+		return mPayload;
+	}
+
+	const LLSD& getSubstitutions() const
+	{
+		return mSubstitutions;
+	}
+
+	const LLDate& getDate() const
+	{
+		return mTimestamp;
+	}
+
+	std::string getType() const
+	{
+		return (mTemplatep ? mTemplatep->mType : "");
+	}
+
+	std::string getMessage() const;
+	std::string getLabel() const;
+
+	std::string getURL() const;
+//	{
+//		return (mTemplatep ? mTemplatep->mURL : "");
+//	}
+
+	S32 getURLOption() const
+	{
+		return (mTemplatep ? mTemplatep->mURLOption : -1);
+	}
+    
+	S32 getURLOpenExternally() const
+	{
+		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
+	}
+	
+	const LLNotificationFormPtr getForm();
+
+	const LLDate getExpiration() const
+	{
+		return mExpiresAt;
+	}
+
+	ENotificationPriority getPriority() const
+	{
+		return mPriority;
+	}
+
+	const LLUUID getID() const
+	{
+		return mId;
+	}
+	
+	// comparing two notifications normally means comparing them by UUID (so we can look them
+	// up quickly this way)
+	bool operator<(const LLNotification& rhs) const
+	{
+		return mId < rhs.mId;
+	}
+
+	bool operator==(const LLNotification& rhs) const
+	{
+		return mId == rhs.mId;
+	}
+
+	bool operator!=(const LLNotification& rhs) const
+	{
+		return !operator==(rhs);
+	}
+
+	bool isSameObjectAs(const LLNotification* rhs) const
+	{
+		return this == rhs;
+	}
+	
+	// this object has been updated, so tell all our clients
+	void update();
+
+	void updateFrom(LLNotificationPtr other);
+	
+	// A fuzzy equals comparator.
+	// true only if both notifications have the same template and 
+	//     1) flagged as unique (there can be only one of these) OR 
+	//     2) all required payload fields of each also exist in the other.
+	bool isEquivalentTo(LLNotificationPtr that) const;
+	
+	// if the current time is greater than the expiration, the notification is expired
+	bool isExpired() const
+	{
+		if (mExpiresAt.secondsSinceEpoch() == 0)
+		{
+			return false;
+		}
+		
+		LLDate rightnow = LLDate::now();
+		return rightnow > mExpiresAt;
+	}
+	
+	std::string summarize() const;
+
+	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
+
+	virtual ~LLNotification() {}
+};
+
+std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
+
+namespace LLNotificationFilters
+{
+	// a sample filter
+	bool includeEverything(LLNotificationPtr p);
+
+	typedef enum e_comparison 
+	{ 
+		EQUAL, 
+		LESS, 
+		GREATER, 
+		LESS_EQUAL, 
+		GREATER_EQUAL 
+	} EComparison;
+
+	// generic filter functor that takes method or member variable reference
+	template<typename T>
+	struct filterBy
+	{
+		typedef boost::function<T (LLNotificationPtr)>	field_t;
+		typedef typename boost::remove_reference<T>::type		value_t;
+		
+		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
+			:	mField(field), 
+				mFilterValue(value),
+				mComparison(comparison)
+		{
+		}		
+		
+		bool operator()(LLNotificationPtr p)
+		{
+			switch(mComparison)
+			{
+			case EQUAL:
+				return mField(p) == mFilterValue;
+			case LESS:
+				return mField(p) < mFilterValue;
+			case GREATER:
+				return mField(p) > mFilterValue;
+			case LESS_EQUAL:
+				return mField(p) <= mFilterValue;
+			case GREATER_EQUAL:
+				return mField(p) >= mFilterValue;
+			default:
+				return false;
+			}
+		}
+
+		field_t mField;
+		value_t	mFilterValue;
+		EComparison mComparison;
+	};
+};
+
+namespace LLNotificationComparators
+{
+	typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
+
+	// generic order functor that takes method or member variable reference
+	template<typename T>
+	struct orderBy
+	{
+		typedef boost::function<T (LLNotificationPtr)> field_t;
+		orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
+		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
+		{
+			if (mDirection == ORDER_DECREASING)
+			{
+				return mField(lhs) > mField(rhs);
+			}
+			else
+			{
+				return mField(lhs) < mField(rhs);
+			}
+		}
+
+		field_t mField;
+		EDirection mDirection;
+	};
+
+	struct orderByUUID : public orderBy<const LLUUID&>
+	{
+		orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
+	};
+
+	struct orderByDate : public orderBy<const LLDate&>
+	{
+		orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
+	};
+};
+
+typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
+typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
+typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
+typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
+
+// ========================================================
+// Abstract base class (interface) for a channel; also used for the master container.
+// This lets us arrange channels into a call hierarchy.
+
+// We maintain a heirarchy of notification channels; events are always started at the top
+// and propagated through the hierarchy only if they pass a filter.
+// Any channel can be created with a parent. A null parent (empty string) means it's
+// tied to the root of the tree (the LLNotifications class itself).
+// The default hierarchy looks like this:
+//
+// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
+//                                                                          +-- Alerts
+//                                                                          +-- Notifications
+//
+// In general, new channels that want to only see notifications that pass through 
+// all of the built-in tests should attach to the "Visible" channel
+//
+class LLNotificationChannelBase :
+	public LLEventTrackable
+{
+	LOG_CLASS(LLNotificationChannelBase);
+public:
+	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
+		mFilter(filter), mItems(comp) 
+	{}
+	virtual ~LLNotificationChannelBase() {}
+	// you can also connect to a Channel, so you can be notified of
+	// changes to this channel
+	template <typename LISTENER>
+    LLBoundListener connectChanged(const LISTENER& slot)
+    {
+        // Examine slot to see if it binds an LLEventTrackable subclass, or a
+        // boost::shared_ptr to something, or a boost::weak_ptr to something.
+        // Call this->connectChangedImpl() to actually connect it.
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectPassedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectFailedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
+                                              this,
+                                              _1));
+    }
+
+	// use this when items change or to add a new one
+	bool updateItem(const LLSD& payload);
+	const LLNotificationFilter& getFilter() { return mFilter; }
+
+protected:
+    LLBoundListener connectChangedImpl(const LLEventListener& slot);
+    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
+    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
+
+	LLNotificationSet mItems;
+	LLStandardSignal mChanged;
+	LLStandardSignal mPassedFilter;
+	LLStandardSignal mFailedFilter;
+	
+	// these are action methods that subclasses can override to take action 
+	// on specific types of changes; the management of the mItems list is
+	// still handled by the generic handler.
+	virtual void onLoad(LLNotificationPtr p) {}
+	virtual void onAdd(LLNotificationPtr p) {}
+	virtual void onDelete(LLNotificationPtr p) {}
+	virtual void onChange(LLNotificationPtr p) {}
+
+	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
+	LLNotificationFilter mFilter;
+};
+
+// The type of the pointers that we're going to manage in the NotificationQueue system
+// Because LLNotifications is a singleton, we don't actually expect to ever 
+// destroy it, but if it becomes necessary to do so, the shared_ptr model
+// will ensure that we don't leak resources.
+class LLNotificationChannel;
+typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
+
+// manages a list of notifications
+// Note that if this is ever copied around, we might find ourselves with multiple copies
+// of a queue with notifications being added to different nonequivalent copies. So we 
+// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
+// 
+// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
+// do something like:
+//		LLNotificationChannel::buildChannel("name", "parent"...);
+// This returns an LLNotificationChannelPtr, which you can store, or
+// you can then retrieve the channel by using the registry:
+//		LLNotifications::instance().getChannel("name")...
+//
+class LLNotificationChannel : 
+	boost::noncopyable, 
+	public LLNotificationChannelBase
+{
+	LOG_CLASS(LLNotificationChannel);
+
+public:  
+	virtual ~LLNotificationChannel() {}
+	typedef LLNotificationSet::iterator Iterator;
+    
+	std::string getName() const { return mName; }
+	std::string getParentChannelName() { return mParent; }
+    
+    bool isEmpty() const;
+    
+    Iterator begin();
+    Iterator end();
+
+    // Channels have a comparator to control sort order;
+	// the default sorts by arrival date
+    void setComparator(LLNotificationComparator comparator);
+	
+	std::string summarize();
+
+	// factory method for constructing these channels; since they're self-registering,
+	// we want to make sure that you can't use new to make them
+	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
+						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
+						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
+	
+protected:
+    // Notification Channels have a filter, which determines which notifications
+	// will be added to this channel. 
+	// Channel filters cannot change.
+	// Channels have a protected constructor so you can't make smart pointers that don't 
+	// come from our internal reference; call NotificationChannel::build(args)
+	LLNotificationChannel(const std::string& name, const std::string& parent,
+						  LLNotificationFilter filter, LLNotificationComparator comparator);
+
+private:
+	std::string mName;
+	std::string mParent;
+	LLNotificationComparator mComparator;
+};
+
+
+class LLNotificationsListener;
+
+class LLNotifications : 
+	public LLSingleton<LLNotifications>, 
+	public LLNotificationChannelBase
+{
+	LOG_CLASS(LLNotifications);
+
+	friend class LLSingleton<LLNotifications>;
+public:
+	// load notification descriptions from file; 
+	// OK to call more than once because it will reload
+	bool loadTemplates();  
+	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
+	
+	// Add a simple notification (from XUI)
+	void addFromCallback(const LLSD& name);
+	
+	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions = LLSD(), 
+						const LLSD& payload = LLSD());
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						const std::string& functor_name);
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						LLNotificationFunctorRegistry::ResponseFunctor functor);
+	LLNotificationPtr add(const LLNotification::Params& p);
+
+	void add(const LLNotificationPtr pNotif);
+	void cancel(LLNotificationPtr pNotif);
+	void update(const LLNotificationPtr pNotif);
+
+	LLNotificationPtr find(LLUUID uuid);
+	
+	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
+	
+	void forEachNotification(NotificationProcess process);
+
+	// This is all stuff for managing the templates
+	// take your template out
+	LLNotificationTemplatePtr getTemplate(const std::string& name);
+	
+	// get the whole collection
+	typedef std::vector<std::string> TemplateNames;
+	TemplateNames getTemplateNames() const;  // returns a list of notification names
+	
+	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
+
+	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
+	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
+
+	// test for existence
+	bool templateExists(const std::string& name);
+	// useful if you're reloading the file
+	void clearTemplates();   // erase all templates
+
+	void forceResponse(const LLNotification::Params& params, S32 option);
+
+	void createDefaultChannels();
+
+	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
+	ChannelMap mChannels;
+
+	void addChannel(LLNotificationChannelPtr pChan);
+	LLNotificationChannelPtr getChannel(const std::string& channelName);
+	
+	std::string getGlobalString(const std::string& key) const;
+
+	void setIgnoreAllNotifications(bool ignore);
+	bool getIgnoreAllNotifications();
+
+private:
+	// we're a singleton, so we don't have a public constructor
+	LLNotifications();
+	/*virtual*/ void initSingleton();
+	
+	void loadPersistentNotifications();
+
+	bool expirationFilter(LLNotificationPtr pNotification);
+	bool expirationHandler(const LLSD& payload);
+	bool uniqueFilter(LLNotificationPtr pNotification);
+	bool uniqueHandler(const LLSD& payload);
+	bool failedUniquenessTest(const LLSD& payload);
+	LLNotificationChannelPtr pHistoryChannel;
+	LLNotificationChannelPtr pExpirationChannel;
+	
+	// put your template in
+	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
+	TemplateMap mTemplates;
+
+	std::string mFileName;
+	
+	typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
+	XMLTemplateMap mXmlTemplates;
+
+	LLNotificationMap mUniqueNotifications;
+	
+	typedef std::map<std::string, std::string> GlobalStringMap;
+	GlobalStringMap mGlobalStrings;
+
+	bool mIgnoreAllNotifications;
+
+    boost::scoped_ptr<LLNotificationsListener> mListener;
+};
+
+
+#endif//LL_LLNOTIFICATIONS_H
+
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
new file mode 100644
index 0000000000..d2d83bd6e3
--- /dev/null
+++ b/indra/llui/llnotificationslistener.cpp
@@ -0,0 +1,28 @@
+/**
+ * @file   llnotificationslistener.cpp
+ * @author Brad Kittenbrink
+ * @date   2009-07-08
+ * @brief  Implementation for llnotificationslistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llnotificationslistener.h"
+
+#include "llnotifications.h"
+
+LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
+    LLDispatchListener("LLNotifications", "op"),
+    mNotifications(notifications)
+{
+    add("requestAdd", &LLNotificationsListener::requestAdd);
+}
+
+void LLNotificationsListener::requestAdd(const LLSD& event_data) const
+{
+    mNotifications.add(event_data["name"], event_data["substitutions"], event_data["payload"]);
+}
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
new file mode 100644
index 0000000000..a163b00550
--- /dev/null
+++ b/indra/llui/llnotificationslistener.h
@@ -0,0 +1,31 @@
+/**
+ * @file   llnotificationslistener.h
+ * @author Brad Kittenbrink
+ * @date   2009-07-08
+ * @brief  Wrap subset of LLNotifications API in event API for test scripts.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLNOTIFICATIONSLISTENER_H
+#define LL_LLNOTIFICATIONSLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLNotifications;
+class LLSD;
+
+class LLNotificationsListener : public LLDispatchListener
+{
+public:
+    LLNotificationsListener(LLNotifications & notifications);
+
+    void requestAdd(LLSD const & event_data) const;
+
+private:
+    LLNotifications & mNotifications;
+};
+
+#endif // LL_LLNOTIFICATIONSLISTENER_H
-- 
cgit v1.2.3


From bc852ca9276e19ce6cb75d189d58d783a7df5e6f Mon Sep 17 00:00:00 2001
From: "palmer@945battery-guestB-224.lindenlab.com"
 <palmer@945battery-guestB-224.lindenlab.com>
Date: Thu, 9 Jul 2009 16:18:04 -0700
Subject: Line ending changes and Build Params changes from login-api-svn-1

---
 indra/llui/llnotificationslistener.cpp | 12 ++++++------
 indra/llui/llnotificationslistener.h   | 32 ++++++++++++++++----------------
 2 files changed, 22 insertions(+), 22 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index d2d83bd6e3..d6e552ca5c 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -14,12 +14,12 @@
 #include "llnotificationslistener.h"
 
 #include "llnotifications.h"
-
-LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
-    LLDispatchListener("LLNotifications", "op"),
-    mNotifications(notifications)
-{
-    add("requestAdd", &LLNotificationsListener::requestAdd);
+
+LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) :
+    LLDispatchListener("LLNotifications", "op"),
+    mNotifications(notifications)
+{
+    add("requestAdd", &LLNotificationsListener::requestAdd);
 }
 
 void LLNotificationsListener::requestAdd(const LLSD& event_data) const
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
index a163b00550..3576cacbdb 100644
--- a/indra/llui/llnotificationslistener.h
+++ b/indra/llui/llnotificationslistener.h
@@ -13,19 +13,19 @@
 #define LL_LLNOTIFICATIONSLISTENER_H
 
 #include "lleventdispatcher.h"
-
-class LLNotifications;
-class LLSD;
-
-class LLNotificationsListener : public LLDispatchListener
-{
-public:
-    LLNotificationsListener(LLNotifications & notifications);
-
-    void requestAdd(LLSD const & event_data) const;
-
-private:
-    LLNotifications & mNotifications;
-};
-
-#endif // LL_LLNOTIFICATIONSLISTENER_H
+
+class LLNotifications;
+class LLSD;
+
+class LLNotificationsListener : public LLDispatchListener
+{
+public:
+    LLNotificationsListener(LLNotifications & notifications);
+
+    void requestAdd(LLSD const & event_data) const;
+
+private:
+    LLNotifications & mNotifications;
+};
+
+#endif // LL_LLNOTIFICATIONSLISTENER_H
-- 
cgit v1.2.3


From 61c27f2663aee60ba6eaeed57341915c8b8b5097 Mon Sep 17 00:00:00 2001
From: brad kittenbrink <brad@lindenlab.com>
Date: Wed, 15 Jul 2009 17:54:11 -0700
Subject: Oops, LLNotificationsListener can't just be forward declared under
 gcc.

---
 indra/llui/llnotifications.h | 1825 +++++++++++++++++++++---------------------
 1 file changed, 912 insertions(+), 913 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 971d11db97..93cdcbeefd 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -1,913 +1,912 @@
-/**
-* @file llnotifications.h
-* @brief Non-UI manager and support for keeping a prioritized list of notifications
-* @author Q (with assistance from Richard and Coco)
-*
-* $LicenseInfo:firstyear=2008&license=viewergpl$
-* 
-* Copyright (c) 2008-2009, Linden Research, Inc.
-* 
-* Second Life Viewer Source Code
-* The source code in this file ("Source Code") is provided by Linden Lab
-* to you under the terms of the GNU General Public License, version 2.0
-* ("GPL"), unless you have obtained a separate licensing agreement
-* ("Other License"), formally executed by you and Linden Lab.  Terms of
-* the GPL can be found in doc/GPL-license.txt in this distribution, or
-* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
-* 
-* There are special exceptions to the terms and conditions of the GPL as
-* it is applied to this Source Code. View the full text of the exception
-* in the file doc/FLOSS-exception.txt in this software distribution, or
-* online at
-* http://secondlifegrid.net/programs/open_source/licensing/flossexception
-* 
-* By copying, modifying or distributing this software, you acknowledge
-* that you have read and understood your obligations described above,
-* and agree to abide by those obligations.
-* 
-* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-* COMPLETENESS OR PERFORMANCE.
-* $/LicenseInfo$
-*/
-
-#ifndef LL_LLNOTIFICATIONS_H
-#define LL_LLNOTIFICATIONS_H
-
-/**
- * This system is intended to provide a singleton mechanism for adding
- * notifications to one of an arbitrary set of event channels.
- * 
- * Controlling JIRA: DEV-9061
- *
- * Every notification has (see code for full list):
- *  - a textual name, which is used to look up its template in the XML files
- *  - a payload, which is a block of LLSD
- *  - a channel, which is normally extracted from the XML files but
- *	  can be overridden.
- *  - a timestamp, used to order the notifications
- *  - expiration time -- if nonzero, specifies a time after which the
- *    notification will no longer be valid.
- *  - a callback name and a couple of status bits related to callbacks (see below)
- * 
- * There is a management class called LLNotifications, which is an LLSingleton.
- * The class maintains a collection of all of the notifications received
- * or processed during this session, and also manages the persistence
- * of those notifications that must be persisted.
- * 
- * We also have Channels. A channel is a view on a collection of notifications;
- * The collection is defined by a filter function that controls which
- * notifications are in the channel, and its ordering is controlled by 
- * a comparator. 
- *
- * There is a hierarchy of channels; notifications flow down from
- * the management class (LLNotifications, which itself inherits from
- * The channel base class) to the individual channels.
- * Any change to notifications (add, delete, modify) is 
- * automatically propagated through the channel hierarchy.
- * 
- * We provide methods for adding a new notification, for removing
- * one, and for managing channels. Channels are relatively cheap to construct
- * and maintain, so in general, human interfaces should use channels to
- * select and manage their lists of notifications.
- * 
- * We also maintain a collection of templates that are loaded from the 
- * XML file of template translations. The system supports substitution
- * of named variables from the payload into the XML file.
- * 
- * By default, only the "unknown message" template is built into the system.
- * It is not an error to add a notification that's not found in the 
- * template system, but it is logged.
- *
- */
-
-#include <string>
-#include <list>
-#include <vector>
-#include <map>
-#include <set>
-#include <iomanip>
-#include <sstream>
-
-#include <boost/utility.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <boost/type_traits.hpp>
-
-// we want to minimize external dependencies, but this one is important
-#include "llsd.h"
-
-// and we need this to manage the notification callbacks
-#include "llevents.h"
-#include "llfunctorregistry.h"
-#include "llui.h"
-#include "llmemory.h"
-
-class LLNotification;
-typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
-
-	
-typedef enum e_notification_priority
-{
-	NOTIFICATION_PRIORITY_UNSPECIFIED,
-	NOTIFICATION_PRIORITY_LOW,
-	NOTIFICATION_PRIORITY_NORMAL,
-	NOTIFICATION_PRIORITY_HIGH,
-	NOTIFICATION_PRIORITY_CRITICAL
-} ENotificationPriority;
-
-typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
-
-typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
-typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
-
-// context data that can be looked up via a notification's payload by the display logic
-// derive from this class to implement specific contexts
-class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
-{
-public:
-	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
-	{
-	}
-
-	virtual ~LLNotificationContext() {}
-
-	LLSD asLLSD() const
-	{
-		return getKey();
-	}
-
-private:
-
-};
-
-// Contains notification form data, such as buttons and text fields along with
-// manipulator functions
-class LLNotificationForm
-{
-	LOG_CLASS(LLNotificationForm);
-
-public:
-	typedef enum e_ignore_type
-	{ 
-		IGNORE_NO,
-		IGNORE_WITH_DEFAULT_RESPONSE, 
-		IGNORE_WITH_LAST_RESPONSE, 
-		IGNORE_SHOW_AGAIN 
-	} EIgnoreType;
-
-	LLNotificationForm();
-	LLNotificationForm(const LLSD& sd);
-	LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
-
-	LLSD asLLSD() const;
-
-	S32 getNumElements() { return mFormData.size(); }
-	LLSD getElement(S32 index) { return mFormData.get(index); }
-	LLSD getElement(const std::string& element_name);
-	bool hasElement(const std::string& element_name);
-	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
-	void formatElements(const LLSD& substitutions);
-	// appends form elements from another form serialized as LLSD
-	void append(const LLSD& sub_form);
-	std::string getDefaultOption();
-
-	EIgnoreType getIgnoreType() { return mIgnore; }
-	std::string getIgnoreMessage() { return mIgnoreMsg; }
-
-private:
-	LLSD	mFormData;
-	EIgnoreType mIgnore;
-	std::string mIgnoreMsg;
-};
-
-typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
-
-// This is the class of object read from the XML file (notifications.xml, 
-// from the appropriate local language directory).
-struct LLNotificationTemplate
-{
-	LLNotificationTemplate();
-    // the name of the notification -- the key used to identify it
-    // Ideally, the key should follow variable naming rules 
-    // (no spaces or punctuation).
-    std::string mName;
-    // The type of the notification
-    // used to control which queue it's stored in
-    std::string mType;
-    // The text used to display the notification. Replaceable parameters
-    // are enclosed in square brackets like this [].
-    std::string mMessage;
-	// The label for the notification; used for 
-	// certain classes of notification (those with a window and a window title). 
-	// Also used when a notification pops up underneath the current one.
-	// Replaceable parameters can be used in the label.
-	std::string mLabel;
-	// The name of the icon image. This should include an extension.
-	std::string mIcon;
-    // This is the Highlander bit -- "There Can Be Only One"
-    // An outstanding notification with this bit set
-    // is updated by an incoming notification with the same name,
-    // rather than creating a new entry in the queue.
-    // (used for things like progress indications, or repeating warnings
-    // like "the grid is going down in N minutes")
-    bool mUnique;
-    // if we want to be unique only if a certain part of the payload is constant
-    // specify the field names for the payload. The notification will only be
-    // combined if all of the fields named in the context are identical in the
-    // new and the old notification; otherwise, the notification will be
-    // duplicated. This is to support suppressing duplicate offers from the same
-    // sender but still differentiating different offers. Example: Invitation to
-    // conference chat.
-    std::vector<std::string> mUniqueContext;
-    // If this notification expires automatically, this value will be 
-    // nonzero, and indicates the number of seconds for which the notification
-    // will be valid (a teleport offer, for example, might be valid for 
-    // 300 seconds). 
-    U32 mExpireSeconds;
-    // if the offer expires, one of the options is chosen automatically
-    // based on its "value" parameter. This controls which one. 
-    // If expireSeconds is specified, expireOption should also be specified.
-    U32 mExpireOption;
-    // if the notification contains a url, it's stored here (and replaced 
-    // into the message where [_URL] is found)
-    std::string mURL;
-    // if there's a URL in the message, this controls which option visits
-    // that URL. Obsolete this and eliminate the buttons for affected
-    // messages when we allow clickable URLs in the UI
-    U32 mURLOption;
-	
-	U32 mURLOpenExternally;
-	//This is a flag that tells if the url needs to open externally dispite 
-	//what the user setting is.
-	
-	// does this notification persist across sessions? if so, it will be
-	// serialized to disk on first receipt and read on startup
-	bool mPersist;
-	// This is the name of the default functor, if present, to be
-	// used for the notification's callback. It is optional, and used only if 
-	// the notification is constructed without an identified functor.
-	std::string mDefaultFunctor;
-	// The form data associated with a given notification (buttons, text boxes, etc)
-    LLNotificationFormPtr mForm;
-	// default priority for notifications of this type
-	ENotificationPriority mPriority;
-	// UUID of the audio file to be played when this notification arrives
-	// this is loaded as a name, but looked up to get the UUID upon template load.
-	// If null, it wasn't specified.
-	LLUUID mSoundEffect;
-};
-
-// we want to keep a map of these by name, and it's best to manage them
-// with smart pointers
-typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
-
-/**
- * @class LLNotification
- * @brief The object that expresses the details of a notification
- * 
- * We make this noncopyable because
- * we want to manage these through LLNotificationPtr, and only
- * ever create one instance of any given notification.
- * 
- * The enable_shared_from_this flag ensures that if we construct
- * a smart pointer from a notification, we'll always get the same
- * shared pointer.
- */
-class LLNotification  : 
-	boost::noncopyable,
-	public boost::enable_shared_from_this<LLNotification>
-{
-LOG_CLASS(LLNotification);
-friend class LLNotifications;
-
-public:
-	// parameter object used to instantiate a new notification
-	struct Params : public LLInitParam::Block<Params>
-	{
-		friend class LLNotification;
-	
-		Mandatory<std::string>					name;
-
-		// optional
-		Optional<LLSD>							substitutions;
-		Optional<LLSD>							payload;
-		Optional<ENotificationPriority>			priority;
-		Optional<LLSD>							form_elements;
-		Optional<LLDate>						timestamp;
-		Optional<LLNotificationContext*>		context;
-
-		struct Functor : public LLInitParam::Choice<Functor>
-		{
-			Alternative<std::string>										name;
-			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
-
-			Functor()
-			:	name("functor_name"),
-				function("functor")
-			{}
-		};
-		Optional<Functor>						functor;
-
-		Params()
-		:	name("name"),
-			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
-			timestamp("time_stamp")
-		{
-			timestamp = LLDate::now();
-		}
-
-		Params(const std::string& _name) 
-			:	name("name"),
-				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
-				timestamp("time_stamp")
-		{
-			functor.name = _name;
-			name = _name;
-			timestamp = LLDate::now();
-		}
-	};
-
-private:
-	
-	LLUUID mId;
-	LLSD mPayload;
-	LLSD mSubstitutions;
-	LLDate mTimestamp;
-	LLDate mExpiresAt;
-	bool mCancelled;
-	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
-	bool mIgnored;
-	ENotificationPriority mPriority;
-	LLNotificationFormPtr mForm;
-	
-	// a reference to the template
-	LLNotificationTemplatePtr mTemplatep;
-	
-	/*
-	 We want to be able to store and reload notifications so that they can survive
-	 a shutdown/restart of the client. So we can't simply pass in callbacks;
-	 we have to specify a callback mechanism that can be used by name rather than 
-	 by some arbitrary pointer -- and then people have to initialize callbacks 
-	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
-	 */
-	 std::string mResponseFunctorName;
-	
-	/*
-	 In cases where we want to specify an explict, non-persisted callback, 
-	 we store that in the callback registry under a dynamically generated
-	 key, and store the key in the notification, so we can still look it up
-	 using the same mechanism.
-	 */
-	bool mTemporaryResponder;
-
-	void init(const std::string& template_name, const LLSD& form_elements);
-
-	LLNotification(const Params& p);
-
-	// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
-	// for anything real!
-	LLNotification(LLUUID uuid) : mId(uuid) {}
-
-	void cancel();
-
-	bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
-
-public:
-
-	// constructor from a saved notification
-	LLNotification(const LLSD& sd);
-
-	void setResponseFunctor(std::string const &responseFunctorName);
-
-	typedef enum e_response_template_type
-	{
-		WITHOUT_DEFAULT_BUTTON,
-		WITH_DEFAULT_BUTTON
-	} EResponseTemplateType;
-
-	// return response LLSD filled in with default form contents and (optionally) the default button selected
-	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
-
-	// returns index of first button with value==TRUE
-	// usually this the button the user clicked on
-	// returns -1 if no button clicked (e.g. form has not been displayed)
-	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
-	// returns name of first button with value==TRUE
-	static std::string getSelectedOptionName(const LLSD& notification);
-
-	// after someone responds to a notification (usually by clicking a button,
-	// but sometimes by filling out a little form and THEN clicking a button),
-    // the result of the response (the name and value of the button clicked,
-	// plus any other data) should be packaged up as LLSD, then passed as a
-	// parameter to the notification's respond() method here. This will look up
-	// and call the appropriate responder.
-	//
-	// response is notification serialized as LLSD:
-	// ["name"] = notification name
-	// ["form"] = LLSD tree that includes form description and any prefilled form data
-	// ["response"] = form data filled in by user
-	// (including, but not limited to which button they clicked on)
-	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
-	//				["item_id"] (attached inventory item), etc.
-	// ["substitutions"] = string substitutions used to generate notification message
-    // from the template
-	// ["time"] = time at which notification was generated;
-	// ["expiry"] = time at which notification expires;
-	// ["responseFunctor"] = name of registered functor that handles responses to notification;
-	LLSD asLLSD();
-
-	void respond(const LLSD& sd);
-
-	void setIgnored(bool ignore);
-
-	bool isCancelled() const
-	{
-		return mCancelled;
-	}
-
-	bool isRespondedTo() const
-	{
-		return mRespondedTo;
-	}
-
-	bool isIgnored() const
-	{
-		return mIgnored;
-	}
-
-	const std::string& getName() const
-	{
-		return mTemplatep->mName;
-	}
-	
-	const LLUUID& id() const
-	{
-		return mId;
-	}
-	
-	const LLSD& getPayload() const
-	{
-		return mPayload;
-	}
-
-	const LLSD& getSubstitutions() const
-	{
-		return mSubstitutions;
-	}
-
-	const LLDate& getDate() const
-	{
-		return mTimestamp;
-	}
-
-	std::string getType() const
-	{
-		return (mTemplatep ? mTemplatep->mType : "");
-	}
-
-	std::string getMessage() const;
-	std::string getLabel() const;
-
-	std::string getURL() const;
-//	{
-//		return (mTemplatep ? mTemplatep->mURL : "");
-//	}
-
-	S32 getURLOption() const
-	{
-		return (mTemplatep ? mTemplatep->mURLOption : -1);
-	}
-    
-	S32 getURLOpenExternally() const
-	{
-		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
-	}
-	
-	const LLNotificationFormPtr getForm();
-
-	const LLDate getExpiration() const
-	{
-		return mExpiresAt;
-	}
-
-	ENotificationPriority getPriority() const
-	{
-		return mPriority;
-	}
-
-	const LLUUID getID() const
-	{
-		return mId;
-	}
-	
-	// comparing two notifications normally means comparing them by UUID (so we can look them
-	// up quickly this way)
-	bool operator<(const LLNotification& rhs) const
-	{
-		return mId < rhs.mId;
-	}
-
-	bool operator==(const LLNotification& rhs) const
-	{
-		return mId == rhs.mId;
-	}
-
-	bool operator!=(const LLNotification& rhs) const
-	{
-		return !operator==(rhs);
-	}
-
-	bool isSameObjectAs(const LLNotification* rhs) const
-	{
-		return this == rhs;
-	}
-	
-	// this object has been updated, so tell all our clients
-	void update();
-
-	void updateFrom(LLNotificationPtr other);
-	
-	// A fuzzy equals comparator.
-	// true only if both notifications have the same template and 
-	//     1) flagged as unique (there can be only one of these) OR 
-	//     2) all required payload fields of each also exist in the other.
-	bool isEquivalentTo(LLNotificationPtr that) const;
-	
-	// if the current time is greater than the expiration, the notification is expired
-	bool isExpired() const
-	{
-		if (mExpiresAt.secondsSinceEpoch() == 0)
-		{
-			return false;
-		}
-		
-		LLDate rightnow = LLDate::now();
-		return rightnow > mExpiresAt;
-	}
-	
-	std::string summarize() const;
-
-	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
-
-	virtual ~LLNotification() {}
-};
-
-std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
-
-namespace LLNotificationFilters
-{
-	// a sample filter
-	bool includeEverything(LLNotificationPtr p);
-
-	typedef enum e_comparison 
-	{ 
-		EQUAL, 
-		LESS, 
-		GREATER, 
-		LESS_EQUAL, 
-		GREATER_EQUAL 
-	} EComparison;
-
-	// generic filter functor that takes method or member variable reference
-	template<typename T>
-	struct filterBy
-	{
-		typedef boost::function<T (LLNotificationPtr)>	field_t;
-		typedef typename boost::remove_reference<T>::type		value_t;
-		
-		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
-			:	mField(field), 
-				mFilterValue(value),
-				mComparison(comparison)
-		{
-		}		
-		
-		bool operator()(LLNotificationPtr p)
-		{
-			switch(mComparison)
-			{
-			case EQUAL:
-				return mField(p) == mFilterValue;
-			case LESS:
-				return mField(p) < mFilterValue;
-			case GREATER:
-				return mField(p) > mFilterValue;
-			case LESS_EQUAL:
-				return mField(p) <= mFilterValue;
-			case GREATER_EQUAL:
-				return mField(p) >= mFilterValue;
-			default:
-				return false;
-			}
-		}
-
-		field_t mField;
-		value_t	mFilterValue;
-		EComparison mComparison;
-	};
-};
-
-namespace LLNotificationComparators
-{
-	typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
-
-	// generic order functor that takes method or member variable reference
-	template<typename T>
-	struct orderBy
-	{
-		typedef boost::function<T (LLNotificationPtr)> field_t;
-		orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
-		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
-		{
-			if (mDirection == ORDER_DECREASING)
-			{
-				return mField(lhs) > mField(rhs);
-			}
-			else
-			{
-				return mField(lhs) < mField(rhs);
-			}
-		}
-
-		field_t mField;
-		EDirection mDirection;
-	};
-
-	struct orderByUUID : public orderBy<const LLUUID&>
-	{
-		orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
-	};
-
-	struct orderByDate : public orderBy<const LLDate&>
-	{
-		orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
-	};
-};
-
-typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
-typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
-typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
-typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
-
-// ========================================================
-// Abstract base class (interface) for a channel; also used for the master container.
-// This lets us arrange channels into a call hierarchy.
-
-// We maintain a heirarchy of notification channels; events are always started at the top
-// and propagated through the hierarchy only if they pass a filter.
-// Any channel can be created with a parent. A null parent (empty string) means it's
-// tied to the root of the tree (the LLNotifications class itself).
-// The default hierarchy looks like this:
-//
-// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
-//                                                                          +-- Alerts
-//                                                                          +-- Notifications
-//
-// In general, new channels that want to only see notifications that pass through 
-// all of the built-in tests should attach to the "Visible" channel
-//
-class LLNotificationChannelBase :
-	public LLEventTrackable
-{
-	LOG_CLASS(LLNotificationChannelBase);
-public:
-	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
-		mFilter(filter), mItems(comp) 
-	{}
-	virtual ~LLNotificationChannelBase() {}
-	// you can also connect to a Channel, so you can be notified of
-	// changes to this channel
-	template <typename LISTENER>
-    LLBoundListener connectChanged(const LISTENER& slot)
-    {
-        // Examine slot to see if it binds an LLEventTrackable subclass, or a
-        // boost::shared_ptr to something, or a boost::weak_ptr to something.
-        // Call this->connectChangedImpl() to actually connect it.
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
-                                              this,
-                                              _1));
-    }
-    template <typename LISTENER>
-	LLBoundListener connectPassedFilter(const LISTENER& slot)
-    {
-        // see comments in connectChanged()
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
-                                              this,
-                                              _1));
-    }
-    template <typename LISTENER>
-	LLBoundListener connectFailedFilter(const LISTENER& slot)
-    {
-        // see comments in connectChanged()
-        return LLEventDetail::visit_and_connect(slot,
-                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
-                                              this,
-                                              _1));
-    }
-
-	// use this when items change or to add a new one
-	bool updateItem(const LLSD& payload);
-	const LLNotificationFilter& getFilter() { return mFilter; }
-
-protected:
-    LLBoundListener connectChangedImpl(const LLEventListener& slot);
-    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
-    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
-
-	LLNotificationSet mItems;
-	LLStandardSignal mChanged;
-	LLStandardSignal mPassedFilter;
-	LLStandardSignal mFailedFilter;
-	
-	// these are action methods that subclasses can override to take action 
-	// on specific types of changes; the management of the mItems list is
-	// still handled by the generic handler.
-	virtual void onLoad(LLNotificationPtr p) {}
-	virtual void onAdd(LLNotificationPtr p) {}
-	virtual void onDelete(LLNotificationPtr p) {}
-	virtual void onChange(LLNotificationPtr p) {}
-
-	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
-	LLNotificationFilter mFilter;
-};
-
-// The type of the pointers that we're going to manage in the NotificationQueue system
-// Because LLNotifications is a singleton, we don't actually expect to ever 
-// destroy it, but if it becomes necessary to do so, the shared_ptr model
-// will ensure that we don't leak resources.
-class LLNotificationChannel;
-typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
-
-// manages a list of notifications
-// Note that if this is ever copied around, we might find ourselves with multiple copies
-// of a queue with notifications being added to different nonequivalent copies. So we 
-// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
-// 
-// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
-// do something like:
-//		LLNotificationChannel::buildChannel("name", "parent"...);
-// This returns an LLNotificationChannelPtr, which you can store, or
-// you can then retrieve the channel by using the registry:
-//		LLNotifications::instance().getChannel("name")...
-//
-class LLNotificationChannel : 
-	boost::noncopyable, 
-	public LLNotificationChannelBase
-{
-	LOG_CLASS(LLNotificationChannel);
-
-public:  
-	virtual ~LLNotificationChannel() {}
-	typedef LLNotificationSet::iterator Iterator;
-    
-	std::string getName() const { return mName; }
-	std::string getParentChannelName() { return mParent; }
-    
-    bool isEmpty() const;
-    
-    Iterator begin();
-    Iterator end();
-
-    // Channels have a comparator to control sort order;
-	// the default sorts by arrival date
-    void setComparator(LLNotificationComparator comparator);
-	
-	std::string summarize();
-
-	// factory method for constructing these channels; since they're self-registering,
-	// we want to make sure that you can't use new to make them
-	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
-						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
-						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
-	
-protected:
-    // Notification Channels have a filter, which determines which notifications
-	// will be added to this channel. 
-	// Channel filters cannot change.
-	// Channels have a protected constructor so you can't make smart pointers that don't 
-	// come from our internal reference; call NotificationChannel::build(args)
-	LLNotificationChannel(const std::string& name, const std::string& parent,
-						  LLNotificationFilter filter, LLNotificationComparator comparator);
-
-private:
-	std::string mName;
-	std::string mParent;
-	LLNotificationComparator mComparator;
-};
-
-
-class LLNotificationsListener;
-
-class LLNotifications : 
-	public LLSingleton<LLNotifications>, 
-	public LLNotificationChannelBase
-{
-	LOG_CLASS(LLNotifications);
-
-	friend class LLSingleton<LLNotifications>;
-public:
-	// load notification descriptions from file; 
-	// OK to call more than once because it will reload
-	bool loadTemplates();  
-	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
-	
-	// Add a simple notification (from XUI)
-	void addFromCallback(const LLSD& name);
-	
-	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions = LLSD(), 
-						const LLSD& payload = LLSD());
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions, 
-						const LLSD& payload, 
-						const std::string& functor_name);
-	LLNotificationPtr add(const std::string& name, 
-						const LLSD& substitutions, 
-						const LLSD& payload, 
-						LLNotificationFunctorRegistry::ResponseFunctor functor);
-	LLNotificationPtr add(const LLNotification::Params& p);
-
-	void add(const LLNotificationPtr pNotif);
-	void cancel(LLNotificationPtr pNotif);
-	void update(const LLNotificationPtr pNotif);
-
-	LLNotificationPtr find(LLUUID uuid);
-	
-	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
-	
-	void forEachNotification(NotificationProcess process);
-
-	// This is all stuff for managing the templates
-	// take your template out
-	LLNotificationTemplatePtr getTemplate(const std::string& name);
-	
-	// get the whole collection
-	typedef std::vector<std::string> TemplateNames;
-	TemplateNames getTemplateNames() const;  // returns a list of notification names
-	
-	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
-
-	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
-	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
-
-	// test for existence
-	bool templateExists(const std::string& name);
-	// useful if you're reloading the file
-	void clearTemplates();   // erase all templates
-
-	void forceResponse(const LLNotification::Params& params, S32 option);
-
-	void createDefaultChannels();
-
-	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
-	ChannelMap mChannels;
-
-	void addChannel(LLNotificationChannelPtr pChan);
-	LLNotificationChannelPtr getChannel(const std::string& channelName);
-	
-	std::string getGlobalString(const std::string& key) const;
-
-	void setIgnoreAllNotifications(bool ignore);
-	bool getIgnoreAllNotifications();
-
-private:
-	// we're a singleton, so we don't have a public constructor
-	LLNotifications();
-	/*virtual*/ void initSingleton();
-	
-	void loadPersistentNotifications();
-
-	bool expirationFilter(LLNotificationPtr pNotification);
-	bool expirationHandler(const LLSD& payload);
-	bool uniqueFilter(LLNotificationPtr pNotification);
-	bool uniqueHandler(const LLSD& payload);
-	bool failedUniquenessTest(const LLSD& payload);
-	LLNotificationChannelPtr pHistoryChannel;
-	LLNotificationChannelPtr pExpirationChannel;
-	
-	// put your template in
-	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
-	TemplateMap mTemplates;
-
-	std::string mFileName;
-	
-	typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
-	XMLTemplateMap mXmlTemplates;
-
-	LLNotificationMap mUniqueNotifications;
-	
-	typedef std::map<std::string, std::string> GlobalStringMap;
-	GlobalStringMap mGlobalStrings;
-
-	bool mIgnoreAllNotifications;
-
-    boost::scoped_ptr<LLNotificationsListener> mListener;
-};
-
-
-#endif//LL_LLNOTIFICATIONS_H
-
+/**
+* @file llnotifications.h
+* @brief Non-UI manager and support for keeping a prioritized list of notifications
+* @author Q (with assistance from Richard and Coco)
+*
+* $LicenseInfo:firstyear=2008&license=viewergpl$
+* 
+* Copyright (c) 2008-2009, Linden Research, Inc.
+* 
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab.  Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+* 
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+* 
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+* 
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#ifndef LL_LLNOTIFICATIONS_H
+#define LL_LLNOTIFICATIONS_H
+
+/**
+ * This system is intended to provide a singleton mechanism for adding
+ * notifications to one of an arbitrary set of event channels.
+ * 
+ * Controlling JIRA: DEV-9061
+ *
+ * Every notification has (see code for full list):
+ *  - a textual name, which is used to look up its template in the XML files
+ *  - a payload, which is a block of LLSD
+ *  - a channel, which is normally extracted from the XML files but
+ *	  can be overridden.
+ *  - a timestamp, used to order the notifications
+ *  - expiration time -- if nonzero, specifies a time after which the
+ *    notification will no longer be valid.
+ *  - a callback name and a couple of status bits related to callbacks (see below)
+ * 
+ * There is a management class called LLNotifications, which is an LLSingleton.
+ * The class maintains a collection of all of the notifications received
+ * or processed during this session, and also manages the persistence
+ * of those notifications that must be persisted.
+ * 
+ * We also have Channels. A channel is a view on a collection of notifications;
+ * The collection is defined by a filter function that controls which
+ * notifications are in the channel, and its ordering is controlled by 
+ * a comparator. 
+ *
+ * There is a hierarchy of channels; notifications flow down from
+ * the management class (LLNotifications, which itself inherits from
+ * The channel base class) to the individual channels.
+ * Any change to notifications (add, delete, modify) is 
+ * automatically propagated through the channel hierarchy.
+ * 
+ * We provide methods for adding a new notification, for removing
+ * one, and for managing channels. Channels are relatively cheap to construct
+ * and maintain, so in general, human interfaces should use channels to
+ * select and manage their lists of notifications.
+ * 
+ * We also maintain a collection of templates that are loaded from the 
+ * XML file of template translations. The system supports substitution
+ * of named variables from the payload into the XML file.
+ * 
+ * By default, only the "unknown message" template is built into the system.
+ * It is not an error to add a notification that's not found in the 
+ * template system, but it is logged.
+ *
+ */
+
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+#include <set>
+#include <iomanip>
+#include <sstream>
+
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/type_traits.hpp>
+
+// we want to minimize external dependencies, but this one is important
+#include "llsd.h"
+
+// and we need this to manage the notification callbacks
+#include "llevents.h"
+#include "llfunctorregistry.h"
+#include "llui.h"
+#include "llmemory.h"
+#include "llnotificationslistener.h"
+
+class LLNotification;
+typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
+
+	
+typedef enum e_notification_priority
+{
+	NOTIFICATION_PRIORITY_UNSPECIFIED,
+	NOTIFICATION_PRIORITY_LOW,
+	NOTIFICATION_PRIORITY_NORMAL,
+	NOTIFICATION_PRIORITY_HIGH,
+	NOTIFICATION_PRIORITY_CRITICAL
+} ENotificationPriority;
+
+typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
+
+typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
+typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
+
+// context data that can be looked up via a notification's payload by the display logic
+// derive from this class to implement specific contexts
+class LLNotificationContext : public LLInstanceTracker<LLNotificationContext, LLUUID>
+{
+public:
+	LLNotificationContext() : LLInstanceTracker<LLNotificationContext, LLUUID>(LLUUID::generateNewID())
+	{
+	}
+
+	virtual ~LLNotificationContext() {}
+
+	LLSD asLLSD() const
+	{
+		return getKey();
+	}
+
+private:
+
+};
+
+// Contains notification form data, such as buttons and text fields along with
+// manipulator functions
+class LLNotificationForm
+{
+	LOG_CLASS(LLNotificationForm);
+
+public:
+	typedef enum e_ignore_type
+	{ 
+		IGNORE_NO,
+		IGNORE_WITH_DEFAULT_RESPONSE, 
+		IGNORE_WITH_LAST_RESPONSE, 
+		IGNORE_SHOW_AGAIN 
+	} EIgnoreType;
+
+	LLNotificationForm();
+	LLNotificationForm(const LLSD& sd);
+	LLNotificationForm(const std::string& name, const LLXMLNodePtr xml_node);
+
+	LLSD asLLSD() const;
+
+	S32 getNumElements() { return mFormData.size(); }
+	LLSD getElement(S32 index) { return mFormData.get(index); }
+	LLSD getElement(const std::string& element_name);
+	bool hasElement(const std::string& element_name);
+	void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
+	void formatElements(const LLSD& substitutions);
+	// appends form elements from another form serialized as LLSD
+	void append(const LLSD& sub_form);
+	std::string getDefaultOption();
+
+	EIgnoreType getIgnoreType() { return mIgnore; }
+	std::string getIgnoreMessage() { return mIgnoreMsg; }
+
+private:
+	LLSD	mFormData;
+	EIgnoreType mIgnore;
+	std::string mIgnoreMsg;
+};
+
+typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
+
+// This is the class of object read from the XML file (notifications.xml, 
+// from the appropriate local language directory).
+struct LLNotificationTemplate
+{
+	LLNotificationTemplate();
+    // the name of the notification -- the key used to identify it
+    // Ideally, the key should follow variable naming rules 
+    // (no spaces or punctuation).
+    std::string mName;
+    // The type of the notification
+    // used to control which queue it's stored in
+    std::string mType;
+    // The text used to display the notification. Replaceable parameters
+    // are enclosed in square brackets like this [].
+    std::string mMessage;
+	// The label for the notification; used for 
+	// certain classes of notification (those with a window and a window title). 
+	// Also used when a notification pops up underneath the current one.
+	// Replaceable parameters can be used in the label.
+	std::string mLabel;
+	// The name of the icon image. This should include an extension.
+	std::string mIcon;
+    // This is the Highlander bit -- "There Can Be Only One"
+    // An outstanding notification with this bit set
+    // is updated by an incoming notification with the same name,
+    // rather than creating a new entry in the queue.
+    // (used for things like progress indications, or repeating warnings
+    // like "the grid is going down in N minutes")
+    bool mUnique;
+    // if we want to be unique only if a certain part of the payload is constant
+    // specify the field names for the payload. The notification will only be
+    // combined if all of the fields named in the context are identical in the
+    // new and the old notification; otherwise, the notification will be
+    // duplicated. This is to support suppressing duplicate offers from the same
+    // sender but still differentiating different offers. Example: Invitation to
+    // conference chat.
+    std::vector<std::string> mUniqueContext;
+    // If this notification expires automatically, this value will be 
+    // nonzero, and indicates the number of seconds for which the notification
+    // will be valid (a teleport offer, for example, might be valid for 
+    // 300 seconds). 
+    U32 mExpireSeconds;
+    // if the offer expires, one of the options is chosen automatically
+    // based on its "value" parameter. This controls which one. 
+    // If expireSeconds is specified, expireOption should also be specified.
+    U32 mExpireOption;
+    // if the notification contains a url, it's stored here (and replaced 
+    // into the message where [_URL] is found)
+    std::string mURL;
+    // if there's a URL in the message, this controls which option visits
+    // that URL. Obsolete this and eliminate the buttons for affected
+    // messages when we allow clickable URLs in the UI
+    U32 mURLOption;
+	
+	U32 mURLOpenExternally;
+	//This is a flag that tells if the url needs to open externally dispite 
+	//what the user setting is.
+	
+	// does this notification persist across sessions? if so, it will be
+	// serialized to disk on first receipt and read on startup
+	bool mPersist;
+	// This is the name of the default functor, if present, to be
+	// used for the notification's callback. It is optional, and used only if 
+	// the notification is constructed without an identified functor.
+	std::string mDefaultFunctor;
+	// The form data associated with a given notification (buttons, text boxes, etc)
+    LLNotificationFormPtr mForm;
+	// default priority for notifications of this type
+	ENotificationPriority mPriority;
+	// UUID of the audio file to be played when this notification arrives
+	// this is loaded as a name, but looked up to get the UUID upon template load.
+	// If null, it wasn't specified.
+	LLUUID mSoundEffect;
+};
+
+// we want to keep a map of these by name, and it's best to manage them
+// with smart pointers
+typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
+
+/**
+ * @class LLNotification
+ * @brief The object that expresses the details of a notification
+ * 
+ * We make this noncopyable because
+ * we want to manage these through LLNotificationPtr, and only
+ * ever create one instance of any given notification.
+ * 
+ * The enable_shared_from_this flag ensures that if we construct
+ * a smart pointer from a notification, we'll always get the same
+ * shared pointer.
+ */
+class LLNotification  : 
+	boost::noncopyable,
+	public boost::enable_shared_from_this<LLNotification>
+{
+LOG_CLASS(LLNotification);
+friend class LLNotifications;
+
+public:
+	// parameter object used to instantiate a new notification
+	struct Params : public LLInitParam::Block<Params>
+	{
+		friend class LLNotification;
+	
+		Mandatory<std::string>					name;
+
+		// optional
+		Optional<LLSD>							substitutions;
+		Optional<LLSD>							payload;
+		Optional<ENotificationPriority>			priority;
+		Optional<LLSD>							form_elements;
+		Optional<LLDate>						timestamp;
+		Optional<LLNotificationContext*>		context;
+
+		struct Functor : public LLInitParam::Choice<Functor>
+		{
+			Alternative<std::string>										name;
+			Alternative<LLNotificationFunctorRegistry::ResponseFunctor>	function;
+
+			Functor()
+			:	name("functor_name"),
+				function("functor")
+			{}
+		};
+		Optional<Functor>						functor;
+
+		Params()
+		:	name("name"),
+			priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+			timestamp("time_stamp")
+		{
+			timestamp = LLDate::now();
+		}
+
+		Params(const std::string& _name) 
+			:	name("name"),
+				priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
+				timestamp("time_stamp")
+		{
+			functor.name = _name;
+			name = _name;
+			timestamp = LLDate::now();
+		}
+	};
+
+private:
+	
+	LLUUID mId;
+	LLSD mPayload;
+	LLSD mSubstitutions;
+	LLDate mTimestamp;
+	LLDate mExpiresAt;
+	bool mCancelled;
+	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
+	bool mIgnored;
+	ENotificationPriority mPriority;
+	LLNotificationFormPtr mForm;
+	
+	// a reference to the template
+	LLNotificationTemplatePtr mTemplatep;
+	
+	/*
+	 We want to be able to store and reload notifications so that they can survive
+	 a shutdown/restart of the client. So we can't simply pass in callbacks;
+	 we have to specify a callback mechanism that can be used by name rather than 
+	 by some arbitrary pointer -- and then people have to initialize callbacks 
+	 in some useful location. So we use LLNotificationFunctorRegistry to manage them.
+	 */
+	 std::string mResponseFunctorName;
+	
+	/*
+	 In cases where we want to specify an explict, non-persisted callback, 
+	 we store that in the callback registry under a dynamically generated
+	 key, and store the key in the notification, so we can still look it up
+	 using the same mechanism.
+	 */
+	bool mTemporaryResponder;
+
+	void init(const std::string& template_name, const LLSD& form_elements);
+
+	LLNotification(const Params& p);
+
+	// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
+	// for anything real!
+	LLNotification(LLUUID uuid) : mId(uuid) {}
+
+	void cancel();
+
+	bool payloadContainsAll(const std::vector<std::string>& required_fields) const;
+
+public:
+
+	// constructor from a saved notification
+	LLNotification(const LLSD& sd);
+
+	void setResponseFunctor(std::string const &responseFunctorName);
+
+	typedef enum e_response_template_type
+	{
+		WITHOUT_DEFAULT_BUTTON,
+		WITH_DEFAULT_BUTTON
+	} EResponseTemplateType;
+
+	// return response LLSD filled in with default form contents and (optionally) the default button selected
+	LLSD getResponseTemplate(EResponseTemplateType type = WITHOUT_DEFAULT_BUTTON);
+
+	// returns index of first button with value==TRUE
+	// usually this the button the user clicked on
+	// returns -1 if no button clicked (e.g. form has not been displayed)
+	static S32 getSelectedOption(const LLSD& notification, const LLSD& response);
+	// returns name of first button with value==TRUE
+	static std::string getSelectedOptionName(const LLSD& notification);
+
+	// after someone responds to a notification (usually by clicking a button,
+	// but sometimes by filling out a little form and THEN clicking a button),
+    // the result of the response (the name and value of the button clicked,
+	// plus any other data) should be packaged up as LLSD, then passed as a
+	// parameter to the notification's respond() method here. This will look up
+	// and call the appropriate responder.
+	//
+	// response is notification serialized as LLSD:
+	// ["name"] = notification name
+	// ["form"] = LLSD tree that includes form description and any prefilled form data
+	// ["response"] = form data filled in by user
+	// (including, but not limited to which button they clicked on)
+	// ["payload"] = transaction specific data, such as ["source_id"] (originator of notification),  
+	//				["item_id"] (attached inventory item), etc.
+	// ["substitutions"] = string substitutions used to generate notification message
+    // from the template
+	// ["time"] = time at which notification was generated;
+	// ["expiry"] = time at which notification expires;
+	// ["responseFunctor"] = name of registered functor that handles responses to notification;
+	LLSD asLLSD();
+
+	void respond(const LLSD& sd);
+
+	void setIgnored(bool ignore);
+
+	bool isCancelled() const
+	{
+		return mCancelled;
+	}
+
+	bool isRespondedTo() const
+	{
+		return mRespondedTo;
+	}
+
+	bool isIgnored() const
+	{
+		return mIgnored;
+	}
+
+	const std::string& getName() const
+	{
+		return mTemplatep->mName;
+	}
+	
+	const LLUUID& id() const
+	{
+		return mId;
+	}
+	
+	const LLSD& getPayload() const
+	{
+		return mPayload;
+	}
+
+	const LLSD& getSubstitutions() const
+	{
+		return mSubstitutions;
+	}
+
+	const LLDate& getDate() const
+	{
+		return mTimestamp;
+	}
+
+	std::string getType() const
+	{
+		return (mTemplatep ? mTemplatep->mType : "");
+	}
+
+	std::string getMessage() const;
+	std::string getLabel() const;
+
+	std::string getURL() const;
+//	{
+//		return (mTemplatep ? mTemplatep->mURL : "");
+//	}
+
+	S32 getURLOption() const
+	{
+		return (mTemplatep ? mTemplatep->mURLOption : -1);
+	}
+    
+	S32 getURLOpenExternally() const
+	{
+		return(mTemplatep? mTemplatep->mURLOpenExternally : -1);
+	}
+	
+	const LLNotificationFormPtr getForm();
+
+	const LLDate getExpiration() const
+	{
+		return mExpiresAt;
+	}
+
+	ENotificationPriority getPriority() const
+	{
+		return mPriority;
+	}
+
+	const LLUUID getID() const
+	{
+		return mId;
+	}
+	
+	// comparing two notifications normally means comparing them by UUID (so we can look them
+	// up quickly this way)
+	bool operator<(const LLNotification& rhs) const
+	{
+		return mId < rhs.mId;
+	}
+
+	bool operator==(const LLNotification& rhs) const
+	{
+		return mId == rhs.mId;
+	}
+
+	bool operator!=(const LLNotification& rhs) const
+	{
+		return !operator==(rhs);
+	}
+
+	bool isSameObjectAs(const LLNotification* rhs) const
+	{
+		return this == rhs;
+	}
+	
+	// this object has been updated, so tell all our clients
+	void update();
+
+	void updateFrom(LLNotificationPtr other);
+	
+	// A fuzzy equals comparator.
+	// true only if both notifications have the same template and 
+	//     1) flagged as unique (there can be only one of these) OR 
+	//     2) all required payload fields of each also exist in the other.
+	bool isEquivalentTo(LLNotificationPtr that) const;
+	
+	// if the current time is greater than the expiration, the notification is expired
+	bool isExpired() const
+	{
+		if (mExpiresAt.secondsSinceEpoch() == 0)
+		{
+			return false;
+		}
+		
+		LLDate rightnow = LLDate::now();
+		return rightnow > mExpiresAt;
+	}
+	
+	std::string summarize() const;
+
+	bool hasUniquenessConstraints() const { return (mTemplatep ? mTemplatep->mUnique : false);}
+
+	virtual ~LLNotification() {}
+};
+
+std::ostream& operator<<(std::ostream& s, const LLNotification& notification);
+
+namespace LLNotificationFilters
+{
+	// a sample filter
+	bool includeEverything(LLNotificationPtr p);
+
+	typedef enum e_comparison 
+	{ 
+		EQUAL, 
+		LESS, 
+		GREATER, 
+		LESS_EQUAL, 
+		GREATER_EQUAL 
+	} EComparison;
+
+	// generic filter functor that takes method or member variable reference
+	template<typename T>
+	struct filterBy
+	{
+		typedef boost::function<T (LLNotificationPtr)>	field_t;
+		typedef typename boost::remove_reference<T>::type		value_t;
+		
+		filterBy(field_t field, value_t value, EComparison comparison = EQUAL) 
+			:	mField(field), 
+				mFilterValue(value),
+				mComparison(comparison)
+		{
+		}		
+		
+		bool operator()(LLNotificationPtr p)
+		{
+			switch(mComparison)
+			{
+			case EQUAL:
+				return mField(p) == mFilterValue;
+			case LESS:
+				return mField(p) < mFilterValue;
+			case GREATER:
+				return mField(p) > mFilterValue;
+			case LESS_EQUAL:
+				return mField(p) <= mFilterValue;
+			case GREATER_EQUAL:
+				return mField(p) >= mFilterValue;
+			default:
+				return false;
+			}
+		}
+
+		field_t mField;
+		value_t	mFilterValue;
+		EComparison mComparison;
+	};
+};
+
+namespace LLNotificationComparators
+{
+	typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
+
+	// generic order functor that takes method or member variable reference
+	template<typename T>
+	struct orderBy
+	{
+		typedef boost::function<T (LLNotificationPtr)> field_t;
+		orderBy(field_t field, EDirection = ORDER_INCREASING) : mField(field) {}
+		bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
+		{
+			if (mDirection == ORDER_DECREASING)
+			{
+				return mField(lhs) > mField(rhs);
+			}
+			else
+			{
+				return mField(lhs) < mField(rhs);
+			}
+		}
+
+		field_t mField;
+		EDirection mDirection;
+	};
+
+	struct orderByUUID : public orderBy<const LLUUID&>
+	{
+		orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
+	};
+
+	struct orderByDate : public orderBy<const LLDate&>
+	{
+		orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
+	};
+};
+
+typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
+typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
+typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
+typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
+
+// ========================================================
+// Abstract base class (interface) for a channel; also used for the master container.
+// This lets us arrange channels into a call hierarchy.
+
+// We maintain a heirarchy of notification channels; events are always started at the top
+// and propagated through the hierarchy only if they pass a filter.
+// Any channel can be created with a parent. A null parent (empty string) means it's
+// tied to the root of the tree (the LLNotifications class itself).
+// The default hierarchy looks like this:
+//
+// LLNotifications --+-- Expiration --+-- Mute --+-- Ignore --+-- Visible --+-- History
+//                                                                          +-- Alerts
+//                                                                          +-- Notifications
+//
+// In general, new channels that want to only see notifications that pass through 
+// all of the built-in tests should attach to the "Visible" channel
+//
+class LLNotificationChannelBase :
+	public LLEventTrackable
+{
+	LOG_CLASS(LLNotificationChannelBase);
+public:
+	LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : 
+		mFilter(filter), mItems(comp) 
+	{}
+	virtual ~LLNotificationChannelBase() {}
+	// you can also connect to a Channel, so you can be notified of
+	// changes to this channel
+	template <typename LISTENER>
+    LLBoundListener connectChanged(const LISTENER& slot)
+    {
+        // Examine slot to see if it binds an LLEventTrackable subclass, or a
+        // boost::shared_ptr to something, or a boost::weak_ptr to something.
+        // Call this->connectChangedImpl() to actually connect it.
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectChangedImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectPassedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectPassedFilterImpl,
+                                              this,
+                                              _1));
+    }
+    template <typename LISTENER>
+	LLBoundListener connectFailedFilter(const LISTENER& slot)
+    {
+        // see comments in connectChanged()
+        return LLEventDetail::visit_and_connect(slot,
+                                  boost::bind(&LLNotificationChannelBase::connectFailedFilterImpl,
+                                              this,
+                                              _1));
+    }
+
+	// use this when items change or to add a new one
+	bool updateItem(const LLSD& payload);
+	const LLNotificationFilter& getFilter() { return mFilter; }
+
+protected:
+    LLBoundListener connectChangedImpl(const LLEventListener& slot);
+    LLBoundListener connectPassedFilterImpl(const LLEventListener& slot);
+    LLBoundListener connectFailedFilterImpl(const LLEventListener& slot);
+
+	LLNotificationSet mItems;
+	LLStandardSignal mChanged;
+	LLStandardSignal mPassedFilter;
+	LLStandardSignal mFailedFilter;
+	
+	// these are action methods that subclasses can override to take action 
+	// on specific types of changes; the management of the mItems list is
+	// still handled by the generic handler.
+	virtual void onLoad(LLNotificationPtr p) {}
+	virtual void onAdd(LLNotificationPtr p) {}
+	virtual void onDelete(LLNotificationPtr p) {}
+	virtual void onChange(LLNotificationPtr p) {}
+
+	bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
+	LLNotificationFilter mFilter;
+};
+
+// The type of the pointers that we're going to manage in the NotificationQueue system
+// Because LLNotifications is a singleton, we don't actually expect to ever 
+// destroy it, but if it becomes necessary to do so, the shared_ptr model
+// will ensure that we don't leak resources.
+class LLNotificationChannel;
+typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
+
+// manages a list of notifications
+// Note that if this is ever copied around, we might find ourselves with multiple copies
+// of a queue with notifications being added to different nonequivalent copies. So we 
+// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
+// 
+// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to 
+// do something like:
+//		LLNotificationChannel::buildChannel("name", "parent"...);
+// This returns an LLNotificationChannelPtr, which you can store, or
+// you can then retrieve the channel by using the registry:
+//		LLNotifications::instance().getChannel("name")...
+//
+class LLNotificationChannel : 
+	boost::noncopyable, 
+	public LLNotificationChannelBase
+{
+	LOG_CLASS(LLNotificationChannel);
+
+public:  
+	virtual ~LLNotificationChannel() {}
+	typedef LLNotificationSet::iterator Iterator;
+    
+	std::string getName() const { return mName; }
+	std::string getParentChannelName() { return mParent; }
+    
+    bool isEmpty() const;
+    
+    Iterator begin();
+    Iterator end();
+
+    // Channels have a comparator to control sort order;
+	// the default sorts by arrival date
+    void setComparator(LLNotificationComparator comparator);
+	
+	std::string summarize();
+
+	// factory method for constructing these channels; since they're self-registering,
+	// we want to make sure that you can't use new to make them
+	static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
+						LLNotificationFilter filter=LLNotificationFilters::includeEverything, 
+						LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
+	
+protected:
+    // Notification Channels have a filter, which determines which notifications
+	// will be added to this channel. 
+	// Channel filters cannot change.
+	// Channels have a protected constructor so you can't make smart pointers that don't 
+	// come from our internal reference; call NotificationChannel::build(args)
+	LLNotificationChannel(const std::string& name, const std::string& parent,
+						  LLNotificationFilter filter, LLNotificationComparator comparator);
+
+private:
+	std::string mName;
+	std::string mParent;
+	LLNotificationComparator mComparator;
+};
+
+
+class LLNotifications : 
+	public LLSingleton<LLNotifications>, 
+	public LLNotificationChannelBase
+{
+	LOG_CLASS(LLNotifications);
+
+	friend class LLSingleton<LLNotifications>;
+public:
+	// load notification descriptions from file; 
+	// OK to call more than once because it will reload
+	bool loadTemplates();  
+	LLXMLNodePtr checkForXMLTemplate(LLXMLNodePtr item);
+	
+	// Add a simple notification (from XUI)
+	void addFromCallback(const LLSD& name);
+	
+	// we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions = LLSD(), 
+						const LLSD& payload = LLSD());
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						const std::string& functor_name);
+	LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						LLNotificationFunctorRegistry::ResponseFunctor functor);
+	LLNotificationPtr add(const LLNotification::Params& p);
+
+	void add(const LLNotificationPtr pNotif);
+	void cancel(LLNotificationPtr pNotif);
+	void update(const LLNotificationPtr pNotif);
+
+	LLNotificationPtr find(LLUUID uuid);
+	
+	typedef boost::function<void (LLNotificationPtr)> NotificationProcess;
+	
+	void forEachNotification(NotificationProcess process);
+
+	// This is all stuff for managing the templates
+	// take your template out
+	LLNotificationTemplatePtr getTemplate(const std::string& name);
+	
+	// get the whole collection
+	typedef std::vector<std::string> TemplateNames;
+	TemplateNames getTemplateNames() const;  // returns a list of notification names
+	
+	typedef std::map<std::string, LLNotificationTemplatePtr> TemplateMap;
+
+	TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
+	TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
+
+	// test for existence
+	bool templateExists(const std::string& name);
+	// useful if you're reloading the file
+	void clearTemplates();   // erase all templates
+
+	void forceResponse(const LLNotification::Params& params, S32 option);
+
+	void createDefaultChannels();
+
+	typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
+	ChannelMap mChannels;
+
+	void addChannel(LLNotificationChannelPtr pChan);
+	LLNotificationChannelPtr getChannel(const std::string& channelName);
+	
+	std::string getGlobalString(const std::string& key) const;
+
+	void setIgnoreAllNotifications(bool ignore);
+	bool getIgnoreAllNotifications();
+
+private:
+	// we're a singleton, so we don't have a public constructor
+	LLNotifications();
+	/*virtual*/ void initSingleton();
+	
+	void loadPersistentNotifications();
+
+	bool expirationFilter(LLNotificationPtr pNotification);
+	bool expirationHandler(const LLSD& payload);
+	bool uniqueFilter(LLNotificationPtr pNotification);
+	bool uniqueHandler(const LLSD& payload);
+	bool failedUniquenessTest(const LLSD& payload);
+	LLNotificationChannelPtr pHistoryChannel;
+	LLNotificationChannelPtr pExpirationChannel;
+	
+	// put your template in
+	bool addTemplate(const std::string& name, LLNotificationTemplatePtr theTemplate);
+	TemplateMap mTemplates;
+
+	std::string mFileName;
+	
+	typedef std::map<std::string, LLXMLNodePtr> XMLTemplateMap;
+	XMLTemplateMap mXmlTemplates;
+
+	LLNotificationMap mUniqueNotifications;
+	
+	typedef std::map<std::string, std::string> GlobalStringMap;
+	GlobalStringMap mGlobalStrings;
+
+	bool mIgnoreAllNotifications;
+
+    boost::scoped_ptr<LLNotificationsListener> mListener;
+};
+
+
+#endif//LL_LLNOTIFICATIONS_H
+
-- 
cgit v1.2.3


From db7f15df68cda2850c3d8a7ffcc59fc136de6f95 Mon Sep 17 00:00:00 2001
From: "Mark Palange (Mani)" <palange@lindenlab.com>
Date: Wed, 22 Jul 2009 14:53:55 -0700
Subject: Adding LLLoginInstance unit test

---
 indra/llui/llnotificationslistener.cpp | 29 ++++++++++++++++++++++++++++-
 indra/llui/llnotificationslistener.h   |  5 ++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index d6e552ca5c..6ebbee68ac 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -24,5 +24,32 @@ LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications
 
 void LLNotificationsListener::requestAdd(const LLSD& event_data) const
 {
-    mNotifications.add(event_data["name"], event_data["substitutions"], event_data["payload"]);
+	if(event_data.has("reply"))
+	{
+		mNotifications.add(event_data["name"], 
+						   event_data["substitutions"], 
+						   event_data["payload"],
+						   boost::bind(&LLNotificationListener::Responder, 
+									   this, 
+									   event_data["reply"].asString(), 
+									   _1, _2
+									   )
+						   );
+	}
+	else
+	{
+		mNotifications.add(event_data["name"], 
+						   event_data["substitutions"], 
+						   event_data["payload"]);
+	}
+}
+
+void LLNotificationsListener::Responder(const std::string& reply_pump, 
+										const LLSD& notification, 
+										const LLSD& response)
+{
+	LLSD reponse_event;
+	reponse_event["notification"] = notification;
+	reponse_event["response"] = response;
+	mEventPumps.obtain(reply_pump).post(reponse_event);
 }
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
index 3576cacbdb..d11aed1b52 100644
--- a/indra/llui/llnotificationslistener.h
+++ b/indra/llui/llnotificationslistener.h
@@ -25,7 +25,10 @@ public:
     void requestAdd(LLSD const & event_data) const;
 
 private:
-    LLNotifications & mNotifications;
+	void NotificationResponder(const std::string& replypump, 
+							   const LLSD& notification, 
+							   const LLSD& response);
+	LLNotifications & mNotifications;
 };
 
 #endif // LL_LLNOTIFICATIONSLISTENER_H
-- 
cgit v1.2.3


From 9538328d5f7cf0f0be5dd77b8e27032e09104fff Mon Sep 17 00:00:00 2001
From: "Mark Palange (Mani)" <palange@lindenlab.com>
Date: Fri, 24 Jul 2009 15:08:16 -0700
Subject: Adding LLLoginInstance unit test.  - Added LLNotificationsInterface
 class.  - Removed LLLoginInstance use of LLNotifications EventAPI

---
 indra/llui/llnotifications.h           | 13 ++++++++++++-
 indra/llui/llnotificationslistener.cpp |  8 ++++----
 indra/llui/llnotificationslistener.h   |  2 +-
 3 files changed, 17 insertions(+), 6 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 93cdcbeefd..c534267fca 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -799,8 +799,19 @@ private:
 	LLNotificationComparator mComparator;
 };
 
+// An interface class to provide a clean linker seam to the LLNotifications class.
+// Extend this interface as needed for your use of LLNotifications.
+class LLNotificationsInterface
+{
+public:
+	virtual LLNotificationPtr add(const std::string& name, 
+						const LLSD& substitutions, 
+						const LLSD& payload, 
+						LLNotificationFunctorRegistry::ResponseFunctor functor) = 0;
+};
 
 class LLNotifications : 
+	public LLNotificationsInterface,
 	public LLSingleton<LLNotifications>, 
 	public LLNotificationChannelBase
 {
@@ -824,7 +835,7 @@ public:
 						const LLSD& substitutions, 
 						const LLSD& payload, 
 						const std::string& functor_name);
-	LLNotificationPtr add(const std::string& name, 
+	/* virtual */ LLNotificationPtr add(const std::string& name, 
 						const LLSD& substitutions, 
 						const LLSD& payload, 
 						LLNotificationFunctorRegistry::ResponseFunctor functor);
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index 6ebbee68ac..75f4d6177d 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -29,7 +29,7 @@ void LLNotificationsListener::requestAdd(const LLSD& event_data) const
 		mNotifications.add(event_data["name"], 
 						   event_data["substitutions"], 
 						   event_data["payload"],
-						   boost::bind(&LLNotificationListener::Responder, 
+						   boost::bind(&LLNotificationsListener::NotificationResponder, 
 									   this, 
 									   event_data["reply"].asString(), 
 									   _1, _2
@@ -44,12 +44,12 @@ void LLNotificationsListener::requestAdd(const LLSD& event_data) const
 	}
 }
 
-void LLNotificationsListener::Responder(const std::string& reply_pump, 
+void LLNotificationsListener::NotificationResponder(const std::string& reply_pump, 
 										const LLSD& notification, 
-										const LLSD& response)
+										const LLSD& response) const
 {
 	LLSD reponse_event;
 	reponse_event["notification"] = notification;
 	reponse_event["response"] = response;
-	mEventPumps.obtain(reply_pump).post(reponse_event);
+	LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event);
 }
diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h
index d11aed1b52..6f71a7c781 100644
--- a/indra/llui/llnotificationslistener.h
+++ b/indra/llui/llnotificationslistener.h
@@ -27,7 +27,7 @@ public:
 private:
 	void NotificationResponder(const std::string& replypump, 
 							   const LLSD& notification, 
-							   const LLSD& response);
+							   const LLSD& response) const;
 	LLNotifications & mNotifications;
 };
 
-- 
cgit v1.2.3


From 2da8eb43d57ae6876f9955386f604f2c56849211 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 14 Aug 2009 14:40:43 -0400
Subject: Wrap a subset of the LLFloaterReg API with an event API

---
 indra/llui/CMakeLists.txt           |  2 ++
 indra/llui/llfloaterreg.cpp         |  3 ++
 indra/llui/llfloaterreg.h           |  1 +
 indra/llui/llfloaterreglistener.cpp | 60 +++++++++++++++++++++++++++++++++++++
 indra/llui/llfloaterreglistener.h   | 34 +++++++++++++++++++++
 5 files changed, 100 insertions(+)
 create mode 100644 indra/llui/llfloaterreglistener.cpp
 create mode 100644 indra/llui/llfloaterreglistener.h

(limited to 'indra/llui')

diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 269c02263d..49230833f8 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -40,6 +40,7 @@ set(llui_SOURCE_FILES
     llfiltereditor.cpp
     llfloater.cpp
     llfloaterreg.cpp
+    llfloaterreglistener.cpp
     llflyoutbutton.cpp 
     llfocusmgr.cpp
     llfunctorregistry.cpp
@@ -115,6 +116,7 @@ set(llui_HEADER_FILES
     llfiltereditor.h 
     llfloater.h
     llfloaterreg.h
+    llfloaterreglistener.h
     llflyoutbutton.h 
     llfocusmgr.h
     llfunctorregistry.h
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index a63b1b085c..8617ba940e 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -36,6 +36,7 @@
 
 #include "llfloater.h"
 #include "llmultifloater.h"
+#include "llfloaterreglistener.h"
 
 //*******************************************************
 
@@ -45,6 +46,8 @@ LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
 LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
 std::map<std::string,std::string> LLFloaterReg::sGroupMap;
 
+static LLFloaterRegListener sFloaterRegListener("LLFloaterReg");
+
 //*******************************************************
 
 //static
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 7edac43c96..451bd1dbe3 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -70,6 +70,7 @@ public:
 	typedef std::map<std::string, BuildData> build_map_t;
 	
 private:
+	friend class LLFloaterRegListener;
 	static instance_list_t sNullInstanceList;
 	static instance_map_t sInstanceMap;
 	static build_map_t sBuildMap;
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
new file mode 100644
index 0000000000..37708a7cd9
--- /dev/null
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -0,0 +1,60 @@
+/**
+ * @file   llfloaterreglistener.cpp
+ * @author Nat Goodspeed
+ * @date   2009-08-12
+ * @brief  Implementation for llfloaterreglistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llfloaterreglistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llfloaterreg.h"
+
+LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
+    LLDispatchListener(pumpName, "op")
+{
+    add("getBuildMap",  &LLFloaterRegListener::getBuildMap,  LLSD().insert("reply", LLSD()));
+    LLSD requiredName;
+    requiredName["name"] = LLSD();
+    add("showInstance", &LLFloaterRegListener::showInstance, requiredName);
+    add("hideInstance", &LLFloaterRegListener::hideInstance, requiredName);
+}
+
+void LLFloaterRegListener::getBuildMap(const LLSD& event) const
+{
+    // Honor the "reqid" convention by echoing event["reqid"] in our reply packet.
+    LLReqID reqID(event);
+    LLSD reply(reqID.makeResponse());
+    // Build an LLSD map that mirrors sBuildMap. Since we have no good way to
+    // represent a C++ callable in LLSD, the only part of BuildData we can
+    // store is the filename. For each LLSD map entry, it would be more
+    // extensible to store a nested LLSD map containing a single key "file" --
+    // but we don't bother, simply storing the string filename instead.
+    for (LLFloaterReg::build_map_t::const_iterator mi(LLFloaterReg::sBuildMap.begin()),
+                                                   mend(LLFloaterReg::sBuildMap.end());
+         mi != mend; ++mi)
+    {
+        reply[mi->first] = mi->second.mFile;
+    }
+    // Send the reply to the LLEventPump named in event["reply"].
+    LLEventPumps::instance().obtain(event["reply"]).post(reply);
+}
+
+void LLFloaterRegListener::showInstance(const LLSD& event) const
+{
+    LLFloaterReg::showInstance(event["name"], event["key"], event["focus"]);
+}
+
+void LLFloaterRegListener::hideInstance(const LLSD& event) const
+{
+    LLFloaterReg::hideInstance(event["name"], event["key"]);
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
new file mode 100644
index 0000000000..049389c094
--- /dev/null
+++ b/indra/llui/llfloaterreglistener.h
@@ -0,0 +1,34 @@
+/**
+ * @file   llfloaterreglistener.h
+ * @author Nat Goodspeed
+ * @date   2009-08-12
+ * @brief  Wrap (subset of) LLFloaterReg API with an event API
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLFLOATERREGLISTENER_H)
+#define LL_LLFLOATERREGLISTENER_H
+
+#include "lleventdispatcher.h"
+#include <string>
+
+class LLSD;
+
+/// Event API wrapper for LLFloaterReg
+class LLFloaterRegListener: public LLDispatchListener
+{
+public:
+    /// As all public LLFloaterReg methods are static, there's no point in
+    /// binding an LLFloaterReg instance.
+    LLFloaterRegListener(const std::string& pumpName);
+
+private:
+    void getBuildMap(const LLSD& event) const;
+    void showInstance(const LLSD& event) const;
+    void hideInstance(const LLSD& event) const;
+};
+
+#endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
-- 
cgit v1.2.3


From 25ceef032b49591244c7df704494436b8b2e4044 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 19 Aug 2009 15:05:08 -0400
Subject: Wrap LLFloaterReg::toggleInstance() as well as showInstance() and
 hideInstance(). Use toggleInstance() in testfloaters.py.

---
 indra/llui/llfloaterreglistener.cpp | 6 ++++++
 indra/llui/llfloaterreglistener.h   | 1 +
 2 files changed, 7 insertions(+)

(limited to 'indra/llui')

diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
index 37708a7cd9..cb8fa6dfda 100644
--- a/indra/llui/llfloaterreglistener.cpp
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -27,6 +27,7 @@ LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
     requiredName["name"] = LLSD();
     add("showInstance", &LLFloaterRegListener::showInstance, requiredName);
     add("hideInstance", &LLFloaterRegListener::hideInstance, requiredName);
+    add("toggleInstance", &LLFloaterRegListener::toggleInstance, requiredName);
 }
 
 void LLFloaterRegListener::getBuildMap(const LLSD& event) const
@@ -58,3 +59,8 @@ void LLFloaterRegListener::hideInstance(const LLSD& event) const
 {
     LLFloaterReg::hideInstance(event["name"], event["key"]);
 }
+
+void LLFloaterRegListener::toggleInstance(const LLSD& event) const
+{
+    LLFloaterReg::toggleInstance(event["name"], event["key"]);
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
index 049389c094..58d2c07936 100644
--- a/indra/llui/llfloaterreglistener.h
+++ b/indra/llui/llfloaterreglistener.h
@@ -29,6 +29,7 @@ private:
     void getBuildMap(const LLSD& event) const;
     void showInstance(const LLSD& event) const;
     void hideInstance(const LLSD& event) const;
+    void toggleInstance(const LLSD& event) const;
 };
 
 #endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
-- 
cgit v1.2.3


From d40d745cba1de0df4ada7d4d2cf9f1632279ae12 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 11 Sep 2009 22:24:30 -0400
Subject: DEV-38598, QAR-1619: Ensure we remove LLFloaterTOS from LLFloaterReg
 registry. LLFloater's destructor calls LLFloaterReg::removeInstance() with
 its own name and key. But for the new LLFloaterTOS invocation, we pass a key
 that's an LLSD map. removeInstance() critically depends on
 LLFloater::KeyCompare::equate() -- but equate() never considered a non-scalar
 LLSD key value. Fortunately llsdutil.h already provides a deep-equality
 function for LLSD: llsd_equals(). Making equate() trivially call
 llsd_equals() fixes the crash on TOS cancel.

---
 indra/llui/llfloater.cpp | 25 ++-----------------------
 1 file changed, 2 insertions(+), 23 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index ca3829e1bd..786340b468 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -60,6 +60,7 @@
 #include "v2math.h"
 #include "lltrans.h"
 #include "llmultifloater.h"
+#include "llsdutil.h"
 
 // use this to control "jumping" behavior when Ctrl-Tabbing
 const S32 TABBED_FLOATER_OFFSET = 0;
@@ -175,29 +176,7 @@ bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
 
 bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
 {
-	if (a.type() != b.type())
-	{
-		//llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl;
-		return false;
-	}
-	else if (a.isUndefined())
-		return true;
-	else if (a.isInteger())
-		return a.asInteger() == b.asInteger();
-	else if (a.isReal())
-		return a.asReal() == b.asReal();
-	else if (a.isString())
-		return a.asString() == b.asString();
-	else if (a.isUUID())
-		return a.asUUID() == b.asUUID();
-	else if (a.isDate())
-		return a.asDate() == b.asDate();
-	else if (a.isURI())
-		return a.asString() == b.asString(); // compare URIs as strings
-	else if (a.isBoolean())
-		return a.asBoolean() == b.asBoolean();
-	else
-		return false; // no valid operation for Binary
+	return llsd_equals(a, b);
 }
 
 //************************************
-- 
cgit v1.2.3


From 689af4b32948e2d2a07b60adcc318668c4d55585 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Sat, 12 Sep 2009 09:11:32 -0400
Subject: DEV-38598: remove dangerous compare-LLSD-less-than operation

---
 indra/llui/llfloater.cpp | 11 +++++++++++
 indra/llui/llfloater.h   |  4 +++-
 2 files changed, 14 insertions(+), 1 deletion(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 786340b468..a372bac497 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -146,6 +146,16 @@ LLFloater::handle_map_t	LLFloater::sFloaterMap;
 
 LLFloaterView* gFloaterView = NULL;
 
+/*==========================================================================*|
+// DEV-38598: The fundamental problem with this operation is that it can only
+// support a subset of LLSD values. While it's plausible to compare two arrays
+// lexicographically, what strict ordering can you impose on maps?
+// (LLFloaterTOS's current key is an LLSD map.)
+
+// Of course something like this is necessary if you want to build a std::set
+// or std::map with LLSD keys. Fortunately we're getting by with other
+// container types for now.
+
 //static
 bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
 {
@@ -173,6 +183,7 @@ bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
 	else
 		return false; // no valid operation for Binary
 }
+|*==========================================================================*/
 
 bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b)
 {
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index ee066317e0..cace13939f 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -87,12 +87,14 @@ friend class LLMultiFloater;
 public:
 	struct KeyCompare
 	{
-		static bool compare(const LLSD& a, const LLSD& b);
+//		static bool compare(const LLSD& a, const LLSD& b);
 		static bool equate(const LLSD& a, const LLSD& b);
+/*==========================================================================*|
 		bool operator()(const LLSD& a, const LLSD& b) const
 		{
 			return compare(a, b);
 		}
+|*==========================================================================*/
 	};
 	
 	enum EFloaterButtons
-- 
cgit v1.2.3


From a162496da9044e695bc306321da1fb278259b9c6 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 8 Oct 2009 22:48:02 -0400
Subject: DEV-40930: At app shutdown, clear LLModalDialog::sModalStack.
 Otherwise, any modal dialog still left open will crump on destruction with
 LL_ERRS. If we don't want the user to shut down the app with a modal dialog
 open, we should deal with it better than a popup that simply makes us look
 buggy.

---
 indra/llui/llmodaldialog.cpp | 15 +++++++++++++--
 indra/llui/llmodaldialog.h   |  3 ++-
 2 files changed, 15 insertions(+), 3 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index f77ec5f4c7..387af05935 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -297,5 +297,16 @@ void LLModalDialog::onAppFocusGained()
 	}
 }
 
-
-
+void LLModalDialog::shutdownModals()
+{
+	// This method is only for use during app shutdown. ~LLModalDialog()
+	// checks sModalStack, and if the dialog instance is still there, it
+	// crumps with "Attempt to delete dialog while still in sModalStack!" But
+	// at app shutdown, all bets are off. If the user asks to shut down the
+	// app, we shouldn't have to care WHAT's open. Put differently, if a modal
+	// dialog is so crucial that we can't let the user terminate until s/he
+	// addresses it, we should reject a termination request. The current state
+	// of affairs is that we accept it, but then produce an llerrs popup that
+	// simply makes our software look unreliable.
+	sModalStack.clear();
+}
diff --git a/indra/llui/llmodaldialog.h b/indra/llui/llmodaldialog.h
index 9d716a1880..863572fb5a 100644
--- a/indra/llui/llmodaldialog.h
+++ b/indra/llui/llmodaldialog.h
@@ -73,7 +73,8 @@ public:
 	static void		onAppFocusGained();
 
 	static S32		activeCount() { return sModalStack.size(); }
-	
+	static void		shutdownModals();
+
 protected:
 	void			centerOnScreen();
 
-- 
cgit v1.2.3


From 590d3b9e3a2abdd37270ca64689a64c4e879fbe6 Mon Sep 17 00:00:00 2001
From: Steve Bennetts <steve@lindenlab.com>
Date: Thu, 15 Oct 2009 14:14:46 -0700
Subject: EXT-1279 Crash if font file not found. Added getFontDefault() to
 llfontgl.h

--HG--
branch : branch-test
---
 indra/llui/llconsole.cpp | 5 +++++
 indra/llui/llui.cpp      | 7 ++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 285ce82d2d..e0053b4cc7 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -120,6 +120,11 @@ void LLConsole::setFontSize(S32 size_index)
 	{
 		mFont = LLFontGL::getFontSansSerifHuge();
 	}
+	// Make sure the font exists
+	if (mFont == NULL)
+	{
+		mFont = LLFontGL::getFontDefault();
+	}
 	
 	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
 	{
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index c89e5944fa..eb1b60244d 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1954,7 +1954,12 @@ namespace LLInitParam
 				return fontp;
 			}
 		}
-
+		
+		if (mData.mValue == NULL)
+		{
+			mData.mValue = LLFontGL::getFontDefault();
+		}
+		
 		// default to current value
 		return mData.mValue;
 	}
-- 
cgit v1.2.3


From 2a5c25cb3a47a319559aae6de1206e91b3c1647e Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Sat, 17 Oct 2009 11:56:26 -0400
Subject: New LLFloater methods capture LLFloaterReg visibility tests. The
 logic was redundantly expressed in LLFloaterReg -- and would be useful
 elsewhere -- so was introduced as LLFloater::isShown(). Thanks to Richard and
 James for suggesting the terminology.

---
 indra/llui/llfloater.cpp    | 10 ++++++++++
 indra/llui/llfloater.h      |  8 +++++++-
 indra/llui/llfloaterreg.cpp | 11 ++---------
 3 files changed, 19 insertions(+), 10 deletions(-)

(limited to 'indra/llui')

diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 66defbbf0a..d7a24192bb 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2605,3 +2605,13 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
 	moveResizeHandlesToFront();
 }
 
+bool LLFloater::isShown() const
+{
+    return ! isMinimized() && isInVisibleChain();
+}
+
+/* static */
+bool LLFloater::isShown(const LLFloater* floater)
+{
+    return floater && floater->isShown();
+}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 466d060068..ef609860d1 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -185,7 +185,13 @@ public:
 	void			addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE);
 	LLFloater*		getDependee() { return (LLFloater*)mDependeeHandle.get(); }
 	void		removeDependentFloater(LLFloater* dependent);
-	BOOL			isMinimized()					{ return mMinimized; }
+	BOOL			isMinimized() const				{ return mMinimized; }
+	/// isShown() differs from getVisible() in that isShown() also considers
+	/// isMinimized(). isShown() is true only if visible and not minimized.
+	bool			isShown() const;
+	/// The static isShown() can accept a NULL pointer (which of course
+	/// returns false). When non-NULL, it calls the non-static isShown().
+	static bool		isShown(const LLFloater* floater);
 	BOOL			isFrontmost();
 	BOOL			isDependent()					{ return !mDependeeHandle.isDead(); }
 	void			setCanMinimize(BOOL can_minimize);
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index 8617ba940e..589a34b2c8 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -247,7 +247,7 @@ bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key)
 bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
 {
 	LLFloater* instance = findInstance(name, key); 
-	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
+	if (LLFloater::isShown(instance))
 	{
 		// When toggling *visibility*, close the host instead of the floater when hosted
 		if (instance->getHost())
@@ -267,14 +267,7 @@ bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
 bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
 {
 	LLFloater* instance = findInstance(name, key); 
-	if (instance && !instance->isMinimized() && instance->isInVisibleChain())
-	{
-		return true;
-	}
-	else
-	{
-		return false;
-	}
+	return LLFloater::isShown(instance);
 }
 
 //static
-- 
cgit v1.2.3


From ed84101a6e31760b7a44de857669ce255ee67d9b Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Sat, 17 Oct 2009 12:00:12 -0400
Subject: Introduce LLView::isAvailable() to test enabled & visible. Better
 term? The point of the method is to verify that a user could actually
 interact with the LLView in question.

---
 indra/llui/llview.cpp | 12 ++++++++++++
 indra/llui/llview.h   |  5 +++++
 2 files changed, 17 insertions(+)

(limited to 'indra/llui')

diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 1df8838738..2be8b8c17d 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -438,6 +438,18 @@ void LLView::setEnabled(BOOL enabled)
 	mEnabled = enabled;
 }
 
+//virtual
+bool LLView::isAvailable() const
+{
+    return isInEnabledChain() && isInVisibleChain();
+}
+
+//static
+bool LLView::isAvailable(const LLView* view)
+{
+    return view && view->isAvailable();
+}
+
 //virtual
 BOOL LLView::setLabelArg( const std::string& key, const LLStringExplicit& text )
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 7ddff2bd9e..f630932317 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -304,6 +304,11 @@ public:
 	BOOL			getVisible() const			{ return mVisible; }
 	virtual void	setEnabled(BOOL enabled);
 	BOOL			getEnabled() const			{ return mEnabled; }
+	/// 'available' in this context means 'visible and enabled': in other
+	/// words, can a user actually interact with this?
+	virtual bool	isAvailable() const;
+	/// The static isAvailable() tests an LLView* that could be NULL.
+	static bool		isAvailable(const LLView* view);
 	U8              getSoundFlags() const       { return mSoundFlags; }
 
 	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );
-- 
cgit v1.2.3


From 2849175a302f26be03b5da404ef93363d42ed313 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Sat, 17 Oct 2009 12:03:23 -0400
Subject: Introduce LLFloaterRegListener "clickButton" event operation. Based
 on discussion with James and Richard, this operation should allow an
 automation script to locate a visible LLFloater and simulate clicking any one
 of its LLButton children by name. As yet untested.

---
 indra/llui/llfloaterreglistener.cpp | 48 +++++++++++++++++++++++++++++++++++++
 indra/llui/llfloaterreglistener.h   |  1 +
 2 files changed, 49 insertions(+)

(limited to 'indra/llui')

diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
index cb8fa6dfda..57d148b5af 100644
--- a/indra/llui/llfloaterreglistener.cpp
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -18,6 +18,8 @@
 // external library headers
 // other Linden headers
 #include "llfloaterreg.h"
+#include "llfloater.h"
+#include "llbutton.h"
 
 LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
     LLDispatchListener(pumpName, "op")
@@ -28,6 +30,10 @@ LLFloaterRegListener::LLFloaterRegListener(const std::string& pumpName):
     add("showInstance", &LLFloaterRegListener::showInstance, requiredName);
     add("hideInstance", &LLFloaterRegListener::hideInstance, requiredName);
     add("toggleInstance", &LLFloaterRegListener::toggleInstance, requiredName);
+    LLSD requiredNameButton;
+    requiredNameButton["name"] = LLSD();
+    requiredNameButton["button"] = LLSD();
+    add("clickButton", &LLFloaterRegListener::clickButton, requiredNameButton);
 }
 
 void LLFloaterRegListener::getBuildMap(const LLSD& event) const
@@ -64,3 +70,45 @@ void LLFloaterRegListener::toggleInstance(const LLSD& event) const
 {
     LLFloaterReg::toggleInstance(event["name"], event["key"]);
 }
+
+void LLFloaterRegListener::clickButton(const LLSD& event) const
+{
+    // If the caller requests a reply, build the reply.
+    LLReqID reqID(event);
+    LLSD reply(reqID.makeResponse());
+
+    LLFloater* floater = LLFloaterReg::findInstance(event["name"], event["key"]);
+    if (! LLFloater::isShown(floater))
+    {
+        reply["type"]  = "LLFloater";
+        reply["name"]  = event["name"];
+        reply["key"]   = event["key"];
+        reply["error"] = floater? "!isShown()" : "NULL";
+    }
+    else
+    {
+        // Here 'floater' points to an LLFloater instance with the specified
+        // name and key which isShown().
+        LLButton* button = floater->findChild<LLButton>(event["button"]);
+        if (! LLButton::isAvailable(button))
+        {
+            reply["type"]  = "LLButton";
+            reply["name"]  = event["button"];
+            reply["error"] = button? "!isAvailable()" : "NULL";
+        }
+        else
+        {
+            // Here 'button' points to an isAvailable() LLButton child of
+            // 'floater' with the specified button name. Pretend to click it.
+            button->onCommit();
+            // Leave reply["error"] isUndefined(): no error, i.e. success.
+        }
+    }
+
+    // Send a reply only if caller asked for a reply.
+    LLSD replyPump(event["reply"]);
+    if (replyPump.isString())       // isUndefined() if absent
+    {
+        LLEventPumps::instance().obtain(replyPump).post(reply);
+    }
+}
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
index 58d2c07936..304ecd1090 100644
--- a/indra/llui/llfloaterreglistener.h
+++ b/indra/llui/llfloaterreglistener.h
@@ -30,6 +30,7 @@ private:
     void showInstance(const LLSD& event) const;
     void hideInstance(const LLSD& event) const;
     void toggleInstance(const LLSD& event) const;
+    void clickButton(const LLSD& event) const;
 };
 
 #endif /* ! defined(LL_LLFLOATERREGLISTENER_H) */
-- 
cgit v1.2.3