summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/CMakeLists.txt50
-rw-r--r--indra/llui/llbutton.cpp734
-rw-r--r--indra/llui/llbutton.h199
-rw-r--r--indra/llui/llcallbackmap.h19
-rw-r--r--indra/llui/llcheckboxctrl.cpp282
-rw-r--r--indra/llui/llcheckboxctrl.h73
-rw-r--r--indra/llui/llcombobox.cpp594
-rw-r--r--indra/llui/llcombobox.h131
-rw-r--r--indra/llui/llconsole.cpp393
-rw-r--r--indra/llui/llconsole.h162
-rw-r--r--indra/llui/llcontainerview.cpp301
-rw-r--r--indra/llui/llcontainerview.h92
-rw-r--r--indra/llui/lldraghandle.cpp105
-rw-r--r--indra/llui/lldraghandle.h44
-rw-r--r--indra/llui/llf32uictrl.cpp57
-rw-r--r--indra/llui/llf32uictrl.h83
-rw-r--r--indra/llui/llfloater.cpp1673
-rw-r--r--indra/llui/llfloater.h305
-rw-r--r--indra/llui/llfloaterreg.cpp423
-rw-r--r--indra/llui/llfloaterreg.h152
-rw-r--r--indra/llui/llflyoutbutton.cpp94
-rw-r--r--indra/llui/llflyoutbutton.h71
-rw-r--r--indra/llui/llfocusmgr.cpp20
-rw-r--r--indra/llui/llfunctorregistry.cpp1
-rw-r--r--indra/llui/llfunctorregistry.h2
-rw-r--r--indra/llui/lliconctrl.cpp128
-rw-r--r--indra/llui/lliconctrl.h32
-rw-r--r--indra/llui/llkeywords.cpp4
-rw-r--r--indra/llui/lllayoutstack.cpp740
-rw-r--r--indra/llui/lllayoutstack.h105
-rw-r--r--indra/llui/lllazyvalue.h88
-rw-r--r--indra/llui/lllineeditor.cpp720
-rw-r--r--indra/llui/lllineeditor.h178
-rw-r--r--indra/llui/llmenugl.cpp3068
-rw-r--r--indra/llui/llmenugl.h612
-rw-r--r--indra/llui/llmodaldialog.cpp48
-rw-r--r--indra/llui/llmodaldialog.h2
-rw-r--r--indra/llui/llmultifloater.cpp510
-rw-r--r--indra/llui/llmultifloater.h107
-rw-r--r--indra/llui/llmultislider.cpp220
-rw-r--r--indra/llui/llmultislider.h97
-rw-r--r--indra/llui/llmultisliderctrl.cpp394
-rw-r--r--indra/llui/llmultisliderctrl.h71
-rw-r--r--indra/llui/llnotifications.cpp161
-rw-r--r--indra/llui/llnotifications.h97
-rw-r--r--indra/llui/llpanel.cpp1229
-rw-r--r--indra/llui/llpanel.h174
-rw-r--r--indra/llui/llprogressbar.cpp141
-rw-r--r--indra/llui/llprogressbar.h45
-rw-r--r--indra/llui/llradiogroup.cpp257
-rw-r--r--indra/llui/llradiogroup.h79
-rw-r--r--indra/llui/llresizebar.cpp37
-rw-r--r--indra/llui/llresizebar.h26
-rw-r--r--indra/llui/llresizehandle.cpp57
-rw-r--r--indra/llui/llresizehandle.h13
-rw-r--r--indra/llui/llresmgr.cpp147
-rw-r--r--indra/llui/llresmgr.h25
-rw-r--r--indra/llui/llscrollbar.cpp239
-rw-r--r--indra/llui/llscrollbar.h72
-rw-r--r--indra/llui/llscrollcontainer.cpp317
-rw-r--r--indra/llui/llscrollcontainer.h37
-rw-r--r--indra/llui/llscrollingpanellist.cpp64
-rw-r--r--indra/llui/llscrollingpanellist.h30
-rw-r--r--indra/llui/llscrolllistcell.cpp413
-rw-r--r--indra/llui/llscrolllistcell.h223
-rw-r--r--indra/llui/llscrolllistcolumn.cpp330
-rw-r--r--indra/llui/llscrolllistcolumn.h191
-rw-r--r--indra/llui/llscrolllistctrl.cpp1888
-rw-r--r--indra/llui/llscrolllistctrl.h435
-rw-r--r--indra/llui/llscrolllistitem.cpp157
-rw-r--r--indra/llui/llscrolllistitem.h129
-rw-r--r--indra/llui/llsdparam.cpp158
-rw-r--r--indra/llui/llsdparam.h107
-rw-r--r--indra/llui/llsearcheditor.cpp124
-rw-r--r--indra/llui/llsearcheditor.h98
-rw-r--r--indra/llui/llslider.cpp162
-rw-r--r--indra/llui/llslider.h71
-rw-r--r--indra/llui/llsliderctrl.cpp342
-rw-r--r--indra/llui/llsliderctrl.h119
-rw-r--r--indra/llui/llspinctrl.cpp373
-rw-r--r--indra/llui/llspinctrl.h74
-rw-r--r--indra/llui/llstatbar.cpp293
-rw-r--r--indra/llui/llstatbar.h108
-rw-r--r--indra/llui/llstatgraph.cpp163
-rw-r--r--indra/llui/llstatgraph.h76
-rw-r--r--indra/llui/llstatview.cpp80
-rw-r--r--indra/llui/llstatview.h66
-rw-r--r--indra/llui/llstyle.cpp32
-rw-r--r--indra/llui/llstyle.h9
-rw-r--r--indra/llui/lltabcontainer.cpp814
-rw-r--r--indra/llui/lltabcontainer.h133
-rw-r--r--indra/llui/lltextbox.cpp249
-rw-r--r--indra/llui/lltextbox.h81
-rw-r--r--indra/llui/lltexteditor.cpp574
-rw-r--r--indra/llui/lltexteditor.h110
-rw-r--r--indra/llui/lltextparser.cpp55
-rw-r--r--indra/llui/lltextparser.h34
-rw-r--r--indra/llui/llui.cpp404
-rw-r--r--indra/llui/llui.h311
-rw-r--r--indra/llui/lluicolortable.cpp155
-rw-r--r--indra/llui/lluicolortable.h58
-rw-r--r--indra/llui/lluictrl.cpp443
-rw-r--r--indra/llui/lluictrl.h212
-rw-r--r--indra/llui/lluictrlfactory.cpp1103
-rw-r--r--indra/llui/lluictrlfactory.h422
-rw-r--r--indra/llui/lluifwd.h1
-rw-r--r--indra/llui/lluiimage.cpp166
-rw-r--r--indra/llui/lluiimage.h114
-rw-r--r--indra/llui/lluistring.cpp14
-rw-r--r--indra/llui/llview.cpp1361
-rw-r--r--indra/llui/llview.h365
-rw-r--r--indra/llui/llviewborder.cpp143
-rw-r--r--indra/llui/llviewborder.h57
-rw-r--r--indra/llui/llviewmodel.cpp163
-rw-r--r--indra/llui/llviewmodel.h219
-rw-r--r--indra/llui/llviewquery.h2
116 files changed, 16991 insertions, 13424 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 5de8dc76af..117e8e28ab 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,36 @@ 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
+ lluicolortable.cpp
lluictrl.cpp
lluictrlfactory.cpp
+ lluiimage.cpp
lluistring.cpp
- lluitrans.cpp
llundo.cpp
llviewborder.cpp
+ llviewmodel.cpp
llview.cpp
llviewquery.cpp
)
@@ -85,52 +102,69 @@ 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
+ lluicolortable.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..f2aa9c0d4c 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,171 @@
#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");
+static LLDefaultWidgetRegistry::Register<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"),
+ 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);
-}
-
-
-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 ),
+ addSynonym(is_toggle, "toggle");
+ held_down_delay.seconds = 0.5f;
+ initial_value.set(LLSD(false), false);
+}
+
+
+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;
-
- // 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
- {
- setImageUnselected(std::string("button_enabled_32x128.tga"));
- setImageDisabled(std::string("button_disabled_32x128.tga"));
- }
+ static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
+ static Params default_params(LLUICtrlFactory::getDefaultParams<Params>());
- if( selected_image_name != "" )
+ //if we aren't a picture_style button set label as name if not provided
+ if (!p.picture_style.isProvided() || !p.picture_style)
{
- // 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 (mImageUnselected.isNull())
+ {
+ llwarns << "Button: " << getName() << " with no image!" << llendl;
}
+
+ 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 +218,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 +241,55 @@ void LLButton::onCommit()
}
// do this last, as it can result in destroying this button
- if (mClickedCallback)
- {
- (*mClickedCallback)( mCallbackUserData );
- }
+ LLUICtrl::onCommit();
+}
+
+boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb )
+{
+ return mCommitSignal.connect(cb);
+}
+boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb )
+{
+ return mMouseDownSignal.connect(cb);
+}
+boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb )
+{
+ return mMouseUpSignal.connect(cb);
+}
+boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb )
+{
+ return mHeldDownSignal.connect(cb);
+}
+
+boost::signals2::connection LLButton::setRightClickedCallback( const commit_signal_t::slot_type& cb )
+{
+ return mRightClickSignal.connect(cb);
}
+// *TODO: Deprecate (for backwards compatability only)
+boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data )
+{
+ return setClickedCallback(boost::bind(cb, data));
+}
+boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data )
+{
+ return setMouseDownCallback(boost::bind(cb, data));
+}
+boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data )
+{
+ return setMouseUpCallback(boost::bind(cb, data));
+}
+boost::signals2::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 +301,8 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char)
toggleState();
}
- if (mClickedCallback)
- {
- (*mClickedCallback)( mCallbackUserData );
- }
+ LLUICtrl::onCommit();
+
handled = TRUE;
}
return handled;
@@ -299,10 +320,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask )
handled = TRUE;
- if (mClickedCallback)
- {
- (*mClickedCallback)( mCallbackUserData );
- }
+ LLUICtrl::onCommit();
}
return handled;
}
@@ -318,13 +336,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 +360,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,31 +378,65 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask)
toggleState();
}
- if (mClickedCallback)
- {
- (*mClickedCallback)( mCallbackUserData );
- }
+ LLUICtrl::onCommit();
}
}
return TRUE;
}
+BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ // Route future Mouse messages here preemptively. (Release on mouse up.)
+ gFocusMgr.setMouseCapture( this );
-BOOL LLButton::handleHover(S32 x, S32 y, MASK mask)
+ if (hasTabStop() && !getIsChrome())
+ {
+ setFocus(TRUE);
+ }
+
+
+ return TRUE;
+}
+
+BOOL LLButton::handleRightMouseUp(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));
+ // We only handle the click if the click both started and ended within us
+ if( hasMouseCapture() )
+ {
+ // Always release the mouse
+ gFocusMgr.setMouseCapture( NULL );
- if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback)
+ if (pointInView(x, y))
+ {
+ mRightClickSignal(this, getValue());
+ }
+ }
+ return TRUE;
+}
+
+
+void LLButton::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ if (getEnabled())
+ mNeedsHighlight = TRUE;
+}
+
+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 +452,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 +476,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 +519,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 +559,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 +629,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 +643,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);
@@ -602,7 +655,7 @@ void LLButton::draw()
else
{
// no image
- llwarns << "No image for button " << getName() << llendl;
+ lldebugs << "No image for button " << getName() << llendl;
// draw it in pink so we can find it
gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1, FALSE);
}
@@ -634,7 +687,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 +760,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 +782,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 +809,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 )
@@ -816,8 +853,55 @@ void LLButton::setDisabledSelectedLabel( const LLStringExplicit& label )
void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
{
mImageUnselected = image;
+ if (mImageUnselected.isNull())
+ {
+ llwarns << "Setting default button image for: " << getName() << " to NULL" << llendl;
+ }
}
+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().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom));
+ }
+ }
+}
void LLButton::setImages( const std::string &image_name, const std::string &selected_name )
{
setImageUnselected(image_name);
@@ -845,14 +929,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 +957,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 +982,9 @@ void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign a
}
}
-
void LLButton::onMouseCaptureLost()
{
- mMouseDownTimer.stop();
- mMouseDownTimer.reset();
+ resetMouseDownTimer();
}
//-------------------------------------------------------------------------
@@ -975,28 +1056,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 +1069,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..1398e5c14b 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,81 @@ 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;
+
+ // 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 BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ virtual BOOL handleRightMouseUp(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 +151,27 @@ 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
- void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; }
+ 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::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button
+ boost::signals2::connection setRightClickedCallback( const commit_signal_t::slot_type& cb ); // right mouse down and up within button
+
+
+ // *TODO: Deprecate (for backwards compatability only)
+ 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; }
+
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 +201,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 +221,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 +245,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 +263,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 +319,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 +343,7 @@ private:
BOOL mNeedsHighlight;
BOOL mCommitOnReturn;
+ BOOL mFadeWhenDisabled;
std::string mHelpURL;
@@ -300,4 +352,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..932a1b6297 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;
-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 )
+template LLCheckBoxCtrl* LLView::getChild<LLCheckBoxCtrl>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+
+static LLDefaultWidgetRegistry::Register<LLCheckBoxCtrl> r("check_box");
+
+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 (self->mRadioStyle)
- {
- self->setValue(TRUE);
- }
-
- self->setControlValue(self->getValue());
- // HACK: because buttons don't normally commit
- self->onCommit();
+ //if (mRadioStyle)
+ //{
+ // setValue(TRUE);
+ //}
- 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..2f8f088a3e 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;
+
+ Ignored 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..51ab3326fe 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,129 @@
#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 LLDefaultWidgetRegistry::Register<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),
+ mHasAutocompletedText(false),
+ 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);
+ LLUICtrl::initFromParams(p);
- 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);
-
- 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 +201,7 @@ void LLComboBox::onCommit()
mTextEntry->setValue(getSimple());
mTextEntry->setTentative(FALSE);
}
+ setControlValue(getValue());
LLUICtrl::onCommit();
}
@@ -431,6 +396,7 @@ BOOL LLComboBox::remove(S32 index)
if (index < mList->getItemCount())
{
mList->deleteSingleItem(index);
+ setLabel(mList->getSelectedItemLabel());
return TRUE;
}
return FALSE;
@@ -448,21 +414,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 +460,47 @@ 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.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,73 @@ 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();
- if (last_selected_item)
- {
- // highlight the original selection before potentially selecting a new item
- self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item));
- }
+ // this might change selection, so do it first
+ prearrangeList();
- if( self->mPrearrangeCallback )
+ // highlight the last selected item from the original selection before potentially selecting a new item
+ // as visual cue to original value of combo box
+ LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
+ if (last_selected_item)
{
- self->mPrearrangeCallback( self, self->mCallbackUserData );
+ mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
}
- 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
+//------------------------------------------------------------------
+
+void LLComboBox::onItemSelected(const LLSD& data)
+{
+ const std::string name = mList->getSelectedItemLabel();
- S32 cur_id = self->getCurrentIndex();
+ 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 +758,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 +792,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,46 +804,35 @@ 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)
{
mTextEntry->setText(text);
+ mHasAutocompletedText = FALSE;
updateSelection();
}
}
-//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,14 @@ 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 )
- {
- self->mPrearrangeCallback( self, self->mCallbackUserData );
- }
+ prearrangeList();
- if (self->mList->getItemCount() != 0)
+ if (mList->getItemCount() != 0)
{
- self->showList();
+ showList();
}
}
line_editor->selectAll();
@@ -920,17 +860,14 @@ 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 )
- {
- self->mPrearrangeCallback( self, self->mCallbackUserData );
- }
+ prearrangeList();
- if (self->mList->getItemCount() != 0)
+ if (mList->getItemCount() != 0)
{
- self->showList();
+ showList();
}
}
line_editor->selectAll();
@@ -939,7 +876,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
else
{
// RN: presumably text entry
- self->updateSelection();
+ updateSelection();
}
}
@@ -948,7 +885,7 @@ void LLComboBox::updateSelection()
LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor());
// user-entered portion of string, based on assumption that any selected
// text was a result of auto-completion
- LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText();
+ LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText();
std::string full_string = mTextEntry->getText();
// go ahead and arrange drop down list on first typed character, even
@@ -956,23 +893,14 @@ void LLComboBox::updateSelection()
// callback to populate content
if( mTextEntry->getWText().size() == 1 )
{
- if (mPrearrangeCallback)
- {
- mPrearrangeCallback( this, mCallbackUserData );
- }
+ prearrangeList(mTextEntry->getText());
}
if (mList->selectItemByLabel(full_string, FALSE))
{
mTextEntry->setTentative(FALSE);
}
- else if (!mList->selectItemByPrefix(left_wstring, FALSE))
- {
- mList->deselectAllItems();
- mTextEntry->setText(wstring_to_utf8str(user_wstring));
- mTextEntry->setTentative(mTextEntryTentative);
- }
- else
+ else if (mList->selectItemByPrefix(left_wstring, FALSE))
{
LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel());
LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
@@ -980,17 +908,23 @@ void LLComboBox::updateSelection()
mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
mTextEntry->endSelection();
mTextEntry->setTentative(FALSE);
+ mHasAutocompletedText = TRUE;
+ }
+ else // no matching items found
+ {
+ mList->deselectAllItems();
+ mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion
+ mTextEntry->setTentative(mTextEntryTentative);
+ mHasAutocompletedText = FALSE;
}
}
-//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)
@@ -1007,6 +941,14 @@ void LLComboBox::setFocus(BOOL b)
}
}
+void LLComboBox::prearrangeList(std::string filter)
+{
+ if (mPrearrangeCallback)
+ {
+ mPrearrangeCallback(this, LLSD(filter));
+ }
+}
+
//============================================================================
// LLCtrlListInterface functions
@@ -1114,155 +1056,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..bc98690a01 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,62 @@ 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&);
+ void prearrangeList(std::string filter = "");
+
+public:
+ // LLView interface
virtual void draw();
virtual void onFocusLost();
- virtual void onLostTop();
virtual void setEnabled(BOOL enabled);
@@ -105,7 +136,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 +164,7 @@ public:
BOOL setCurrentByIndex( S32 index );
S32 getCurrentIndex() const;
- virtual void updateLayout();
+ void createLineEditor(const Params&);
//========================================================================
LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; };
@@ -170,66 +200,45 @@ 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();
-
+
+ virtual void onTextEntry(LLLineEditor* line_editor);
+
protected:
LLButton* mButton;
+ LLLineEditor* mTextEntry;
LLScrollListCtrl* mList;
EPreferredPosition mListPosition;
LLPointer<LLUIImage> mArrowImage;
- std::string mLabel;
+ LLUIString mLabel;
+ BOOL mHasAutocompletedText;
private:
- S32 mButtonPadding;
- LLLineEditor* mTextEntry;
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..40cc430e25
--- /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 LLDefaultWidgetRegistry::Register<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..8932a7ccf2 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,125 @@ 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
+}
+
+//************************************
+
+//static
+const LLFloater::Params& LLFloater::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLFloater::Params>();
+}
+
+
+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;
+ sButtonToolTips[i] =LLTrans::getString( sButtonToolTipsIndex[i]);
}
- for (S32 i = 0; i < 4; i++)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
- 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 +260,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 +457,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 +511,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 +547,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 +560,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 +594,7 @@ void LLFloater::close(bool app_quitting)
if (floaterp)
{
++dependent_it;
- floaterp->close();
+ floaterp->closeFloater(app_quitting);
}
else
{
@@ -597,7 +621,7 @@ void LLFloater::close(bool app_quitting)
}
}
}
-
+
// Let floater do cleanup.
onClose(app_quitting);
}
@@ -607,6 +631,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 +689,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 +796,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 +811,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 +849,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 +867,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 +938,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
{
@@ -996,6 +1032,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)
{
// chrome floaters don't take focus at all
@@ -1276,19 +1319,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 +1339,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 +1359,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 +1414,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 +1429,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 +1448,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 +1465,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 +1533,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 +1557,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 +1571,7 @@ void LLFloater::setCanMinimize(BOOL can_minimize)
void LLFloater::setCanClose(BOOL can_close)
{
+ mCanClose = can_close;
mButtonsEnabled[BUTTON_CLOSE] = can_close;
updateButtons();
@@ -1538,83 +1586,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 +1608,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 +1629,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 +1653,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 +1713,12 @@ 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)
+ ,mSnapOffsetRight(0)
{
- setTabStop(FALSE);
- resetStartingFloaterPosition();
}
// By default, adjust vertical.
@@ -1830,69 +1812,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 +2023,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 +2045,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 +2100,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 +2123,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());
@@ -2302,11 +2222,12 @@ LLRect LLFloaterView::getSnapRect() const
{
LLRect snap_rect = getRect();
snap_rect.mBottom += mSnapOffsetBottom;
+ snap_rect.mRight -= mSnapOffsetRight;
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 +2240,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 +2253,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 +2269,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 +2321,7 @@ void LLFloaterView::syncFloaterTabOrder()
}
}
-LLFloater* LLFloaterView::getParentFloater(LLView* viewp)
+LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const
{
LLView* parentp = viewp->getParent();
@@ -2426,641 +2380,166 @@ 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)
-{
-
-}
-
-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)
+void LLFloater::setInstanceName(const std::string& name)
{
- 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())
- {
- //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
+ if (!mVisibilityControl.empty())
{
- //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)
+//static
+void LLFloater::setupParamsForExport(Params& p, LLView* parent)
{
- 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();
+ // Do rectangle munging to topleft layout first
+ LLPanel::setupParamsForExport(p, parent);
- // 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);
- }
+ // Copy the rectangle out to apply layout constraints
+ LLRect rect = p.rect;
- //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;
+ // Null out other settings
+ p.rect.left.setProvided(false);
+ p.rect.top.setProvided(false);
+ p.rect.right.setProvided(false);
+ p.rect.bottom.setProvided(false);
- updateResizeLimits();
+ // Explicitly set width/height
+ p.rect.width.set( rect.getWidth(), true );
+ p.rect.height.set( rect.getHeight(), true );
- if ( select_added_floater )
- {
- mTabContainer->selectTabPanel(floaterp);
- }
- else
+ // If you can't resize this floater, don't export min_height
+ // and min_width
+ bool can_resize = p.can_resize;
+ if (!can_resize)
{
- // reassert visible tab (hiding new floater if necessary)
- mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
- }
-
- floaterp->setHost(this);
- if (isMinimized())
- {
- floaterp->setVisible(FALSE);
+ p.min_height.setProvided(false);
+ p.min_width.setProvided(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)
+void LLFloater::initFromParams(const LLFloater::Params& p)
{
- return mTabContainer->selectTabPanel(floaterp);
-}
+ // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
+ LLPanel::initFromParams(p);
-// virtual
-void LLMultiFloater::selectNextFloater()
-{
- mTabContainer->selectNextTab();
-}
+ mTitle = p.title;
+ mShortTitle = p.short_title;
+ applyTitle();
-// virtual
-void LLMultiFloater::selectPrevFloater()
-{
- mTabContainer->selectPrevTab();
-}
+ 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;
-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 (p.save_rect)
{
- addFloater(floaterp, TRUE);
+ mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set
}
-}
-
-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())
+ if (p.save_visibility)
{
- 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);
+ mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
}
- 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)
+void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater, LLXMLNodePtr output_node)
{
- // default implementation does nothing
-}
+ Params params(LLUICtrlFactory::getDefaultParams<LLFloater::Params>());
+ LLXUIParser::instance().readXUI(node, params);
-void LLMultiFloater::tabClose()
-{
- if (mTabContainer->getTabCount() == 0)
+ if (output_node)
{
- // no more children, close myself
- close();
+ 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::setVisible(BOOL visible)
-{
- // *FIX: shouldn't have to do this, fix adding to minimized multifloater
- LLFloater::setVisible(visible);
+ setupParams(params, parent);
+ initFromParams(params);
+
+ initFloater();
- if (mTabContainer)
+ LLMultiFloater* last_host = LLFloater::getFloaterHost();
+ if (node->hasName("multi_floater"))
{
- LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
+ LLFloater::setFloaterHost((LLMultiFloater*) this);
+ }
- if (cur_floaterp)
- {
- cur_floaterp->setVisible(visible);
- }
+ LLUICtrlFactory::createChildren(this, node, output_node);
- // if no tab selected, and we're being shown,
- // select last tab to be added
- if (visible && !cur_floaterp)
- {
- mTabContainer->selectLastTab();
- }
+ if (node->hasName("multi_floater"))
+ {
+ LLFloater::setFloaterHost(last_host);
}
-}
+
+ 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
+void VisibilityPolicy<LLFloater>::hide(LLFloater* instance, const LLSD& key)
{
- 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)
-{
- 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..3e80f1b284 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,69 @@ 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;
+ }
+ };
+
+ // use this to avoid creating your own default LLFloater::Param instance
+ static const Params& getDefaultParams();
+
+ LLFloater(const LLSD& key = LLSD(), const Params& params = getDefaultParams());
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);
+ // Don't export top/left for rect, only height/width
+ static void setupParamsForExport(Params& p, LLView* parent);
- /*virtual*/ void userSetShape(const LLRect& new_rect);
+ void initFromParams(const LLFloater::Params& p);
+ void initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL);
+
+ /*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 +176,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 +205,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 +217,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 +229,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 +243,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 +258,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 +297,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 +356,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 +370,10 @@ private:
BOOL mHasBeenDraggedWhileMinimized;
S32 mPreviousMinimizedBottom;
S32 mPreviousMinimizedLeft;
-
+
+ LLColor4 mBgColorAlpha;
+ LLColor4 mBgColorOpaque;
+
LLFloaterNotificationContext* mNotificationContext;
LLRootHandle<LLFloater> mHandle;
};
@@ -331,18 +384,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 +418,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
@@ -377,6 +430,7 @@ public:
S32 getZOrder(LLFloater* child);
void setSnapOffsetBottom(S32 offset) { mSnapOffsetBottom = offset; }
+ void setSnapOffsetRight(S32 offset) { mSnapOffsetRight = offset; }
private:
S32 mColumn;
@@ -384,101 +438,26 @@ private:
S32 mNextTop;
BOOL mFocusCycleMode;
S32 mSnapOffsetBottom;
+ S32 mSnapOffsetRight;
};
-// 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 +468,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..ef2f71ad18
--- /dev/null
+++ b/indra/llui/llfloaterreg.h
@@ -0,0 +1,152 @@
+/**
+ * @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$
+ */
+#ifndef LLFLOATERREG_H
+#define LLFLOATERREG_H
+
+/// 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));
+ }
+
+};
+
+#endif
diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp
new file mode 100644
index 0000000000..8846f2a8c4
--- /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 LLDefaultWidgetRegistry::Register<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.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.
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..eddfc71284 100644
--- a/indra/llui/lliconctrl.cpp
+++ b/indra/llui/lliconctrl.cpp
@@ -40,65 +40,33 @@
#include "llcontrol.h"
#include "llui.h"
#include "lluictrlfactory.h"
+#include "lluiimage.h"
-const F32 RESOLUTION_BUMP = 1.f;
+static LLDefaultWidgetRegistry::Register<LLIconCtrl> r("icon");
-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..a6cab0e9ee 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;
+ Ignored 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..39dac296ea
--- /dev/null
+++ b/indra/llui/lllayoutstack.cpp
@@ -0,0 +1,740 @@
+/**
+ * @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"
+
+static LLDefaultWidgetRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack", &LLLayoutStack::fromXML);
+
+
+//
+// LLLayoutStack
+//
+struct LLLayoutStack::LayoutPanel
+{
+ LayoutPanel(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;
+ }
+ }
+
+ ~LayoutPanel()
+ {
+ // 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;
+};
+
+LLLayoutStack::Params::Params()
+: orientation("orientation", std::string("vertical")),
+ animate("animate", TRUE),
+ 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),
+ mAnimate(p.animate)
+{}
+
+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)
+{
+ LayoutPanel* 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);
+
+ // Export must happen before setupParams() mungles rectangles and before
+ // this item gets added to parent (otherwise screws up last_child_rect
+ // logic). JC
+ 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);
+ }
+
+ 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);
+ }
+
+ 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::Params p;
+ LLPanel* panelp = LLUICtrlFactory::create<LLPanel>(p);
+ LLView* new_child = LLUICtrlFactory::getInstance()->createFromXML(child_node, panelp, LLStringUtil::null, output_child, parent ? parent->getChildRegistry() : LLDefaultWidgetRegistry::instance());
+ 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);
+ }
+ LayoutPanel* embedded_panel = new LayoutPanel(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)
+{
+ LayoutPanel* 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())
+ {
+ if (mAnimate)
+ {
+ (*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
+ {
+ (*panel_it)->mVisibleAmt = 1.f;
+ }
+ }
+ else // not visible
+ {
+ if (mAnimate)
+ {
+ (*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;
+ }
+ }
+ else
+ {
+ (*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::LayoutPanel* 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..480bdb5c17
--- /dev/null
+++ b/indra/llui/lllayoutstack.h
@@ -0,0 +1,105 @@
+/**
+ * @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;
+ Optional<bool> animate;
+ // 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 LayoutPanel;
+
+ void updateLayout(BOOL force_resize = FALSE);
+ void calcMinExtents();
+ S32 getDefaultHeight(S32 cur_height);
+ S32 getDefaultWidth(S32 cur_width);
+
+ const ELayoutOrientation mOrientation;
+
+ typedef std::vector<LayoutPanel*> e_panel_list_t;
+ e_panel_list_t mPanels;
+ LayoutPanel* findEmbeddedPanel(LLPanel* panelp) const;
+
+ S32 mMinWidth; // calculated by calcMinExtents
+ S32 mMinHeight; // calculated by calcMinExtents
+ S32 mPanelSpacing;
+
+ bool mAnimate;
+}; // end class LLLayoutStack
+
+#endif
diff --git a/indra/llui/lllazyvalue.h b/indra/llui/lllazyvalue.h
new file mode 100644
index 0000000000..cf45214628
--- /dev/null
+++ b/indra/llui/lllazyvalue.h
@@ -0,0 +1,88 @@
+/**
+ * @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;
+ }
+
+ bool isUsingFunction() const
+ {
+ return mValueGetter != NULL;
+ }
+
+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..5ea45e13cf 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,104 @@
// 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 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval?
-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 LLDefaultWidgetRegistry::Register<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();
+ mTripleClickTimer.reset();
+ setText(p.default_text());
// line history support:
// - initialize line history list
@@ -146,40 +173,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 +238,7 @@ void LLLineEditor::onCommit()
// put current line into the line history
updateHistory();
+ setControlValue(getValue());
LLUICtrl::onCommit();
selectAll();
}
@@ -255,7 +267,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 +285,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 +375,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));
@@ -439,6 +452,7 @@ void LLLineEditor::selectAll()
BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
{
setFocus( TRUE );
+ mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL);
if (mSelectionEnd == 0 && mSelectionStart == mText.length())
{
@@ -555,14 +569,25 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
}
else
{
- // Save selection for word/line selecting on double-click
- mLastSelectionStart = mSelectionStart;
- mLastSelectionEnd = mSelectionEnd;
+ if (mTripleClickTimer.hasExpired())
+ {
+ // Save selection for word/line selecting on double-click
+ mLastSelectionStart = mSelectionStart;
+ mLastSelectionEnd = mSelectionEnd;
- // Move cursor and deselect for regular click
- setCursorAtLocalPos( x );
- deselect();
- startSelection();
+ // Move cursor and deselect for regular click
+ setCursorAtLocalPos( x );
+ deselect();
+ startSelection();
+ }
+ else // handle triple click
+ {
+ selectAll();
+ // We don't want handleMouseUp() to "finish" the selection (and thereby
+ // set mSelectionEnd to where the mouse is), so we finish the selection
+ // here.
+ mIsSelecting = FALSE;
+ }
}
gFocusMgr.setMouseCapture( this );
@@ -936,7 +961,7 @@ void LLLineEditor::cut()
else
if( mKeystrokeCallback )
{
- mKeystrokeCallback( this, mCallbackUserData );
+ mKeystrokeCallback( this );
}
}
}
@@ -1057,7 +1082,7 @@ void LLLineEditor::pasteHelper(bool is_primary)
else
if( mKeystrokeCallback )
{
- mKeystrokeCallback( this, mCallbackUserData );
+ mKeystrokeCallback( this );
}
}
}
@@ -1370,7 +1395,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
{
if (mKeystrokeCallback)
{
- mKeystrokeCallback(this, mCallbackUserData);
+ mKeystrokeCallback(this);
}
}
}
@@ -1420,7 +1445,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 +1486,7 @@ void LLLineEditor::doDelete()
{
if( mKeystrokeCallback )
{
- mKeystrokeCallback( this, mCallbackUserData );
+ mKeystrokeCallback( this );
}
}
}
@@ -1471,6 +1496,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 +1523,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 +1540,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 +1561,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 +1591,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 +1611,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 +1636,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 +1656,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 +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);
@@ -1647,7 +1685,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 +1706,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 +1720,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 +1749,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 +1774,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 +1891,7 @@ void LLLineEditor::setRect(const LLRect& rect)
}
}
-void LLLineEditor::setPrevalidate(BOOL (*func)(const LLWString &))
+void LLLineEditor::setPrevalidate(LLLinePrevalidateFunc func)
{
mPrevalidateFunc = func;
updateAllowingLanguageInput();
@@ -2169,244 +2211,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
+void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data)
{
- 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;
+ mKeystrokeCallback = boost::bind(callback, _1, user_data);
}
-// 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)
-{
- 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;
-}
-
-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 +2238,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 +2328,7 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string,
mKeystrokeTimer.reset();
if( mKeystrokeCallback )
{
- mKeystrokeCallback( this, mCallbackUserData );
+ mKeystrokeCallback( this );
}
}
@@ -2656,146 +2471,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)
+namespace LLInitParam
{
- 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
-{
- 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();
-}
-
-
-//static
-void LLSearchEditor::onSearchEdit(LLLineEditor* caller, void* user_data )
-{
- LLSearchEditor* search_editor = (LLSearchEditor*)user_data;
- if (search_editor->mSearchCallback)
+ template<>
+ bool ParamCompare<LLLinePrevalidateFunc>::equals(const LLLinePrevalidateFunc &a, const LLLinePrevalidateFunc &b)
{
- search_editor->mSearchCallback(caller->getText(), search_editor->mCallbackUserData);
+ return false;
}
-}
-
-//static
-void LLSearchEditor::onClearSearch(void* user_data)
-{
- LLSearchEditor* search_editor = (LLSearchEditor*)user_data;
- search_editor->setText(LLStringUtil::null);
- if (search_editor->mSearchCallback)
+ template<>
+ bool ParamCompare<boost::function<void (LLLineEditor *)> >::equals(
+ const boost::function<void (LLLineEditor *)> &a,
+ const boost::function<void (LLLineEditor *)> &b)
{
- search_editor->mSearchCallback(LLStringUtil::null, search_editor->mCallbackUserData);
+ return false;
}
}
-
-// 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))
- {
- search_editor->mSearchEdit->setLabel(label);
- }
-
- 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..eb021bace9 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;
+
+ Ignored 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,18 @@ protected:
S32 mLastSelectionStart;
S32 mLastSelectionEnd;
- S32 (*mPrevalidateFunc)(const LLWString &str);
+ LLLinePrevalidateFunc mPrevalidateFunc;
LLFrameTimer mKeystrokeTimer;
+ LLTimer mTripleClickTimer;
- 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 +348,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 +392,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 a8d06643ff..4af1c1241b 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -59,16 +59,12 @@
#include "llresmgr.h"
#include "llui.h"
-#include "lluitrans.h"
-
#include "llstl.h"
#include "v2math.h"
#include <set>
#include <boost/tokenizer.hpp>
-using namespace LLOldEvents;
-
// static
LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
@@ -80,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( "|" );
@@ -112,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;
@@ -130,72 +119,75 @@ const F32 PIE_SHRINK_TIME = 0.2f; // time of transition between unbounded and bo
const F32 ACTIVATE_HIGHLIGHT_TIME = 0.3f;
+// widget registrars
+struct MenuRegistry : public LLWidgetRegistry<MenuRegistry>
+{};
+
+static MenuRegistry::Register<LLMenuItemSeparatorGL> register_separator("menu_item_separator");
+static MenuRegistry::Register<LLMenuItemCallGL> register_menu_item_call("menu_item_call");
+static MenuRegistry::Register<LLMenuItemCheckGL> register_menu_item_check("menu_item_check");
+static MenuRegistry::Register<LLMenuGL> register_menu("menu");
+
+static LLDefaultWidgetRegistry::Register<LLMenuGL> register_menu_default("menu");
+
+
+
///============================================================================
/// 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 )
+ 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())
{
- setLabel( label );
-}
-
-// virtual
-LLXMLNodePtr LLMenuItemGL::getXML(bool save_children) const
-{
- 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;
@@ -271,24 +263,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 );
@@ -356,7 +348,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)
@@ -365,6 +357,8 @@ void LLMenuItemGL::doIt( void )
{
LLMenuGL::sMenuContainer->hideMenus();
}
+
+ LLUICtrl::onCommit();
}
// set the hover status (called by it's menu)
@@ -404,7 +398,7 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask )
// switch to keyboard navigation mode
LLMenuGL::setKeyboardMode(TRUE);
- doIt();
+ onCommit();
return TRUE;
}
}
@@ -412,25 +406,30 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask )
return FALSE;
}
-BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK )
+BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK mask)
{
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
- doIt();
+ onCommit();
make_ui_sound("UISndClickRelease");
- return TRUE;
+ return LLView::handleMouseUp(x, y, mask);
}
-BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK )
+BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask)
{
// switch to mouse navigation mode
LLMenuGL::setKeyboardMode(FALSE);
setHighlight(TRUE);
- return TRUE;
+ return LLView::handleMouseDown(x, y, mask);
}
+BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ // If the menu is scrollable let it handle the wheel event.
+ return !getMenu()->isScrollable();
+}
void LLMenuItemGL::draw( void )
{
@@ -441,55 +440,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 );
}
}
@@ -517,38 +519,39 @@ 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.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-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 );
@@ -559,11 +562,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;
}
}
@@ -572,11 +577,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;
}
}
@@ -595,7 +602,6 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask)
}
}
-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuItemVerticalSeparatorGL
//
@@ -619,19 +625,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
{
@@ -641,7 +647,7 @@ void LLMenuItemTearOffGL::doIt()
getMenu()->highlightNextItem(this);
}
- getMenu()->arrange();
+ getMenu()->needsArrange();
LLFloater* parent_floater = mParentHandle.get();
LLFloater* tear_off_menu = LLTearOffMenu::create(getMenu());
@@ -658,7 +664,7 @@ void LLMenuItemTearOffGL::doIt()
tear_off_menu->setFocus(TRUE);
}
}
- LLMenuItemGL::doIt();
+ LLMenuItemGL::onCommit();
}
void LLMenuItemTearOffGL::draw()
@@ -666,17 +672,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;
@@ -699,11 +705,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 ) {}
};
@@ -712,238 +723,113 @@ public:
/// Class LLMenuItemCallGL
///============================================================================
-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
///============================================================================
-
-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;
}
@@ -953,68 +839,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;
}
@@ -1022,64 +861,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()))
- {
- llerrs << "Non-menu handle passed as branch reference." << llendl;
- }
-
- if(getBranch())
+ LLMenuGL* branch = p.branch;
+ if (branch)
{
- 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;
}
- return LLView::getChildView(name, recurse, create_if_missing);;
+ // Always recurse on branches
+ LLView* child = branch->getChildView(name, recurse, FALSE);
+ if (!child)
+ {
+ child = LLView::getChildView(name, recurse, create_if_missing);
+ }
+ return child;
}
// virtual
@@ -1088,49 +911,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;
}
@@ -1145,23 +954,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);
}
@@ -1177,7 +987,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);
}
@@ -1193,21 +1003,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;
}
@@ -1221,14 +1031,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 );
}
}
}
@@ -1262,15 +1072,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())
{
@@ -1281,12 +1095,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;
@@ -1298,39 +1112,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 )
@@ -1344,9 +1160,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);
}
}
@@ -1363,10 +1179,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
@@ -1394,11 +1207,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)
{
}
@@ -1503,7 +1313,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;
}
@@ -1542,7 +1352,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;
@@ -1556,7 +1366,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;
@@ -1568,7 +1378,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
if (!isActive())
{
- doIt();
+ onCommit();
}
getBranch()->highlightNextItem(NULL);
return TRUE;
@@ -1580,7 +1390,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask)
if (!isActive())
{
- doIt();
+ onCommit();
}
getBranch()->highlightPrevItem(NULL);
return TRUE;
@@ -1600,31 +1410,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
@@ -1647,22 +1457,107 @@ void LLMenuItemBranchDownGL::draw( void )
setHover(FALSE);
}
+class LLMenuScrollItem : public LLMenuItemCallGL
+{
+public:
+ enum EArrowType
+ {
+ ARROW_DOWN,
+ ARROW_UP
+ };
+
+ struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
+ {
+ Optional<EArrowType> arrow_type;
+ Optional<CommitCallbackParam> scroll_callback;
+ };
+
+protected:
+ LLMenuScrollItem(const Params&);
+ friend class LLUICtrlFactory;
+
+public:
+ /*virtual*/ void draw();
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
+ /*virtual*/ void setEnabled(BOOL enabled);
+ virtual void onCommit( void );
+
+private:
+ LLButton* mArrowBtn;
+};
+
+LLMenuScrollItem::LLMenuScrollItem(const Params& p)
+: LLMenuItemCallGL(p)
+{
+ std::string icon;
+ if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP)
+ {
+ icon = "arrow_up.tga";
+ }
+ else
+ {
+ icon = "arrow_down.tga";
+ }
+
+ LLButton::Params bparams;
+ bparams.label("");
+ bparams.label_selected("");
+ bparams.mouse_opaque(true);
+ bparams.scale_image(false);
+ bparams.click_callback(p.scroll_callback);
+ bparams.mouse_held_callback(p.scroll_callback);
+ bparams.follows.flags(FOLLOWS_ALL);
+ std::string background = "transparent.j2c";
+ bparams.image_unselected.name(background);
+ bparams.image_disabled.name(background);
+ bparams.image_selected.name(background);
+ bparams.image_hover_selected.name(background);
+ bparams.image_disabled_selected.name(background);
+ bparams.image_hover_unselected.name(background);
+ bparams.image_overlay.name(icon);
+
+ mArrowBtn = LLUICtrlFactory::create<LLButton>(bparams);
+ addChild(mArrowBtn);
+}
+
+/*virtual*/
+void LLMenuScrollItem::draw()
+{
+ LLUICtrl::draw();
+}
+
+/*virtual*/
+void LLMenuScrollItem::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ mArrowBtn->reshape(width, height, called_from_parent);
+ LLView::reshape(width, height, called_from_parent);
+}
+
+/*virtual*/
+void LLMenuScrollItem::setEnabled(BOOL enabled)
+{
+ mArrowBtn->setEnabled(enabled);
+ LLView::setEnabled(enabled);
+}
+
+void LLMenuScrollItem::onCommit( void )
+{
+ LLUICtrl::onCommit();
+}
+
///============================================================================
/// Class LLMenuGL
///============================================================================
-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 ),
+ mScrollable(mHorizontalLayout ? FALSE : p.scrollable), // Scrolling is supported only for vertical layout
+ mKeepFixedSize( p.keep_fixed_size ),
+ mLabel (p.label),
mLastMouseX(0),
mLastMouseY(0),
mMouseVelX(0),
@@ -1670,38 +1565,40 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label, LLHandle<
mTornOff(FALSE),
mTearOffItem(NULL),
mSpilloverBranch(NULL),
+ mFirstVisibleItem(NULL),
+ mArrowUpItem(NULL),
+ mArrowDownItem(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
@@ -1717,10 +1614,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)
{
@@ -1728,315 +1625,51 @@ 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)
+ item_list_t::iterator found_it = std::find(mItems.begin(), mItems.end(), (itemp));
+ if (found_it != mItems.end())
{
- submenu->updateParent(LLMenuGL::sMenuContainer);
- }
- else
- {
- 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;
-
- std::string type;
- std::string item_name;
- std::string source_label;
- std::string item_label;
- KEY jump_key = KEY_NONE;
-
- 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;
- }
-
-
- 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;
+ return LLUICtrl::removeChild(ctrl);
+}
- 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);
- }
+BOOL LLMenuGL::postBuild()
+{
+ createJumpKeys();
+ return LLUICtrl::postBuild();
+}
- if (item != NULL)
- {
- append(item);
- }
- }
- }
+const widget_registry_t& LLMenuGL::getChildRegistry() const
+{
+ return MenuRegistry::instance();
}
+
// 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()
@@ -2081,77 +1714,88 @@ 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;
+void LLMenuGL::scrollItemsUp()
+{
+ // Slowing down the items scrolling when arrow button is held
+ if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem)
+ {
+ mScrollItemsTimer.setTimerExpirySec(.033f);
+ }
+ else
+ {
+ return;
+ }
- KEY jump_key = KEY_NONE;
- S32 token_count = 0;
- for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
+ item_list_t::iterator cur_item_iter;
+ item_list_t::iterator prev_item_iter;
+ for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- new_menu_label += (*token_iter);
- if (token_count > 0)
+ if( (*cur_item_iter) == mFirstVisibleItem)
{
- jump_key = (*token_iter).c_str()[0];
+ break;
+ }
+ if ((*cur_item_iter)->getVisible())
+ {
+ prev_item_iter = cur_item_iter;
}
- ++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 ((*prev_item_iter)->getVisible())
+ {
+ mFirstVisibleItem = *prev_item_iter;
+ }
+
+ mNeedsArrange = TRUE;
+ arrangeAndClear();
+}
- if (node->hasAttribute("drop_shadow"))
+void LLMenuGL::scrollItemsDown()
+{
+ // Slowing down the items scrolling when arrow button is held
+ if (mScrollItemsTimer.hasExpired())
+ {
+ mScrollItemsTimer.setTimerExpirySec(.033f);
+ }
+ else
+ {
+ return;
+ }
+
+ if (NULL == mFirstVisibleItem)
{
- BOOL drop_shadow = FALSE;
- node->getAttributeBOOL("drop_shadow", drop_shadow);
- menu->setDropShadowed(drop_shadow);
+ mFirstVisibleItem = *mItems.begin();
}
- menu->setBackgroundVisible(opaque);
- LLColor4 color(0,0,0,1);
- if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color))
+ item_list_t::iterator cur_item_iter;
+
+ for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++)
{
- menu->setBackgroundColor(color);
+ if( (*cur_item_iter) == mFirstVisibleItem)
+ {
+ break;
+ }
}
- BOOL create_jump_keys = FALSE;
- node->getAttributeBOOL("create_jump_keys", create_jump_keys);
+ item_list_t::iterator next_item_iter;
- LLXMLNodePtr child;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+ for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++)
{
- menu->parseChildXML(child, parent, factory);
+ if( (*next_item_iter)->getVisible())
+ {
+ break;
+ }
}
- if (create_jump_keys)
+ if ((*next_item_iter)->getVisible())
{
- menu->createJumpKeys();
+ mFirstVisibleItem = *next_item_iter;
}
- return menu;
+
+ mNeedsArrange = TRUE;
+ arrangeAndClear();
}
-
// rearrange the child rects so they fit the shape of the menu.
void LLMenuGL::arrange( void )
{
@@ -2169,11 +1813,26 @@ void LLMenuGL::arrange( void )
// torn off menus are not constrained to the size of the screen
U32 max_width = getTornOff() ? U32_MAX : menu_region_rect.getWidth();
- U32 max_height = getTornOff() ? U32_MAX : menu_region_rect.getHeight();
+ U32 max_height = U32_MAX;
+ if (!getTornOff())
+ {
+ max_height = getRect().mTop - menu_region_rect.mBottom;
+ if (menu_region_rect.mTop - getRect().mTop > (S32)max_height)
+ {
+ max_height = menu_region_rect.mTop - getRect().mTop;
+ }
+ }
+
// *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;
+ // Scrolling support
+ item_list_t::iterator first_visible_item_iter;
+ item_list_t::iterator first_hidden_item_iter = mItems.end();
+ S32 height_before_first_visible_item = -1;
+ S32 visible_items_height = 0;
+
if (mHorizontalLayout)
{
item_list_t::iterator item_iter;
@@ -2182,26 +1841,27 @@ void LLMenuGL::arrange( void )
if ((*item_iter)->getVisible())
{
if (!getTornOff()
- && item_iter != mItems.begin() // Don't spillover the first item!
+ && *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->appendNoArrange(itemp); // *NOTE:Mani Favor addChild() in merge with skinning
+ mSpilloverMenu->addChild(itemp);
}
- mSpilloverMenu->arrange(); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mItems.erase(item_iter, mItems.end());
- mItems.push_back(mSpilloverBranch);
+
addChild(mSpilloverBranch);
+
height = llmax(height, mSpilloverBranch->getNominalHeight());
width += mSpilloverBranch->getNominalWidth();
+
break;
}
else
@@ -2216,31 +1876,35 @@ void LLMenuGL::arrange( void )
else
{
item_list_t::iterator item_iter;
+
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter)->getVisible())
{
if (!getTornOff()
- && item_iter != mItems.begin() // Don't spillover the first item!
+ && !mScrollable
+ && *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->appendNoArrange(itemp); // *NOTE:Mani Favor addChild() in merge with skinning
+ mSpilloverMenu->addChild(itemp);
}
- mSpilloverMenu->arrange(); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mSpilloverMenu->updateParent(LLMenuGL::sMenuContainer); // *NOTE: Mani Remove line in merge with skinning/viewer2.0 branch
- mItems.erase(item_iter, mItems.end());
- mItems.push_back(mSpilloverBranch);
+
+
addChild(mSpilloverBranch);
+
height += mSpilloverBranch->getNominalHeight();
width = llmax( width, mSpilloverBranch->getNominalWidth() );
+
break;
}
else
@@ -2249,19 +1913,164 @@ void LLMenuGL::arrange( void )
height += (*item_iter)->getNominalHeight();
width = llmax( width, (*item_iter)->getNominalWidth() );
}
+
+ if (mScrollable)
+ {
+ // Determining visible items boundaries
+ if (NULL == mFirstVisibleItem)
+ {
+ mFirstVisibleItem = *item_iter;
+ }
+
+ if (*item_iter == mFirstVisibleItem)
+ {
+ height_before_first_visible_item = height - (*item_iter)->getNominalHeight();
+ first_visible_item_iter = item_iter;
+ }
+
+ if (-1 != height_before_first_visible_item && 0 == visible_items_height && height - height_before_first_visible_item > max_height - spillover_item_height * 2)
+ {
+ first_hidden_item_iter = item_iter;
+ visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight();
+ }
+ }
}
}
- }
- setRect(LLRect(getRect().mLeft, getRect().mBottom + height, getRect().mLeft + width, getRect().mBottom));
+ if (mScrollable)
+ {
+ S32 max_items_height = max_height - spillover_item_height * 2;
+
+ // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit
+ if (visible_items_height < max_items_height)
+ {
+ if (visible_items_height == 0)
+ {
+ visible_items_height = height - height_before_first_visible_item;
+ }
+
+ item_list_t::iterator tmp_iter(first_visible_item_iter);
+ while (visible_items_height < max_items_height && first_visible_item_iter != mItems.begin())
+ {
+ if ((*first_visible_item_iter)->getVisible())
+ {
+ // It keeps visible item, after first_visible_item_iter
+ tmp_iter = first_visible_item_iter;
+ }
+
+ first_visible_item_iter--;
+
+ if ((*first_visible_item_iter)->getVisible())
+ {
+ visible_items_height += (*first_visible_item_iter)->getNominalHeight();
+ height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight();
+ }
+ }
+
+ // Roll back one item, that doesn't fit
+ if (visible_items_height > max_items_height)
+ {
+ visible_items_height -= (*first_visible_item_iter)->getNominalHeight();
+ height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight();
+ first_visible_item_iter = tmp_iter;
+ }
+ if (!(*first_visible_item_iter)->getVisible())
+ {
+ first_visible_item_iter = tmp_iter;
+ }
+
+ mFirstVisibleItem = *first_visible_item_iter;
+ }
+ }
+ }
S32 cur_height = (S32)llmin(max_height, height);
+
+ if (mScrollable &&
+ (height_before_first_visible_item > MENU_ITEM_PADDING ||
+ height_before_first_visible_item + visible_items_height < (S32)height))
+ {
+ // Reserving 2 extra slots for arrow items
+ cur_height = visible_items_height + spillover_item_height * 2;
+ }
+
+ setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height));
+
S32 cur_width = 0;
+ S32 offset = 0;
+ if (mScrollable)
+ {
+ // No space for all items, creating arrow items
+ if (height_before_first_visible_item > MENU_ITEM_PADDING ||
+ height_before_first_visible_item + visible_items_height < (S32)height)
+ {
+ if (NULL == mArrowUpItem)
+ {
+ LLMenuScrollItem::Params item_params;
+ item_params.name(ARROW_UP);
+ item_params.arrow_type(LLMenuScrollItem::ARROW_UP);
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsUp, this));
+
+ mArrowUpItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
+ LLUICtrl::addChild(mArrowUpItem);
+
+ }
+ if (NULL == mArrowDownItem)
+ {
+ LLMenuScrollItem::Params item_params;
+ item_params.name(ARROW_DOWN);
+ item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN);
+ item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItemsDown, this));
+
+ mArrowDownItem = LLUICtrlFactory::create<LLMenuScrollItem>(item_params);
+ LLUICtrl::addChild(mArrowDownItem);
+ }
+
+ LLRect rect;
+ mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight()));
+ mArrowUpItem->setVisible(TRUE);
+ mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING);
+ mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight());
+ mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight()));
+ mArrowDownItem->setVisible(TRUE);
+ mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height);
+ mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight());
+
+ cur_height -= mArrowUpItem->getNominalHeight();
+
+ offset = menu_region_rect.mRight; // This moves items behind visible area
+ }
+ else
+ {
+ if (NULL != mArrowUpItem)
+ {
+ mArrowUpItem->setVisible(FALSE);
+ }
+ if (NULL != mArrowDownItem)
+ {
+ mArrowDownItem->setVisible(FALSE);
+ }
+ }
+
+ }
+
item_list_t::iterator item_iter;
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
{
if ((*item_iter)->getVisible())
{
+ if (mScrollable)
+ {
+ if (item_iter == first_visible_item_iter)
+ {
+ offset = 0;
+ }
+ else if (item_iter == first_hidden_item_iter)
+ {
+ offset = menu_region_rect.mRight; // This moves items behind visible area
+ }
+ }
+
// setup item rect to hold label
LLRect rect;
if (mHorizontalLayout)
@@ -2271,8 +2080,11 @@ void LLMenuGL::arrange( void )
}
else
{
- rect.setLeftTopAndSize( 0, cur_height, width, (*item_iter)->getNominalHeight());
- cur_height -= (*item_iter)->getNominalHeight();
+ rect.setLeftTopAndSize( 0 + offset, cur_height, width, (*item_iter)->getNominalHeight());
+ if (offset == 0)
+ {
+ cur_height -= (*item_iter)->getNominalHeight();
+ }
}
(*item_iter)->setRect( rect );
(*item_iter)->buildDrawLabel();
@@ -2285,6 +2097,15 @@ void LLMenuGL::arrange( void )
}
}
+void LLMenuGL::arrangeAndClear( void )
+{
+ if (mNeedsArrange)
+ {
+ arrange();
+ mNeedsArrange = FALSE;
+ }
+}
+
void LLMenuGL::createSpilloverBranch()
{
if (!mSpilloverBranch)
@@ -2293,14 +2114,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);
}
}
@@ -2311,25 +2142,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;
@@ -2340,6 +2161,9 @@ void LLMenuGL::cleanupSpilloverBranch()
void LLMenuGL::createJumpKeys()
{
+ if (!mCreateJumpKeys) return;
+ mCreateJumpKeys = FALSE;
+
mJumpKeys.clear();
std::set<std::string> unique_words;
@@ -2440,16 +2264,18 @@ void LLMenuGL::empty( void )
cleanupSpilloverBranch();
mItems.clear();
+ mFirstVisibleItem = NULL;
+ mArrowUpItem = NULL;
+ mArrowDownItem = NULL;
deleteAllChildren();
-
}
// Adjust rectangle of the menu
void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom)
{
setRect(LLRect(left, getRect().mTop, getRect().mRight, bottom));
- arrange();
+ needsArrange();
}
BOOL LLMenuGL::handleJumpKey(KEY key)
@@ -2462,12 +2288,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
@@ -2479,30 +2302,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();
- return TRUE;
-}
-
-// *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0
-// Its added as a fix to a viewer 1.23 bug that has already been address by skinning work.
-BOOL LLMenuGL::appendNoArrange( LLMenuItemGL* item )
-{
- mItems.push_back( item );
- addChild( item );
+ 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
@@ -2515,14 +2326,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;
}
@@ -2560,6 +2379,7 @@ void LLMenuGL::setItemVisible( const std::string& name, BOOL visible )
if( (*item_iter)->getName() == name )
{
(*item_iter)->setVisible( visible );
+ needsArrange();
break;
}
}
@@ -2572,7 +2392,7 @@ void LLMenuGL::setItemLastSelected(LLMenuItemGL* item)
LLMenuHolderGL::setActivatedItem(item);
}
- // fix the checkmarks
+ // update enabled and checkmark status
item->buildDrawLabel();
}
@@ -2670,7 +2490,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)
{
@@ -2777,7 +2597,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)
{
@@ -2880,29 +2703,59 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
}
}
getWindow()->setCursor(UI_CURSOR_ARROW);
+
+ // *HACK Release the mouse capture
+ // This is done to release the mouse after the Navigation Bar "Back" or "Forward" button
+ // drop-down menu is shown. Otherwise any other view won't be able to handle mouse events
+ // until the user chooses one of the drop-down menu items.
+
+ return TRUE;
+}
+
+BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ if (!mScrollable)
+ return blockMouseEvent(x, y);
+
+ if( clicks > 0 )
+ {
+ while( clicks-- )
+ scrollItemsDown();
+ }
+ else
+ {
+ while( clicks++ )
+ scrollItemsUp();
+ }
+
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);
@@ -2990,6 +2843,15 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
//rect.setLeftTopAndSize(x + HPAD, y, rect.getWidth(), rect.getHeight());
menu->setRect( rect );
+ // Resetting scrolling position
+ if (menu->isScrollable())
+ {
+ menu->mFirstVisibleItem = NULL;
+ menu->needsArrange();
+ }
+ menu->arrangeAndClear(); // Fix menu rect if needed.
+ rect = menu->getRect();
+
S32 bottom;
left = rect.mLeft;
bottom = rect.mBottom;
@@ -3017,794 +2879,16 @@ 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 );
-
- LLPieMenu* getBranch() { return mBranch; }
-
-protected:
- LLPieMenu* mBranch;
-};
-
-LLPieMenuBranch::LLPieMenuBranch(const std::string& name,
- const std::string& label,
- LLPieMenu* branch)
-: LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ),
- mBranch( branch )
-{
- mBranch->hide(FALSE);
- mBranch->setParentMenuItem(this);
-}
-
-// called to rebuild the draw label
-void LLPieMenuBranch::buildDrawLabel( void )
-{
- {
- // 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);
- }
-
- 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 (child->hasName(LL_PIE_MENU_TAG))
- {
- // 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);
- }
- else
- {
- parseChildXML(child, context, factory);
- }
- }
-}
-
-// virtual
-void LLPieMenu::setVisible(BOOL visible)
-{
- if (!visible)
- {
- hide(FALSE);
- }
-}
-
-BOOL LLPieMenu::handleHover( S32 x, S32 y, 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())
- {
- 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;
- }
- else
- {
- // clear out our selection
- if (mHoverItem)
- {
- mHoverItem->setHighlight(FALSE);
- mHoverItem = NULL;
- }
- }
-
- if( !handled && pointInView( x, y ) )
- {
- getWindow()->setCursor(UI_CURSOR_ARROW);
- lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
- handled = TRUE;
- }
-
- mHoverThisFrame = TRUE;
-
- return handled;
-}
-
-BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask )
-{
- BOOL handled = FALSE;
- // The click was somewhere within our rectangle
- LLMenuItemGL *item = pieItemFromXY( x, y );
-
- 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 if (!mRightMouseDown)
- {
- // call hidemenus to make sure transient selections get cleared
- ((LLMenuHolderGL*)getParent())->hideMenus();
- }
-
- // always handle mouse down as mouse up will close open menus
- return handled;
-}
-
-BOOL LLPieMenu::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)
- {
- // 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;
- }
- }
-
- return handled;
-}
-
-BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
-{
- // release mouse capture when right mouse button released, and we're past the shrink time
- if (mShrinkBorderTimer.getStarted() &&
- mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME)
- {
- mUseInfiniteRadius = FALSE;
- gFocusMgr.setMouseCapture(NULL);
- }
-
- S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX();
- S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY();
- if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE)
- {
- // user released right mouse button in middle of pie, interpret this as closing the menu
- sMenuContainer->hideMenus();
- return TRUE;
- }
-
-
- BOOL result = handleMouseUp( x, y, mask );
- mRightMouseDown = FALSE;
- mHoveredAnyItem = FALSE;
-
- return result;
-}
-
-BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask )
-{
- BOOL handled = FALSE;
-
- // The click was somewhere within our rectangle
- LLMenuItemGL *item = pieItemFromXY( x, y );
-
- if (item)
- {
- // 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(TRUE);
- }
- }
- else if (!mRightMouseDown)
- {
- // call hidemenus to make sure transient selections get cleared
- ((LLMenuHolderGL*)getParent())->hideMenus();
- }
-
- if (handled)
- {
- make_ui_sound("UISndClickRelease");
- }
-
- if (!handled && !mUseInfiniteRadius)
- {
- // call hidemenus to make sure transient selections get cleared
- sMenuContainer->hideMenus();
- }
-
- if (mFirstMouseDown)
- {
- make_ui_sound("UISndPieMenuAppear");
- mFirstMouseDown = FALSE;
- }
-
- // *FIX: is this necessary?
- if (!mShrinkBorderTimer.getStarted())
- {
- mShrinkBorderTimer.start();
- }
-
- return handled;
-}
-
-
-// virtual
-void LLPieMenu::draw()
-{
- // 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 );
-
- mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f;
- if (mShrinkBorderTimer.getStarted())
- {
- 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);
- }
-
- // correct for non-square pixels
- F32 center_x = width/2;
- F32 center_y = height/2;
- S32 steps = 100;
-
- gGL.pushMatrix();
- {
- gGL.translatef(center_x, center_y, 0.f);
-
- 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");
-
- // 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 );
-
- // 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 );
- }
- 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)
- {
- if ((*item_iter) == itemp)
- {
- 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 = color;
- outer_color.mV[VALPHA] *= mOuterRingAlpha;
- gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color );
- }
- i++;
- }
- }
- gGL.popMatrix();
-}
-
-// virtual
-BOOL LLPieMenu::append(LLMenuItemGL *item)
-{
- item->setBriefItem(TRUE);
- item->setFont( LLFontGL::getFontSansSerifSmall() );
- return LLMenuGL::append(item);
-}
-
-// virtual
-BOOL LLPieMenu::appendSeparator(const std::string &separator_name)
-{
- LLMenuItemGL* separator = new LLMenuItemBlankGL();
- separator->setFont( LLFontGL::getFontSansSerifSmall() );
- return append( separator );
-}
-
-
-BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
-{
- if (menu == this)
- {
- llerrs << "Can't attach a pie menu to itself" << llendl;
- }
- 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()
-{
- 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() )
- {
- font_height = (*mItems.begin())->getNominalHeight();
- }
- 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 );
-
- // 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)
- {
- 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++;
- }
-}
-
-LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
-{
- // 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)
- {
- return NULL;
- }
-
- // infinite radius is only used with right clicks
- S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 );
- if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius)
- {
- return NULL;
- }
-
- 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() )
- {
- item_list_t::iterator item_iter;
- for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
- {
- if (which == 0)
- {
- return (*item_iter);
- }
- which--;
- }
- }
-
- return NULL;
-}
-
-S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
-{
- // 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;
-}
-
-void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
-{
- 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;
- }
-
-
- 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;
-
- LLUI::setCursorPositionLocal(getParent(), center.mX, center.mY);
- }
-
- // *FIX: what happens when mouse buttons reversed?
- mRightMouseDown = mouse_down;
- mFirstMouseDown = mouse_down;
- mUseInfiniteRadius = TRUE;
- mHoveredAnyItem = FALSE;
-
- if (!mFirstMouseDown)
- {
- make_ui_sound("UISndPieMenuAppear");
- }
-
- 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);
-
- if (mouse_down)
- {
- mShrinkBorderTimer.stop();
- }
- else
- {
- mShrinkBorderTimer.start();
- }
-}
-
-void LLPieMenu::hide(BOOL item_selected)
-{
- if (!getVisible()) return;
-
- if (mHoverItem)
- {
- mHoverItem->setHighlight( FALSE );
- mHoverItem = 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");
+static LLDefaultWidgetRegistry::Register<LLMenuBarGL> r2("menu_bar");
-// Default constructor
-LLMenuBarGL::LLMenuBarGL( const std::string& name ) : LLMenuGL ( name, name )
-{
- mHorizontalLayout = TRUE;
- setCanTearOff(FALSE);
- mKeepFixedSize = TRUE;
- mAltKeyTrigger = FALSE;
-}
+LLMenuBarGL::LLMenuBarGL( const Params& p )
+: LLMenuGL(p),
+ mAltKeyTrigger(FALSE)
+{}
// Default destructor
LLMenuBarGL::~LLMenuBarGL()
@@ -3813,108 +2897,6 @@ LLMenuBarGL::~LLMenuBarGL()
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())
- {
- if (child->hasName("menu"))
- {
- 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);
- }
- }
- }
-
- 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;
-}
-
BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
{
if (getHighlightedItem() && mask == MASK_NONE)
@@ -3951,7 +2933,8 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask)
{
- if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && LLUI::sConfigGroup->getBOOL("UseAltKeyForMenus"))
+ static LLUICachedControl<bool> use_altkey_for_menus ("UseAltKeyForMenus", 0);
+ if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && use_altkey_for_menus)
{
mAltKeyTrigger = TRUE;
}
@@ -3984,7 +2967,7 @@ BOOL LLMenuBarGL::handleJumpKey(KEY key)
LLMenuGL::setKeyboardMode(TRUE);
found_it->second->setHighlight(TRUE);
- found_it->second->doIt();
+ found_it->second->onCommit();
}
return TRUE;
}
@@ -4031,6 +3014,7 @@ void LLMenuBarGL::draw()
LLMenuGL::draw();
}
+
void LLMenuBarGL::checkMenuTrigger()
{
// has the ALT key been pressed and subsequently released?
@@ -4038,7 +3022,8 @@ void LLMenuBarGL::checkMenuTrigger()
{
// 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") ||
+ 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())
@@ -4107,7 +3092,7 @@ S32 LLMenuBarGL::getRightmostMenuEdge()
}
// add a vertical separator to this menu
-BOOL LLMenuBarGL::appendSeparator( const std::string &separator_name )
+BOOL LLMenuBarGL::addSeparator()
{
LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL();
return append( separator );
@@ -4124,11 +3109,23 @@ BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu )
BOOL success = TRUE;
- LLMenuItemBranchGL* branch = NULL;
- branch = new LLMenuItemBranchDownGL( menu->getName(), menu->getLabel(), menu->getHandle());
+ // *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;
}
@@ -4174,7 +3171,7 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
handled = TRUE;
if (active_menu && active_menu != viewp)
{
- ((LLMenuItemGL*)viewp)->doIt();
+ ((LLMenuItemGL*)viewp)->onCommit();
LLMenuGL::setKeyboardMode(FALSE);
}
LLMenuGL::setKeyboardMode(FALSE);
@@ -4206,22 +3203,14 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
/// Class LLMenuHolderGL
///============================================================================
LLMenuHolderGL::LLMenuHolderGL()
- : LLPanel(std::string("Menu Holder"))
+ : LLPanel()
{
+ setName("Menu Holder");
setMouseOpaque(FALSE);
sItemActivationTimer.stop();
mCanHide = TRUE;
}
-LLMenuHolderGL::LLMenuHolderGL(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows)
-: LLPanel(name, rect, FALSE)
-{
- setMouseOpaque(mouse_opaque);
- sItemActivationTimer.stop();
- mCanHide = TRUE;
-}
-
-
void LLMenuHolderGL::draw()
{
LLView::draw();
@@ -4236,16 +3225,11 @@ void LLMenuHolderGL::draw()
selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this);
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->getMenu()->drawBackground(selecteditem, interpolant);
selecteditem->draw();
}
LLUI::popMatrix();
@@ -4336,17 +3320,22 @@ void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item)
/// 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)
+ LLFloater()
{
+ 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->arrange();
+ menup->needsArrange();
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);
+ mTargetHeight = (F32)(rect.getHeight() + floater_header_size + 5);
reshape(rect.getWidth(), rect.getHeight());
setRect(rect);
@@ -4367,8 +3356,9 @@ LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) :
void LLTearOffMenu::draw()
{
+ static LLUICachedControl<S32> floater_header_size ("UIFloaterHeaderSize", 0);
mMenu->setBackgroundVisible(isBackgroundOpaque());
- mMenu->arrange();
+ mMenu->needsArrange();
if (getRect().getHeight() != mTargetHeight)
{
@@ -4378,8 +3368,8 @@ void LLTearOffMenu::draw()
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);
+ mTargetHeight = (F32)(mMenu->getRect().getHeight() + floater_header_size + 4);
+ reshape(mMenu->getRect().getWidth() + 3, mMenu->getRect().getHeight() + floater_header_size + 5);
}
LLFloater::draw();
}
@@ -4457,7 +3447,7 @@ LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
LLTearOffMenu* tearoffp = new LLTearOffMenu(menup);
// keep onscreen
gFloaterView->adjustToFitScreen(tearoffp, FALSE);
- tearoffp->open(); /* Flawfinder: ignore */
+ tearoffp->openFloater(LLSD());
return tearoffp;
}
@@ -4475,3 +3465,369 @@ void LLTearOffMenu::onClose(bool app_quitting)
destroy();
}
+
+//-----------------------------------------------------------------------------
+// class LLContextMenuBranch
+// A branch to another context menu
+//-----------------------------------------------------------------------------
+class LLContextMenuBranch : public LLMenuItemGL
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
+ {
+ Mandatory<LLContextMenu*> branch;
+ };
+
+ LLContextMenuBranch(const Params&);
+
+ // called to rebuild the draw label
+ virtual void buildDrawLabel( void );
+
+ // onCommit() - do the primary funcationality of the menu item.
+ virtual void onCommit( void );
+
+ LLContextMenu* getBranch() { return mBranch; }
+ void setHighlight( BOOL highlight );
+
+protected:
+ void showSubMenu();
+
+ LLContextMenu* mBranch;
+};
+
+LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)
+: LLMenuItemGL(p),
+ mBranch( p.branch )
+{
+ mBranch->hide();
+ mBranch->setParentMenuItem(this);
+}
+
+// called to rebuild the draw label
+void LLContextMenuBranch::buildDrawLabel( void )
+{
+ {
+ // 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);
+ }
+
+ mDrawAccelLabel.clear();
+ std::string st = mDrawAccelLabel;
+ appendAcceleratorString( st );
+ mDrawAccelLabel = st;
+
+ // No special branch suffix
+ mDrawBranchLabel.clear();
+}
+
+void LLContextMenuBranch::showSubMenu()
+{
+ S32 center_x;
+ S32 center_y;
+ localPointToScreen(getRect().getWidth(), getRect().getHeight() , &center_x, &center_y);
+ mBranch->show( center_x, center_y, FALSE);
+}
+
+// onCommit() - do the primary funcationality of the menu item.
+void LLContextMenuBranch::onCommit( void )
+{
+ showSubMenu();
+
+}
+void LLContextMenuBranch::setHighlight( BOOL highlight )
+{
+ if (highlight == getHighlight()) return;
+ LLMenuItemGL::setHighlight(highlight);
+ if( highlight )
+ {
+ showSubMenu();
+ }
+ else
+ {
+ mBranch->hide();
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//-----------------------------------------------------------------------------
+// class LLContextMenu
+// A context menu
+//-----------------------------------------------------------------------------
+static LLDefaultWidgetRegistry::Register<LLContextMenu> context_menu_register("context_menu");
+static MenuRegistry::Register<LLContextMenu> context_menu_register2("context_menu");
+
+
+LLContextMenu::LLContextMenu(const Params& p)
+: LLMenuGL(p),
+ mHoveredAnyItem(FALSE),
+ mHoverItem(NULL)
+
+{
+ //setBackgroundVisible(TRUE);
+}
+
+void LLContextMenu::setVisible(BOOL visible)
+{
+ if (!visible)
+ hide();
+}
+
+void LLContextMenu::show(S32 x, S32 y,BOOL adjustCursor)
+{
+ arrangeAndClear();
+
+ S32 width = getRect().getWidth();
+ S32 height = getRect().getHeight();
+ const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
+ LLView* parent_view = getParent();
+
+ if(getParentMenuItem())
+ {
+ S32 parent_width = getParentMenuItem()->getRect().getWidth();
+
+ if(x + width > menu_region_rect.getWidth())
+ x -= parent_width + width;
+ }
+
+ 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 + width/2, local_y - height/2, width, height);
+ arrange();
+
+
+ if (translateIntoRect(menu_region_rect,FALSE) && adjustCursor)
+ {
+ LLUI::setCursorPositionLocal(getParent(), getRect().mLeft , getRect().mTop);
+ }
+
+ LLView::setVisible(TRUE);
+
+}
+
+void LLContextMenu::hide()
+{
+ if (!getVisible()) return;
+
+ LLView::setVisible(FALSE);
+
+ if (mHoverItem)
+ {
+ mHoverItem->setHighlight( FALSE );
+ }
+ mHoverItem = NULL;
+}
+
+
+BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask )
+{
+ LLMenuGL::handleHover(x,y,mask);
+
+ BOOL handled = FALSE;
+
+ LLMenuItemGL *item = getHighlightedItem();
+
+ if (item && item->getEnabled())
+ {
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+ handled = TRUE;
+
+ if (item != mHoverItem)
+ {
+ if (mHoverItem)
+ {
+ mHoverItem->setHighlight( FALSE );
+ }
+ mHoverItem = item;
+ mHoverItem->setHighlight( TRUE );
+ }
+ mHoveredAnyItem = TRUE;
+ }
+ else
+ {
+ // clear out our selection
+ if (mHoverItem)
+ {
+ mHoverItem->setHighlight(FALSE);
+ mHoverItem = NULL;
+ }
+ }
+
+ if( !handled && pointInView( x, y ) )
+ {
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+ handled = TRUE;
+ }
+
+ return handled;
+}
+
+BOOL LLContextMenu::handleMouseDown( S32 x, S32 y, MASK mask )
+{
+ BOOL handled = FALSE;
+ // The click was somewhere within our rectangle
+ LLMenuItemGL *item = getHighlightedItem();
+
+ 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();
+ }
+
+ // always handle mouse down as mouse up will close open menus
+ return handled;
+}
+BOOL LLContextMenu::handleMouseUp( S32 x, S32 y, MASK mask )
+{
+ BOOL handled = FALSE;
+
+ // The click was somewhere within our rectangle
+ LLMenuItemGL *item = getHighlightedItem();
+
+ if (item)
+ {
+ // 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
+ {
+ // call hidemenus to make sure transient selections get cleared
+ ((LLMenuHolderGL*)getParent())->hideMenus();
+ }
+
+ if (!handled)
+ {
+ // call hidemenus to make sure transient selections get cleared
+ sMenuContainer->hideMenus();
+ }
+
+ return handled;
+}
+
+BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ BOOL handled = FALSE;
+
+ // The click was somewhere within our rectangle
+ LLMenuItemGL *item = getHighlightedItem();
+
+ 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)
+ {
+ // capture mouse cursor as if on initial menu show
+ handled = TRUE;
+ }
+
+ if (item)
+ {
+ // 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;
+ }
+ }
+
+ return handled;
+}
+
+BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
+{
+ // release mouse capture when right mouse button released, and we're past the shrink time
+
+ S32 local_x = x - getRect().mLeft;
+ S32 local_y = y - getRect().mBottom;
+
+ if (!mHoveredAnyItem && !pointInView(local_x, local_y))
+ {
+ sMenuContainer->hideMenus();
+ return TRUE;
+ }
+
+
+ BOOL result = handleMouseUp( x, y, mask );
+ mHoveredAnyItem = FALSE;
+
+ return result;
+}
+
+void LLContextMenu::draw()
+{
+ LLMenuGL::draw();
+}
+
+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;
+ 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");
+
+ item = LLUICtrlFactory::create<LLContextMenuBranch>(p);
+ LLMenuGL::sMenuContainer->addChild(item->getBranch());
+ item->setFont( LLFontGL::getFontSansSerifSmall() );
+
+ return append( item );
+}
+
+bool LLContextMenu::addChild(LLView* view, S32 tab_group)
+{
+ 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 e62402d617..526e1c2583 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;
+
+ Ignored 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; }
@@ -167,6 +175,7 @@ public:
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 handleScrollWheel( S32 x, S32 y, S32 clicks );
virtual void draw( void );
BOOL getHover() const { return mGotHover; }
@@ -180,7 +189,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 +205,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 +222,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 +256,48 @@ private:
// calls a user defined callback.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLMenuItemCallGL : public LLMenuItemGL, public LLOldEvents::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::signals2::connection setClickCallback( const commit_signal_t::slot_type& cb )
+ {
+ return setCommitCallback(cb);
+ }
+
+ boost::signals2::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 +314,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;
-};
-
+ struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
+ {
+ Optional<EnableCallbackParam > on_check;
+ Params()
+ : on_check("on_check")
+ {}
+ };
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLMenuItemToggleGL
-//
-// The LLMenuItemToggleGL is a menu item that wraps around a user
-// specified and controlled boolean.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-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::signals2::connection setCheckCallback( const enable_signal_t::slot_type& cb )
+ {
+ return mCheckSignal.connect(cb);
+ }
+
private:
- BOOL* mToggle;
+ enable_signal_t mCheckSignal;
};
-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuGL
//
@@ -397,27 +358,59 @@ 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,
+ scrollable;
+ 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" )),
+ scrollable("scrollable", false)
+ {
+ 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*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
+ /*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*/ const widget_registry_t& getChildRegistry() const;
virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
@@ -430,24 +423,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 );
-
- // *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0
- // Its added as a fix to a viewer 1.23 bug that has already been address by skinning work.
- virtual BOOL appendNoArrange( 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 );
@@ -471,19 +453,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
@@ -504,8 +484,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; }
@@ -518,15 +498,27 @@ public:
static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; }
static BOOL getKeyboardMode() { return sKeyboardMode; }
+ void scrollItemsUp();
+ void scrollItemsDown();
+ BOOL isScrollable() const { return mScrollable; }
+
static class LLMenuHolderGL* sMenuContainer;
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;
item_list_t mItems;
+ LLMenuItemGL*mFirstVisibleItem;
+ LLMenuItemGL *mArrowUpItem, *mArrowDownItem;
+
typedef std::map<KEY, LLMenuItemGL*> navigation_key_map_t;
navigation_key_map_t mJumpKeys;
S32 mLastMouseX;
@@ -534,25 +526,31 @@ protected:
S32 mMouseVelX;
S32 mMouseVelY;
BOOL mHorizontalLayout;
+ BOOL mScrollable;
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;
LLFrameTimer mFadeTimer;
+ LLTimer mScrollItemsTimer;
BOOL mTornOff;
class LLMenuItemTearOffGL* mTearOffItem;
class LLMenuItemBranchGL* mSpilloverBranch;
LLMenuGL* mSpilloverMenu;
LLHandle<LLFloater> mParentFloaterHandle;
KEY mJumpKey;
+ BOOL mCreateJumpKeys;
}; // end class LLMenuGL
@@ -567,15 +565,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);
@@ -586,8 +586,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);
@@ -598,11 +597,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 );
@@ -611,77 +610,69 @@ 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:
BOOL mHoveredAnyItem;
- LLFrameTimer mShrinkBorderTimer;
- F32 mOuterRingAlpha; // for rendering pie menus as both bounded and unbounded
- F32 mCurRadius;
- BOOL mRightMouseDown;
+ LLMenuItemGL* mHoverItem;
};
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLMenuBarGL
//
@@ -691,28 +682,31 @@ 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);
- virtual BOOL handleJumpKey(KEY key);
- virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
- virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ /*virtual*/ BOOL handleAcceleratorKey(KEY key, MASK mask);
+ /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
+ /*virtual*/ BOOL handleJumpKey(KEY key);
+ /*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();
+ /*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 );
@@ -723,6 +717,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;
@@ -738,7 +738,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();
@@ -798,11 +797,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;
@@ -824,4 +831,31 @@ private:
LLEditMenuHandlerMgr() {};
};
+
+// *TODO: Eliminate
+// For backwards compatability only; generally just use boost::bind
+class view_listener_t : public boost::signals2::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..7f4c1c040a
--- /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::getDefaultParams());
+ 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..099a79278a 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");
+static LLDefaultWidgetRegistry::Register<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..89d44eaa87 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::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);
+ 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..312aceaaa2 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");
+static LLDefaultWidgetRegistry::Register<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::signals2::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::signals2::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..4855ed4926 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::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
+ boost::signals2::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 fe1ea95070..452f18b40b 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);
}
@@ -540,10 +556,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);
}
}
@@ -601,8 +618,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:
@@ -636,64 +657,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
@@ -701,15 +664,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
@@ -952,6 +927,7 @@ std::string LLNotificationChannel::summarize()
LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
LLNotificationComparators::orderByUUID())
{
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
}
@@ -1101,9 +1077,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)
{
@@ -1324,8 +1297,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();
@@ -1338,6 +1320,7 @@ bool LLNotifications::loadTemplates()
{
pTemplate->mURL = child->getTextContents();
child->getAttributeU32("option", pTemplate->mURLOption);
+ child->getAttributeU32("openexternally", pTemplate->mURLOpenExternally);
}
if (child->hasName("unique"))
@@ -1377,12 +1360,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,
@@ -1390,7 +1381,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,
@@ -1398,7 +1391,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 d01296c89e..b749724b4e 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -101,6 +101,7 @@
#include "llevents.h"
#include "llfunctorregistry.h"
#include "llui.h"
+#include "llmemory.h"
class LLNotification;
typedef boost::shared_ptr<LLNotification> LLNotificationPtr;
@@ -235,6 +236,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;
@@ -277,42 +283,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>
{
+ 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();
}
- // 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:
@@ -365,10 +378,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
@@ -460,16 +469,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
@@ -798,7 +812,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 28780c7adb..0136a41d61 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -54,74 +54,54 @@
#include "lluictrlfactory.h"
#include "llviewborder.h"
#include "llbutton.h"
+#include "lltabcontainer.h"
-// LLLayoutStack
-#include "llresizebar.h"
-#include "llcriticaldamp.h"
+static LLDefaultWidgetRegistry::Register<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()
-{
- // 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);
-}
-
-LLPanel::LLPanel()
-: mRectControl()
-{
- init();
- setName(std::string("panel"));
+const LLPanel::Params& LLPanel::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLPanel::Params>();
}
-LLPanel::LLPanel(const std::string& name)
-: LLUICtrl(name, LLRect(0, 0, 0, 0), TRUE, NULL, NULL),
- mRectControl()
+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"),
+ class_name("class")
{
- init();
+ name = "panel";
+ addSynonym(background_visible, "bg_visible");
+ addSynonym(has_border, "border_visible");
+ addSynonym(label, "title");
}
-LLPanel::LLPanel(const std::string& name, const LLRect& rect, BOOL bordered)
-: LLUICtrl(name, rect, 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),
+ mEnableCallbackRegistrar(false)
{
- 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 +110,31 @@ 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::addBorder()
+{
+ LLViewBorder::Params p;
+ p.border_thickness(LLPANEL_BORDER_WIDTH);
+ addBorder(p);
+}
+
+
void LLPanel::removeBorder()
{
- delete mBorder;
- mBorder = NULL;
+ if (mBorder)
+ {
+ removeChild(mBorder);
+ delete mBorder;
+ mBorder = NULL;
+ }
}
@@ -258,20 +242,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;
@@ -308,29 +278,26 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask )
}
}
}
-
- // If we have a default button, click it when
- // return is pressed, unless current focus is a return-capturing button
- // in which case *that* button will handle the return key
- LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
- if (cur_focus && !(focused_button && focused_button->getCommitOnReturn()))
+
+ // If RETURN was pressed and something has focus, call onCommit()
+ if (!handled && cur_focus && key == KEY_RETURN && mask == MASK_NONE)
{
- // RETURN key means hit default button in this case
- if (key == KEY_RETURN && mask == MASK_NONE
- && mDefaultBtn != NULL
- && mDefaultBtn->getVisible()
- && mDefaultBtn->getEnabled())
+ LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
+ if (focused_button && focused_button->getCommitOnReturn())
{
+ // current focus is a return-capturing button,
+ // let *that* button handle the return key
+ handled = FALSE;
+ }
+ else if (mDefaultBtn && mDefaultBtn->getVisible() && mDefaultBtn->getEnabled())
+ {
+ // If we have a default button, click it when return is pressed
mDefaultBtn->onCommit();
handled = TRUE;
}
- }
-
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- // set keyboard focus to self to trigger commitOnFocusLost behavior on current ctrl
- if (cur_focus && cur_focus->acceptsTextInput())
+ else if (cur_focus->acceptsTextInput())
{
+ // call onCommit for text input handling control
cur_focus->onCommit();
handled = TRUE;
}
@@ -364,12 +331,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 +364,194 @@ void LLPanel::setBorderVisible(BOOL b)
}
}
-// virtual
-LLXMLNodePtr LLPanel::getXML(bool save_children) const
-{
- LLXMLNodePtr node = LLView::getXML();
-
- if (mBorder && mBorder->getVisible())
- {
- node->createChild("border", TRUE)->setBoolValue(TRUE);
- }
+LLFastTimer::DeclareTimer FTM_PANEL_CONSTRUCTION("Panel Construction");
- if (!mRectControl.empty())
- {
- node->createChild("rect_control", TRUE)->setStringValue(mRectControl);
- }
+LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_node)
+{
+ std::string name("panel");
+ node->getAttributeString("name", name);
- if (!mLabel.empty())
- {
- node->createChild("label", TRUE)->setStringValue(mLabel);
- }
+ std::string class_attr;
+ node->getAttributeString("class", class_attr);
- if (save_children)
+ LLPanel* panelp = NULL;
+
{
- LLView::child_list_const_reverse_iter_t rit;
- for (rit = getChildList()->rbegin(); rit != getChildList()->rend(); ++rit)
+ LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
+
+ if(!class_attr.empty())
{
- LLView* childp = *rit;
-
- if (childp->getSaveToXML())
+ panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr);
+ if (!panelp)
{
- LLXMLNodePtr xml_node = childp->getXML();
-
- node->addChild(xml_node);
+ llwarns << "Panel class \"" << class_attr << "\" not registered." << llendl;
}
}
- }
- return node;
-}
-
-LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *factory)
-{
- std::string name("panel");
- node->getAttributeString("name", name);
+ if (!panelp)
+ {
+ panelp = LLUICtrlFactory::getInstance()->createFactoryPanel(name);
+ }
- 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
+ // factory panels may have registered their own factory maps
+ if (!panelp->getFactoryMap().empty())
{
- panelp->initPanelXML(node, parent, factory);
+ LLUICtrlFactory::instance().pushFactoryFunctions(&panelp->getFactoryMap());
+ }
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ panelp->mCommitCallbackRegistrar.pushScope();
+ panelp->mEnableCallbackRegistrar.pushScope();
+
+ panelp->initPanelXML(node, parent, output_node);
+
+ panelp->mCommitCallbackRegistrar.popScope();
+ panelp->mEnableCallbackRegistrar.popScope();
+
+ if (panelp && !panelp->getFactoryMap().empty())
+ {
+ LLUICtrlFactory::instance().popFactoryFunctions();
}
return panelp;
}
-BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+void LLPanel::initFromParams(const LLPanel::Params& p)
{
- std::string name = getName();
- node->getAttributeString("name", name);
- setName(name);
-
- setPanelParameters(node, parent);
+ // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
+ LLUICtrl::initFromParams(p);
- initChildrenXML(node, factory);
+ for (LLInitParam::ParamIterator<LocalizedString>::const_iterator it = p.strings().begin();
+ it != p.strings().end();
+ ++it)
+ {
+ mUIStrings[it->name] = it->text;
+ }
- std::string xml_filename;
- node->getAttributeString("filename", xml_filename);
+ setName(p.name());
+ setLabel(p.label());
- BOOL didPost;
+ setShape(p.rect);
+ parseFollowsFlags(p);
- 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)
+static LLFastTimer::DeclareTimer FTM_PANEL_SETUP("Panel Setup");
+static LLFastTimer::DeclareTimer FTM_EXTERNAL_PANEL_LOAD("Load Extern Panel Reference");
+static LLFastTimer::DeclareTimer FTM_PANEL_POSTBUILD("Panel PostBuild");
+
+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);
+
{
- // look for string declarations for programmatic text
- if (child->hasName("string"))
+ LLFastTimer timer(FTM_PANEL_SETUP);
+
+ LLXMLNodePtr referenced_xml;
+ std::string xml_filename;
+ node->getAttributeString("filename", xml_filename);
+
+ if (!xml_filename.empty())
{
- std::string string_name;
- child->getAttributeString("name", string_name);
- if (!string_name.empty())
+ LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD);
+ if (output_node)
{
- mUIStrings[string_name] = child->getTextContents();
+ //if we are exporting, we want to export the current xml
+ //not the referenced xml
+ LLXUIParser::instance().readXUI(node, params);
+ Params output_params(params);
+ setupParamsForExport(output_params, parent);
+ output_node->setName(node->getName()->mString);
+ LLXUIParser::instance().writeXUI(
+ output_node, output_params, &default_params);
+ return TRUE;
}
- }
- else
- {
- factory->createWidget(this, child);
- }
- }
-}
+
+ if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
+ {
+ llwarns << "Couldn't parse panel from: " << xml_filename << llendl;
-void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
-{
- /////// Rect, follows, tool_tip, enabled, visible attributes ///////
- initFromXML(node, parent);
+ return FALSE;
+ }
- /////// Border attributes ///////
- BOOL border = mBorder != NULL;
- node->getAttributeBOOL("border", border);
- if (border)
- {
- LLViewBorder::EBevel bevel_style = LLViewBorder::BEVEL_OUT;
- LLViewBorder::getBevelFromAttribute(node, bevel_style);
+ LLXUIParser::instance().readXUI(referenced_xml, params);
+
+ // add children using dimensions from referenced xml for consistent layout
+ setShape(params.rect);
+ LLUICtrlFactory::createChildren(this, 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")
+ if (output_node)
{
- border_style = LLViewBorder::STYLE_TEXTURE;
+ 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);
+ {
+ LLFastTimer timer(FTM_PANEL_CONSTRUCTION);
+ initFromParams(params);
}
- S32 border_thickness = LLPANEL_BORDER_WIDTH;
- node->getAttributeS32("border_thickness", border_thickness);
+ // add children
+ LLUICtrlFactory::createChildren(this, node, output_node);
- addBorder(bevel_style, border_style, border_thickness);
- }
- else
- {
- removeBorder();
+ // 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)
+ {
+ S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
+ parent->addChild(this, tab_group);
+ }
+
+ {
+ LLFastTimer timer(FTM_PANEL_POSTBUILD);
+ postBuild();
+ }
}
+ return TRUE;
+}
- /////// 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);
+const widget_registry_t& LLPanel::getChildRegistry() const
+{
+ // use default widget registry
+ return LLDefaultWidgetRegistry::instance();
+}
+
+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 +565,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 +584,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 +598,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 +607,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 +617,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 +626,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 +635,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 +646,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 +655,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 +664,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 +675,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 +684,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 +696,28 @@ BOOL LLPanel::childHasFocus(const std::string& id)
}
}
-
-void LLPanel::childSetFocusChangedCallback(const std::string& id, void (*cb)(LLFocusableElement*, void*), void* user_data)
+// *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->setFocusChangedCallback(cb, user_data);
+ child->setCommitCallback(boost::bind(cb, child, data));
}
}
-void LLPanel::childSetCommitCallback(const std::string& id, void (*cb)(LLUICtrl*, void*), void *userdata )
+void LLPanel::childSetValidate(const std::string& id, boost::function<bool (const LLSD& data)> cb)
{
- 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 )
-{
- LLUICtrl* child = getChild<LLUICtrl>(id, true);
- if (child)
- {
- child->setDoubleClickCallback(cb);
- if (userdata)
- {
- child->setCallbackUserData(userdata);
- }
- }
-}
-
-void LLPanel::childSetValidate(const std::string& id, BOOL (*cb)(LLUICtrl*, void*))
-{
- 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 +726,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 +736,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 +746,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 +756,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 +765,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 +776,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 +786,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 +796,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 +806,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 +815,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 +824,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 +833,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 +841,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 +852,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 +860,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 +880,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 +898,12 @@ LLView* LLPanel::getChildView(const std::string& name, BOOL recurse, BOOL create
}
if (!view && create_if_missing)
{
- view = createDummyWidget<LLView>(name);
+ view = getDefaultWidget<LLView>(name);
+ if (!view)
+ {
+ // create LLViews explicitly, as they are not registered widget types
+ view = LLUICtrlFactory::createDefaultWidget<LLView>(name);
+ }
}
return view;
}
@@ -1028,621 +936,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)
- {
- 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::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 a7c9579030..fc40cd77eb 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -42,7 +42,6 @@
#include "llviewborder.h"
#include "lluistring.h"
#include "v4color.h"
-#include "llevents.h"
#include <list>
#include <queue>
@@ -57,42 +56,73 @@ const BOOL BORDER_NO = FALSE;
* With or without border,
* Can contain LLUICtrls.
*/
-class LLPanel : public LLUICtrl, public LLEventTrackable
+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;
+ Optional<std::string> class_name;
- // 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);
+protected:
+ friend class LLUICtrlFactory;
+ // RN: for some reason you can't just use LLUICtrlFactory::getDefaultParams as a default argument in VC8
+ static const LLPanel::Params& getDefaultParams();
+
+ // Panels can get constructed directly
+ LLPanel(const LLPanel::Params& params = getDefaultParams());
- /*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();
void removeBorder();
BOOL hasBorder() const { return mBorder != NULL; }
void setBorderVisible( BOOL b );
@@ -107,10 +137,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; }
@@ -127,22 +154,20 @@ 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; }
+ EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }
+
+ void initFromParams(const Params& p);
+ BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL);
+ /*virtual*/ const widget_registry_t& getChildRegistry() const;
+
+ 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;
@@ -167,12 +192,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);
@@ -197,21 +220,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);
@@ -219,36 +242,31 @@ 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);
+
+ //call onOpen to let panel know when it's about to be shown or activated
+ virtual void onOpen(const LLSD& key) {}
protected:
// Override to set not found list
LLButton* getDefaultButton() { return mDefaultBtn; }
LLCallbackMap::map_t mFactoryMap;
-
+ CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar;
+ EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar;
+
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;
@@ -258,56 +276,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..779967940a 100644
--- a/indra/llui/llprogressbar.cpp
+++ b/indra/llui/llprogressbar.cpp
@@ -44,26 +44,32 @@
#include "llglheaders.h"
#include "llfocusmgr.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);
-}
+#include "lluictrlfactory.h"
+
+static LLDefaultWidgetRegistry::Register<LLProgressBar> r("progress_bar");
+
+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..70f98bd908 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -42,52 +42,60 @@
#include "llcontrol.h"
#include "llui.h"
#include "llfocusmgr.h"
+#include "lluictrlfactory.h"
-static LLRegisterWidget<LLRadioGroup> r("radio_group");
+static LLDefaultWidgetRegistry::Register<LLRadioGroup> r1("radio_group");
-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)
-{
- setControlName(control_name, NULL);
- init(border);
-}
+struct RadioGroupRegistry : public LLWidgetRegistry<RadioGroupRegistry>
+{};
+
+static RadioGroupRegistry::Register<LLRadioCtrl> register_radio_ctrl("radio_item");
-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)
+
+
+LLRadioGroup::Params::Params()
+: has_border("draw_border")
{
- init(border);
+ name = "radio_group";
+ mouse_opaque = true;
+ follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP;
}
-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()
{
}
+const widget_registry_t& LLRadioGroup::getChildRegistry() const
+{
+ return RadioGroupRegistry::instance();
+}
+
+// virtual
+BOOL LLRadioGroup::postBuild()
+{
+ if (mControlVariable)
+ {
+ setSelectedIndex(mControlVariable->getValue().asInteger());
+ }
+ return TRUE;
+}
// virtual
void LLRadioGroup::setEnabled(BOOL enabled)
@@ -250,48 +258,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 +352,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 +415,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 +442,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..850d896e29 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -39,22 +39,36 @@
/*
- * 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();
+ Ignored length;
+ Ignored 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;
+};
/*
* An invisible view containing multiple mutually exclusive toggling
@@ -65,30 +79,27 @@ 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);
- virtual ~LLRadioGroup();
+ struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+ {
+ Optional<bool> has_border;
+ Params();
+ };
+
+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,14 +115,11 @@ 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);
+ virtual const widget_registry_t& getChildRegistry() const;
+
//========================================================================
LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; };
@@ -131,9 +139,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;
@@ -141,5 +147,4 @@ private:
BOOL mHasBorder;
};
-
#endif
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..3f1ff34419 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -46,101 +46,86 @@
#include "llwindow.h"
#include "llcontrol.h"
#include "llrender.h"
+#include "lluictrlfactory.h"
+
+static LLDefaultWidgetRegistry::Register<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"),
+ left_button("left_button"),
+ right_button("right_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 +153,7 @@ void LLScrollbar::setDocPos(S32 pos, BOOL update_thumb)
if( mChangeCallback )
{
- mChangeCallback( mDocPos, this, mCallbackUserData );
+ mChangeCallback( mDocPos, this );
}
if( update_thumb )
@@ -221,7 +206,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 +214,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 +303,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 +328,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 +347,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 +371,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 +460,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 +492,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 +518,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 +607,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..2a2e56a92c 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 LLDefaultWidgetRegistry::Register<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,8 +195,17 @@ void LLScrollableContainerView::reshape(S32 width, S32 height,
}
}
-BOOL LLScrollableContainerView::handleKeyHere(KEY key, MASK mask)
+BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
{
+ // allow scrolled view to handle keystrokes in case it delegated keyboard focus
+ // to the scroll container.
+ // NOTE: this should not recurse indefinitely as handleKeyHere
+ // should not propagate to parent controls, so mScrolledView should *not*
+ // call LLScrollContainer::handleKeyHere in turn
+ if (mScrolledView->handleKeyHere(key, mask))
+ {
+ return TRUE;
+ }
for( S32 i = 0; i < SCROLLBAR_COUNT; i++ )
{
if( mScrollbar[i]->handleKeyHere(key, mask) )
@@ -222,7 +217,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 +234,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 +242,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 +256,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 +275,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 +334,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 +361,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 +380,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 +427,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 +448,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 +487,49 @@ 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;
+}
+
+const widget_registry_t& LLScrollContainer::getChildRegistry() const
{
+ // a scroll container can contain any default widget
+ return LLDefaultWidgetRegistry::instance();
+}
+
+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 +553,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 +591,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 +610,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 +685,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 +715,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..26d8cc824e 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,10 @@ 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);
+ virtual const widget_registry_t& getChildRegistry() const;
private:
- void init();
-
// internal scrollbar handlers
virtual void scrollHorizontal( S32 new_pos );
virtual void scrollVertical( S32 new_pos );
@@ -115,7 +116,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..1f3a7f9fcf 100644
--- a/indra/llui/llscrollingpanellist.cpp
+++ b/indra/llui/llscrollingpanellist.cpp
@@ -35,7 +35,7 @@
#include "llscrollingpanellist.h"
-static LLRegisterWidget<LLScrollingPanelList> r("scrolling_panel_list");
+static LLDefaultWidgetRegistry::Register<LLScrollingPanelList> r("scrolling_panel_list");
/////////////////////////////////////////////////////////////////////
@@ -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..02f09bd9b4
--- /dev/null
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -0,0 +1,330 @@
+/**
+ * @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
+//
+//static
+const LLScrollListColumn::Params& LLScrollListColumn::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLScrollListColumn::Params>();
+}
+
+
+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..712ea56454
--- /dev/null
+++ b/indra/llui/llscrolllistcolumn.h
@@ -0,0 +1,191 @@
+/**
+ * @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>
+ {
+ Alternative<bool> dynamic_width;
+ Alternative<S32> pixel_width;
+ Alternative<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>
+ {
+ Alternative<std::string> label;
+ Alternative<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");
+ }
+ };
+
+ static const Params& getDefaultParams();
+
+ //NOTE: this is default constructible so we can store it in a map.
+ LLScrollListColumn(const Params& p = getDefaultParams(), 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..6d91c784f7 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,34 +31,38 @@
* $/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");
+static LLDefaultWidgetRegistry::Register<LLScrollListCtrl> r("scroll_list");
// local structures & classes.
struct SortScrollListItem
@@ -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;
}
@@ -1612,16 +1246,18 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const
// "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* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled, S32 column_width)
+LLScrollListItem* LLScrollListCtrl::addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos, BOOL enabled)
{
- 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).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)
- {
- cell->setColor(color);
- }
- new_item->setColumn(index, cell);
- }
- else if (type == "separator")
- {
- LLScrollListSeparator* cell = new LLScrollListSeparator(width);
- if (has_color)
+ if (columnp->mHeader
+ && cell->isText()
+ && !cell->getValue().asString().empty())
{
- 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..8d200fb73f 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,24 +205,24 @@ 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);
+ LLScrollListItem* addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE);
LLUUID getStringUUIDSelectedItem() const;
LLScrollListItem* getFirstSelected() const;
@@ -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..4237d5b304
--- /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;
+
+ Ignored name; // use for localization tools
+ Ignored type;
+ Ignored 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..9522d32a8b
--- /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 LLDefaultWidgetRegistry::Register<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..8070dc4d02 100644
--- a/indra/llui/llslider.cpp
+++ b/indra/llui/llslider.cpp
@@ -41,53 +41,47 @@
#include "llkeyboard.h" // for the MASK constants
#include "llcontrol.h"
#include "llimagegl.h"
+#include "lluictrlfactory.h"
+
+static LLDefaultWidgetRegistry::Register<LLSlider> r1("slider_bar");
+//FIXME: make this into an unregistered template so that code constructed sliders don't
+// have ambigious template lookup problem
+
+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);
+}
-static LLRegisterWidget<LLSlider> r1("slider_bar");
-static LLRegisterWidget<LLSlider> r2("volume_slider");
-
-
-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 +92,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 +121,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 +164,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 +184,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 +247,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 +263,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 +271,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..dad65fcce0 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::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);
@@ -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..8bdeddcf75 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 )
+static LLDefaultWidgetRegistry::Register<LLSliderCtrl> r("slider");
+
+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::signals2::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::signals2::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,3 @@ 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..5bdbbfcbcc 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::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb );
+ boost::signals2::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..72329a4b32 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 )
+static LLDefaultWidgetRegistry::Register<LLSpinCtrl> r2("spinner");
+
+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)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();
}
}
-// 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)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();
}
}
@@ -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..bd74b285a7
--- /dev/null
+++ b/indra/llui/llstatbar.cpp
@@ -0,0 +1,293 @@
+/**
+ * @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"
+
+///////////////////////////////////////////////////////////////////////////////////
+
+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..6691f16c1e
--- /dev/null
+++ b/indra/llui/llstatview.cpp
@@ -0,0 +1,80 @@
+/**
+ * @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);
+ }
+}
+
+
+// widget registrars
+struct StatViewRegistry : public LLWidgetRegistry<StatViewRegistry>
+{};
+
+static StatViewRegistry::Register<LLStatBar> r1("stat_bar");
+
+
+const widget_registry_t& LLStatView::getChildRegistry() const
+{
+ return StatViewRegistry::instance();
+}
+
+
diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h
new file mode 100644
index 0000000000..20aba7782b
--- /dev/null
+++ b/indra/llui/llstatview.h
@@ -0,0 +1,66 @@
+/**
+ * @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();
+
+ virtual const widget_registry_t& getChildRegistry() const;
+
+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..3391b1275c 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -35,73 +35,139 @@
#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 LLDefaultWidgetRegistry::Register<LLPlaceHolderPanel> r1("placeholder");
+static LLDefaultWidgetRegistry::Register<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),
+ tab_top_image_unselected("tab_top_image_unselected"),
+ tab_top_image_selected("tab_top_image_selected"),
+ tab_bottom_image_unselected("tab_bottom_image_unselected"),
+ tab_bottom_image_selected("tab_bottom_image_selected"),
+ tab_left_image_unselected("tab_left_image_unselected"),
+ tab_left_image_selected("tab_left_image_selected")
+{
+ 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),
+ mImageTopUnselected(p.tab_top_image_unselected),
+ mImageTopSelected(p.tab_top_image_selected),
+ mImageBottomUnselected(p.tab_bottom_image_unselected),
+ mImageBottomSelected(p.tab_bottom_image_selected),
+ mImageLeftUnselected(p.tab_left_image_unselected),
+ mImageLeftSelected(p.tab_left_image_selected)
+{
+ 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 +216,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 +266,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 +286,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 +322,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 +341,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 +395,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 +439,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 +563,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 +574,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
{
@@ -617,14 +698,6 @@ BOOL LLTabContainer::handleKeyHere(KEY key, MASK mask)
}
// 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)
{
BOOL has_scroll_arrows = (getMaxScrollPos() > 0);
@@ -676,21 +749,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 +785,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 +793,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);
@@ -744,28 +829,28 @@ void LLTabContainer::addTabPanel(LLPanel* child,
// Tab button
LLRect btn_rect; // Note: btn_rect.mLeft is just a dummy. Will be updated in draw().
- std::string tab_img;
- std::string tab_selected_img;
+ LLUIImage* tab_img = NULL;
+ LLUIImage* tab_selected_img = NULL;
S32 tab_fudge = 1; // To make new tab art look better, nudge buttons up 1 pel
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 );
- tab_img = "tab_top_blue.tga";
- tab_selected_img = "tab_top_selected_blue.tga";
+ btn_rect.setLeftTopAndSize( 0, getRect().getHeight() - getTopBorderHeight() + tab_fudge, button_width, tabcntr_tab_height );
+ tab_img = mImageTopUnselected.get();
+ tab_selected_img = mImageTopSelected.get();
}
else
{
- 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";
+ btn_rect.setOriginAndSize( 0, 0 + tab_fudge, button_width, tabcntr_tab_height );
+ tab_img = mImageBottomUnselected.get();
+ tab_selected_img = mImageBottomSelected.get();
}
LLTextBox* textbox = NULL;
@@ -774,31 +859,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(mImageLeftUnselected);
+ p.image_selected(mImageLeftSelected);
+ 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 +898,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(tab_img);
+ p.image_selected(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 +946,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 +963,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 +977,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 +1141,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 +1235,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 +1287,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 +1303,7 @@ BOOL LLTabContainer::setTab(S32 which)
is_visible = FALSE;
}
}
- else
+ else if (getMaxScrollPos() > 0)
{
if( i < getScrollPos() )
{
@@ -1220,7 +1311,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 +1334,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 +1386,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 +1394,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 +1405,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 +1444,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 +1453,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 +1470,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 +1536,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 +1652,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 +1678,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 +1734,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 +1751,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..ac8232bbb1 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,38 @@ 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;
+
+ Optional<LLUIImage*> tab_top_image_unselected,
+ tab_top_image_selected,
+ tab_bottom_image_unselected,
+ tab_bottom_image_selected,
+ tab_left_image_unselected,
+ tab_left_image_selected;
+
+ 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 +104,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 +151,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 +161,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 +172,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 +214,6 @@ private:
tuple_list_t mTabList;
S32 mCurrentTabIdx;
- S32 mNextTabIdx;
BOOL mTabsHidden;
BOOL mScrolled;
@@ -216,9 +222,6 @@ private:
S32 mScrollPosPixels;
S32 mMaxScrollPos;
- void (*mCloseCallback)(void*);
- void* mCallbackUserdata;
-
LLTextBox* mTitleBox;
S32 mTopBorderHeight;
@@ -240,7 +243,13 @@ private:
S32 mTotalTabWidth;
LLFrameTimer mDragAndDropDelayTimer;
-};
+ LLPointer<LLUIImage> mImageTopUnselected;
+ LLPointer<LLUIImage> mImageTopSelected;
+ LLPointer<LLUIImage> mImageBottomUnselected;
+ LLPointer<LLUIImage> mImageBottomSelected;
+ LLPointer<LLUIImage> mImageLeftUnselected;
+ LLPointer<LLUIImage> mImageLeftSelected;
+};
#endif // LL_TABCONTAINER_H
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 89893bcf8d..464e4be809 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);
-}
-
-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);
-}
-
-void LLTextBox::initDefaults()
+template LLTextBox* LLView::getChild<LLTextBox>( const std::string& name, BOOL recurse, BOOL create_if_missing ) const;
+
+static LLDefaultWidgetRegistry::Register<LLTextBox> r("text");
+
+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..dca906decc 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();
+ Ignored 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..34bced064e 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -63,32 +63,17 @@
//
// Globals
//
-static LLRegisterWidget<LLTextEditor> r("simple_text_editor");
-
-BOOL gDebugTextEditorTips = FALSE;
+static LLDefaultWidgetRegistry::Register<LLTextEditor> r("simple_text_editor");
//
// 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..f64353555e 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -43,12 +43,13 @@
#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;
@@ -56,6 +57,66 @@ 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;
+
+ Ignored 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,23 +41,13 @@
#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..1d3e5d7a15 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -50,10 +50,22 @@
// Project includes
#include "llcontrol.h"
#include "llui.h"
+#include "lluicolortable.h"
#include "llview.h"
#include "lllineeditor.h"
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llmenugl.h"
#include "llwindow.h"
+// for registration
+#include "llsearcheditor.h"
+#include "llflyoutbutton.h"
+
+// for XUIParse
+#include "llquaternion.h"
+#include <boost/tokenizer.hpp>
+
//
// Globals
//
@@ -65,18 +77,22 @@ 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;
+
+// register searcheditor here
+static LLDefaultWidgetRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
+static LLDefaultWidgetRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
-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 +100,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 +124,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 +1570,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 +1590,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();
}
@@ -1678,27 +1706,61 @@ void LLUI::getCursorPositionLocal(const LLView* viewp, S32 *x, S32 *y)
// static
std::string LLUI::getLanguage()
{
- std::string language = "en-us";
- if (sConfigGroup)
+ std::string language = "en";
+ 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")
{
- language = "en-us";
+ language = "en";
}
}
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";
+ llwarns << "XUI::config file unable to open: " << filename << llendl;
+ sXUIPaths.push_back(dir);
+ }
+}
+
+
+//static
std::string LLUI::locateSkin(const std::string& filename)
{
std::string slash = gDirUtilp->getDirDelimiter();
@@ -1707,7 +1769,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))
{
@@ -1718,7 +1780,7 @@ std::string LLUI::locateSkin(const std::string& filename)
}
if (!gDirUtilp->fileExists(found_file))
{
- std::string local_skin = "xui" + slash + "en-us" + slash + filename;
+ std::string local_skin = "xui" + slash + "en" + slash + filename;
found_file = gDirUtilp->findSkinnedFilename(local_skin);
}
if (!gDirUtilp->fileExists(found_file))
@@ -1765,10 +1827,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 +1855,26 @@ 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)
{
- LLUI::sQAMode = b;
+ return LLCachedControl<LLColor4>(*sSettingGroups["color"], color_name, LLColor4::magenta);
+}
+
+// static
+LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
+{
+ for (settings_map_t::iterator itor = sSettingGroups.begin();
+ itor != sSettingGroups.end(); ++itor)
+ {
+ if(itor->second!= NULL)
+ {
+ 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 +1940,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 char* 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 LLUIColorTable::instance().getColor(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 char* 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 char* 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 6d6ce7a97c..dbd295d4e8 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/signals2.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,46 @@ 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(); }
+ static std::string getLocalizedSkinPath() { return sXUIPaths.back(); } //all files may not exist at the localized path
//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 +375,6 @@ protected:
// T must derive from LLUISingleton<T>
LLUISingleton() { sInstance = static_cast<T*>(this); }
-
~LLUISingleton() { sInstance = NULL; }
public:
@@ -383,6 +392,12 @@ public:
return sInstance;
}
+ static void destroyInstance()
+ {
+ delete sInstance;
+ sInstance = NULL;
+ }
+
private:
static T* sInstance;
};
@@ -413,49 +428,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 +565,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 +662,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>
+{
+ Alternative<F32> seconds;
+ Alternative<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 char* 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 char* 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 char* 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/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
new file mode 100644
index 0000000000..27ba6cc8b4
--- /dev/null
+++ b/indra/llui/lluicolortable.cpp
@@ -0,0 +1,155 @@
+/**
+ * @file lluicolortable.cpp
+ * @brief brief LLUIColorTable class implementation file
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include <queue>
+
+#include "lluicolortable.h"
+
+LLUIColorTable::ColorParams::ColorParams()
+: value("value"),
+ reference("reference")
+{
+}
+
+LLUIColorTable::ColorEntryParams::ColorEntryParams()
+: name("name"),
+ color("")
+{
+}
+
+LLUIColorTable::Params::Params()
+: color_entries("color_entries")
+{
+}
+
+void LLUIColorTable::init(const Params& p)
+{
+ // this map will contain all color references after the following loop
+ typedef std::map<std::string, std::string> string_string_map_t;
+ string_string_map_t unresolved_refs;
+
+ mColors.clear();
+ for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries().begin();
+ it != p.color_entries().end();
+ ++it)
+ {
+ ColorEntryParams color_entry = *it;
+ if(color_entry.color.value.isChosen())
+ {
+ mColors.insert(string_color_map_t::value_type(color_entry.name, color_entry.color.value));
+ }
+ else
+ {
+ unresolved_refs.insert(string_string_map_t::value_type(color_entry.name, color_entry.color.reference));
+ }
+ }
+
+ // maintain an in order queue of visited references for better debugging of cycles
+ typedef std::queue<std::string> string_queue_t;
+ string_queue_t ref_chain;
+
+ // maintain a map of the previously visited references in the reference chain for detecting cycles
+ typedef std::map<std::string, string_string_map_t::iterator> string_color_ref_iter_map_t;
+ string_color_ref_iter_map_t visited_refs;
+
+ // loop through the unresolved color references until there are none left
+ while(!unresolved_refs.empty())
+ {
+ // we haven't visited any references yet
+ visited_refs.clear();
+
+ string_string_map_t::iterator it = unresolved_refs.begin();
+ while(true)
+ {
+ if(it != unresolved_refs.end())
+ {
+ // locate the current reference in the previously visited references...
+ string_color_ref_iter_map_t::iterator visited = visited_refs.lower_bound(it->first);
+ if(visited != visited_refs.end()
+ && !(visited_refs.key_comp()(it->first, visited->first)))
+ {
+ // ...if we find the current reference in the previously visited references
+ // we know that there is a cycle
+ std::string ending_ref = it->first;
+ std::string warning("The following colors form a cycle: ");
+
+ // warn about the references in the chain and remove them from
+ // the unresolved references map because they cannot be resolved
+ for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
+ iter != visited_refs.end();
+ ++iter)
+ {
+ if(!ref_chain.empty())
+ {
+ warning += ref_chain.front() + "->";
+ ref_chain.pop();
+ }
+ unresolved_refs.erase(iter->second);
+ }
+
+ llwarns << warning + ending_ref << llendl;
+
+ break;
+ }
+ else
+ {
+ // ...continue along the reference chain
+ ref_chain.push(it->first);
+ visited_refs.insert(visited, string_color_ref_iter_map_t::value_type(it->first, it));
+ }
+ }
+ else
+ {
+ // since this reference does not refer to another reference it must refer to an
+ // actual color, lets find it...
+ string_color_map_t::iterator color_value = mColors.find(it->second);
+
+ if(color_value != mColors.end())
+ {
+ // ...we found the color, and we now add every reference in the reference chain
+ // to the color map
+ for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
+ iter != visited_refs.end();
+ ++iter)
+ {
+ mColors.insert(string_color_map_t::value_type(iter->first, color_value->second));
+ unresolved_refs.erase(iter->second);
+ }
+
+ break;
+ }
+ else
+ {
+ // ... we did not find the color which imples that the current reference
+ // references a non-existant color
+ for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
+ iter != visited_refs.end();
+ ++iter)
+ {
+ llwarns << iter->first << " references a non-existent color" << llendl;
+ unresolved_refs.erase(iter->second);
+ }
+
+ break;
+ }
+ }
+
+ // find the next color reference in the reference chain
+ it = unresolved_refs.find(it->second);
+ }
+ }
+}
+
+const LLColor4& LLUIColorTable::getColor(const std::string& name) const
+{
+ string_color_map_t::const_iterator iter = mColors.find(name);
+ return (iter != mColors.end() ? iter->second : LLColor4::magenta);
+}
diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h
new file mode 100644
index 0000000000..dcbb1ee5cb
--- /dev/null
+++ b/indra/llui/lluicolortable.h
@@ -0,0 +1,58 @@
+/**
+ * @file lluicolortable.h
+ * @brief brief LLUIColorTable class header file
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLUICOLORTABLE_H_
+#define LL_LLUICOLORTABLE_H_
+
+#include <map>
+
+#include "llinitparam.h"
+#include "llsingleton.h"
+
+#include "v4color.h"
+
+class LLUIColorTable : public LLSingleton<LLUIColorTable>
+{
+public:
+ struct ColorParams : LLInitParam::Choice<ColorParams>
+ {
+ Alternative<LLColor4> value;
+ Alternative<std::string> reference;
+
+ ColorParams();
+ };
+
+ struct ColorEntryParams : LLInitParam::Block<ColorEntryParams>
+ {
+ Mandatory<std::string> name;
+ Mandatory<ColorParams> color;
+
+ ColorEntryParams();
+ };
+
+ struct Params : LLInitParam::Block<Params>
+ {
+ Multiple<ColorEntryParams> color_entries;
+
+ Params();
+ };
+
+ // define colors by passing in a param block that can be generated via XUI file or manually
+ void init(const Params& p);
+
+ // color lookup
+ const LLColor4& getColor(const std::string& name) const;
+
+private:
+ // consider using sorted vector
+ typedef std::map<std::string, LLColor4> string_color_map_t;
+ string_color_map_t mColors;
+};
+
+#endif // LL_LLUICOLORTABLE_H
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 9d97312ab0..7b378fd9c7 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");
+static LLDefaultWidgetRegistry::Register<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"),
+ rightclick_callback("rightclick_callback"),
+ control_name("control_name")
+{
+ 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,98 @@ void LLFocusableElement::setFocus(BOOL b)
{
}
+//static
+const LLUICtrl::Params& LLUICtrl::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLUICtrl::Params>();
+}
-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),
+ mDisabledControlVariable(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_controls.isProvided())
+ {
+ if (p.enabled_controls.enabled.isChosen())
+ {
+ LLControlVariable* control = findControl(p.enabled_controls.enabled);
+ if (control)
+ setEnabledControlVariable(control);
+ }
+ else if(p.enabled_controls.disabled.isChosen())
+ {
+ LLControlVariable* control = findControl(p.enabled_controls.disabled);
+ if (control)
+ setDisabledControlVariable(control);
+ }
+ }
+ if(p.controls_visibility.isProvided())
+ {
+ if (p.controls_visibility.visible.isChosen())
+ {
+ LLControlVariable* control = findControl(p.controls_visibility.visible);
+ if (control)
+ setMakeVisibleControlVariable(control);
+ }
+ else if (p.controls_visibility.invisible.isChosen())
+ {
+ LLControlVariable* control = findControl(p.controls_visibility.invisible);
+ if (control)
+ setMakeInvisibleControlVariable(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);
+ }
+ }
+ }
+
+ if(p.rightclick_callback.isProvided())
+ initCommitCallback(p.rightclick_callback, mRightClickSignal);
+
}
+
LLUICtrl::~LLUICtrl()
{
gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
@@ -127,24 +214,232 @@ LLUICtrl::~LLUICtrl()
}
}
-void LLUICtrl::onCommit()
+void LLUICtrl::initCommitCallback(const CommitCallbackParam& cb, commit_signal_t& sig)
+{
+ if (cb.function.isProvided())
+ {
+ 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)
{
- if( mCommitCallback )
+ // Set the callback function
+ if (cb.function.isProvided())
{
- mCommitCallback( this, mCallbackUserData );
+ 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());
+ }
+}
+
+void LLUICtrl::setDisabledControlVariable(LLControlVariable* control)
+{
+ if (mDisabledControlVariable)
+ {
+ mDisabledControlConnection.disconnect(); // disconnect current signal
+ mDisabledControlVariable = NULL;
+ }
+ if (control)
+ {
+ mDisabledControlVariable = control;
+ mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("disabled")));
+ setEnabled(!(mDisabledControlVariable->getValue().asBoolean()));
+ }
+}
+
+void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control)
+{
+ if (mMakeVisibleControlVariable)
+ {
+ mMakeVisibleControlConnection.disconnect(); // disconnect current signal
+ mMakeVisibleControlVariable = NULL;
+ }
+ if (control)
+ {
+ mMakeVisibleControlVariable = control;
+ mMakeVisibleControlConnection = mMakeVisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("visible")));
+ setVisible(mMakeVisibleControlVariable->getValue().asBoolean());
+ }
+}
+
+void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control)
+{
+ if (mMakeInvisibleControlVariable)
+ {
+ mMakeInvisibleControlConnection.disconnect(); // disconnect current signal
+ mMakeInvisibleControlVariable = NULL;
+ }
+ if (control)
+ {
+ mMakeInvisibleControlVariable = control;
+ mMakeInvisibleControlConnection = mMakeInvisibleControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getUICtrlHandle(), std::string("invisible")));
+ setVisible(!(mMakeInvisibleControlVariable->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 =="disabled")
+ {
+ ctrl->setEnabled(!newvalue.asBoolean());
+ return true;
+ }
+ else if (type == "visible")
+ {
+ ctrl->setVisible(newvalue.asBoolean());
+ return true;
+ }
+ else if (type == "invisible")
+ {
+ ctrl->setVisible(!newvalue.asBoolean());
+ return true;
+ }
+ }
+ return false;
}
// virtual
@@ -248,12 +543,10 @@ void LLUICtrl::onFocusLost()
}
}
-void LLUICtrl::onLostTop()
+void LLUICtrl::onTopLost()
{
- if (mLostTopCallback)
- {
- mLostTopCallback(this, mCallbackUserData);
- }
+ // trigger callbacks
+ LLFocusableElement::onTopLost();
}
@@ -278,12 +571,13 @@ BOOL LLUICtrl::acceptsTextInput() const
//virtual
BOOL LLUICtrl::isDirty() const
{
- return FALSE;
+ return mViewModel->isDirty();
};
//virtual
void LLUICtrl::resetDirty()
{
+ mViewModel->resetDirty();
}
// virtual
@@ -456,7 +750,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 +763,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 +820,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 +839,16 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const
return NULL;
}
+// *TODO: Deprecate; for backwards compatability only:
+boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data)
+{
+ return setCommitCallback( boost::bind(cb, _1, data));
+}
+boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
+{
+ return mValidateSignal.connect(boost::bind(cb, _2));
+}
+
// virtual
void LLUICtrl::setTentative(BOOL b)
{
@@ -583,11 +862,6 @@ BOOL LLUICtrl::getTentative() const
}
// virtual
-void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) )
-{
-}
-
-// virtual
void LLUICtrl::setColor(const LLColor4& color)
{ }
@@ -598,3 +872,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..6dfbd9cf8b 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,128 @@ 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::signals2::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::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::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t;
+
+ struct CallbackParam : public LLInitParam::Block<CallbackParam>
+ {
+ Ignored 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 EnableControls : public LLInitParam::Choice<EnableControls>
+ {
+ Alternative<std::string> enabled;
+ Alternative<std::string> disabled;
+
+ EnableControls()
+ : enabled("enabled_control"),
+ disabled("disabled_control")
+ {}
+ };
+ struct ControlVisibility : public LLInitParam::Choice<ControlVisibility>
+ {
+ Alternative<std::string> visible;
+ Alternative<std::string> invisible;
+
+ ControlVisibility()
+ : visible("make_visible_control"),
+ invisible("make_invisible_control")
+ {}
+ };
+ 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<CommitCallbackParam> rightclick_callback;
+
+ Optional<focus_callback_t> focus_lost_callback;
+
+ Optional<std::string> control_name;
+ Optional<EnableControls> enabled_controls;
+ Optional<ControlVisibility> controls_visibility;
+
+ Params();
+ };
+
/*virtual*/ ~LLUICtrl();
+ void initFromParams(const Params& p);
+protected:
+ friend class LLUICtrlFactory;
+ static const Params& getDefaultParams();
+ LLUICtrl(const Params& p = getDefaultParams(),
+ 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 +193,23 @@ 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);
+ void setDisabledControlVariable(LLControlVariable* control);
+ void setMakeVisibleControlVariable(LLControlVariable* control);
+ void setMakeInvisibleControlVariable(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 +220,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 +236,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 +244,14 @@ public:
LLUICtrl* getParentUICtrl() const;
- void* getCallbackUserData() const { return mCallbackUserData; }
- void setCallbackUserData( void* data ) { mCallbackUserData = data; }
+ 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); }
- 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::signals2::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data);
+ boost::signals2::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 +260,59 @@ 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);
- void* mCallbackUserData;
+ commit_signal_t mCommitSignal;
+ enable_signal_t mValidateSignal;
+ commit_signal_t mRightClickSignal;
+ LLViewModelPtr mViewModel;
+
+ LLControlVariable* mControlVariable;
+ boost::signals2::connection mControlConnection;
+ LLControlVariable* mEnabledControlVariable;
+ boost::signals2::connection mEnabledControlConnection;
+ LLControlVariable* mDisabledControlVariable;
+ boost::signals2::connection mDisabledControlConnection;
+ LLControlVariable* mMakeVisibleControlVariable;
+ boost::signals2::connection mMakeVisibleControlConnection;
+ LLControlVariable* mMakeInvisibleControlVariable;
+ boost::signals2::connection mMakeInvisibleControlConnection;
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..24e4ad18e6 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,37 +78,43 @@ const S32 VPAD = 4;
const S32 FLOATER_H_MARGIN = 15;
const S32 MIN_WIDGET_HEIGHT = 10;
-std::vector<std::string> LLUICtrlFactory::sXUIPaths;
+LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction");
+LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams");
+LLFastTimer::DeclareTimer FTM_WIDGET_SETUP("Widget Setup");
+
+//-----------------------------------------------------------------------------
+// Register widgets that are purely data driven here so they get linked in
+#include "llstatview.h"
+static LLDefaultWidgetRegistry::Register<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;
- }
};
-static LLRegisterWidget<LLUICtrlLocate> r1("locate");
-static LLRegisterWidget<LLUICtrlLocate> r2("pad");
+static LLDefaultWidgetRegistry::Register<LLUICtrlLocate> r1("locate");
//-----------------------------------------------------------------------------
// LLUICtrlFactory()
//-----------------------------------------------------------------------------
LLUICtrlFactory::LLUICtrlFactory()
- : mDummyPanel(NULL)
+ : mDummyPanel(NULL) // instantiated when first needed
{
- setupPaths();
}
LLUICtrlFactory::~LLUICtrlFactory()
@@ -116,141 +123,140 @@ 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())
+ LLXUIParser::instance().readXUI(root_node, block);
+ }
+}
+
+//static
+void LLUICtrlFactory::createChildren(LLView* viewp, 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)
{
- LLUIString path_val_ui(path->getValue());
- std::string language = LLUI::getLanguage();
- path_val_ui.setArg("[LANGUAGE]", language);
+ outputChild = output_node->createChild("", FALSE);
+ }
- if (std::find(sXUIPaths.begin(), sXUIPaths.end(), path_val_ui.getString()) == sXUIPaths.end())
- {
- sXUIPaths.push_back(path_val_ui.getString());
- }
+ if (!instance().createFromXML(child_node, viewp, LLStringUtil::null, outputChild, viewp->getChildRegistry()))
+ {
+ std::string child_name = std::string(child_node->getName()->mString);
+ 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);
}
}
- 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;
}
+LLFastTimer::DeclareTimer FTM_XML_PARSE("XML Reading/Parsing");
//-----------------------------------------------------------------------------
// getLayeredXMLNode()
//-----------------------------------------------------------------------------
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;
- }
+ LLFastTimer timer(FTM_XML_PARSE);
+ return LLXMLNode::getLayeredXMLNode(xui_filename, root, LLUI::getXUIPaths());
+}
+
+//-----------------------------------------------------------------------------
+// getLocalizedXMLNode()
+//-----------------------------------------------------------------------------
+bool LLUICtrlFactory::getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
+{
+ LLFastTimer timer(FTM_XML_PARSE);
+ std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getLocalizedSkinPath(), xui_filename);
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;
- }
+ return false;
}
-
- LLXMLNodePtr updateRoot;
-
- std::vector<std::string>::const_iterator itor;
-
- for (itor = sXUIPaths.begin(), ++itor; itor != sXUIPaths.end(); ++itor)
+ else
{
- 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 true;
}
+static LLFastTimer::DeclareTimer BUILD_FLOATERS("Build Floaters");
//-----------------------------------------------------------------------------
// 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)
{
+ LLFastTimer timer(BUILD_FLOATERS);
LLXMLNodePtr root;
- if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+ //if exporting, only load the language being exported,
+ //instead of layering localized version on top of english
+ if (output_node)
+ {
+ if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
+ {
+ llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
+ return;
+ }
+ }
+ else 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);
- }
+ if (!floaterp->getFactoryMap().empty())
+ {
+ mFactoryStack.push_front(&floaterp->getFactoryMap());
+ }
- floaterp->initFloaterXML(root, NULL, this, open); /* Flawfinder: ignore */
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ floaterp->getCommitCallbackRegistrar().pushScope();
+ floaterp->getEnableCallbackRegistrar().pushScope();
+
+ floaterp->initFloaterXML(root, floaterp->getParent(), open_floater, output_node);
- if (LLUI::sShowXUINames)
- {
- floaterp->setToolTip(filename);
- }
-
- if (factory_map)
- {
- mFactoryStack.pop_front();
+ if (LLUI::sShowXUINames)
+ {
+ floaterp->setToolTip(filename);
+ }
+
+ floaterp->getCommitCallbackRegistrar().popScope();
+ floaterp->getEnableCallbackRegistrar().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 +264,33 @@ 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;
}
+static LLFastTimer::DeclareTimer BUILD_PANELS("Build Panels");
+
//-----------------------------------------------------------------------------
// 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)
{
+ LLFastTimer timer(BUILD_PANELS);
BOOL didPost = FALSE;
LLXMLNodePtr root;
- if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+ //if exporting, only load the language being exported,
+ //instead of layering localized version on top of english
+ if (output_node)
+ {
+ if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
+ {
+ llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
+ return didPost;
+ }
+ }
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
{
+ llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
return didPost;
}
@@ -296,246 +301,794 @@ 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());
+ }
+
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ panelp->getCommitCallbackRegistrar().pushScope();
+ panelp->getEnableCallbackRegistrar().pushScope();
+
+ didPost = panelp->initPanelXML(root, NULL, output_node);
+
+ panelp->getCommitCallbackRegistrar().popScope();
+ panelp->getEnableCallbackRegistrar().popScope();
+
+ if (LLUI::sShowXUINames)
+ {
+ panelp->setToolTip(filename);
+ }
+
+ if (!panelp->getFactoryMap().empty())
+ {
+ mFactoryStack.pop_front();
+ }
}
+ mFileNames.pop_back();
+ return didPost;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+LLFastTimer::DeclareTimer FTM_CREATE_FROM_XML("Create child widget");
- didPost = panelp->initPanelXML(root, NULL, this);
+LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node, const widget_registry_t& registry)
+{
+ LLFastTimer timer(FTM_CREATE_FROM_XML);
+ std::string ctrl_type = node->getName()->mString;
+ LLStringUtil::toLower(ctrl_type);
- if (LLUI::sShowXUINames)
+ const LLWidgetCreatorFunc* funcp = registry.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)
{
- mFactoryStack.pop_front();
+ if (mDummyPanel == NULL)
+ {
+ LLPanel::Params p;
+ mDummyPanel = create<LLPanel>(p);
+ }
+ parent = mDummyPanel;
}
-
- return didPost;
+ LLView *view = (*funcp)(node, parent, output_node);
+ if (LLUI::sShowXUINames && view && !filename.empty())
+ {
+ view->setToolTip(filename);
+ }
+
+ 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;
+ }
}
+ LLPanel::Params panel_p;
+ return create<LLPanel>(panel_p);
+}
- // 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
+}
+
+const widget_registry_t& LLUICtrlFactory::getWidgetRegistry(LLView* viewp)
+{
+ return viewp->getChildRegistry();
+}
+
+
+//
+// LLXUIParser
+//
+LLXUIParser::LLXUIParser()
+: mLastWriteGeneration(-1),
+ mCurReadDepth(0)
+{
+ 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));
+}
+
+static LLFastTimer::DeclareTimer PARSE_XUI("XUI Parsing");
+
+void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent)
+{
+ LLFastTimer timer(PARSE_XUI);
+ mNameStack.clear();
+ mCurReadDepth = 0;
+ 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;
+ name_stack_t name_stack;
- if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+ for (name_stack_t::const_iterator it = stack.begin();
+ it != stack.end();
+ ++it)
{
- return NULL;
+ if (!it->first.empty())
+ {
+ name_stack.push_back(*it);
+ }
}
- // root must be called panel
- if( !root->hasName( LL_PIE_MENU_TAG ))
+ if (name_stack.empty() || mWriteRootNode.isNull()) return NULL;
+
+ std::string attribute_name = 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")
{
- llwarns << "Root node should be named " << LL_PIE_MENU_TAG << " in : " << filename << llendl;
- return NULL;
+ 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;
+ }
}
- std::string name("menu");
- root->getAttributeString("name", name);
+ for (name_stack_t::const_iterator it = ++name_stack.begin();
+ it != name_stack.end();
+ ++it)
+ {
+ attribute_name += ".";
+ attribute_name += it->first;
+ }
- LLPieMenu *menu = new LLPieMenu(name);
- parentp->addChild(menu);
- menu->initXML(root, parentp, this);
+ // *NOTE: <string> elements for translation need to have whitespace
+ // preserved like "initial_value" above, however, the <string> node
+ // becomes an attribute of the containing floater or panel.
+ // Because all <string> elements must have a "name" attribute, and
+ // "name" is parsed first, just put the value into the last written
+ // child.
+ if (attribute_name == "string.value")
+ {
+ // The caller of will shortly call writeStringValue(), which sets
+ // this node's type to string, but we don't want to export type="string".
+ // Set the default for this node to suppress the export.
+ static LLXMLNodePtr default_node;
+ if (default_node.isNull())
+ {
+ default_node = new LLXMLNode();
+ // Force the node to have a string type
+ default_node->setStringValue( std::string() );
+ }
+ mLastWrittenChild->setDefault(default_node);
+ // mLastWrittenChild is the "string" node part of "string.value",
+ // so the caller will call writeStringValue() into that node,
+ // setting the node text contents.
+ return mLastWrittenChild;
+ }
+
+ LLXMLNodePtr attribute_node;
- if (LLUI::sShowXUINames)
+ const char* attribute_cstr = attribute_name.c_str();
+ if (name_stack.size() != 1
+ && !is_font)
{
- menu->setToolTip(filename);
+ std::string child_node_name(mWriteRootNode->getName()->mString);
+ child_node_name += ".";
+ child_node_name += name_stack.front().first;
+
+ LLXMLNodePtr child_node;
+
+ if (mLastWriteGeneration == name_stack.front().second)
+ {
+ child_node = mLastWrittenChild;
+ }
+ else
+ {
+ mLastWriteGeneration = name_stack.front().second;
+ child_node = mWriteRootNode->createChild(child_node_name.c_str(), false);
+ }
+
+ mLastWrittenChild = child_node;
+
+ name_stack_t::const_iterator it = ++name_stack.begin();
+ std::string short_attribute_name(it->first);
+
+ for (++it;
+ it != name_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;
+ }
+
+ attribute_node = child_node->createChild(short_attribute_name.c_str(), true);
+ }
+ else
+ {
+ 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)
+ 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())
{
- std::string filename = built_panel_it->second;
- LLPanel* panelp = built_panel_it->first.get();
- if (!panelp)
+ mCurReadNode = nodep;
+ mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration()));
+ // child nodes are not necessarily valid parameters (could be a child widget)
+ // so don't complain once we've recursed
+ bool silent = mCurReadDepth > 0;
+ block.submitValue(mNameStack, *this, silent);
+ 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
+ mCurReadDepth++;
+ 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)
+ {
+ mNameStack.push_back(std::make_pair(child_name, newParseGeneration()));
+ num_tokens_pushed++;
+ }
+ 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;
+ }
+
+ // 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))
{
- continue;
+ // 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();
}
- llinfos << "Rebuilding UI panel " << panelp->getName()
- << " from " << filename
- << llendl;
- BOOL visible = panelp->getVisible();
- panelp->setVisible(FALSE);
- panelp->setFocus(FALSE);
- panelp->deleteAllChildren();
- buildPanel(panelp, filename.c_str(), &panelp->getFactoryMap());
- panelp->setVisible(visible);
+ while(num_tokens_pushed-- > 0)
+ {
+ mNameStack.pop_back();
+ }
}
+ mCurReadDepth--;
+ return values_parsed;
+}
+
+bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block)
+{
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(".");
+
+ bool any_parsed = false;
- built_floater_t::iterator built_floater_it;
- for (built_floater_it = mBuiltFloaters.begin();
- built_floater_it != mBuiltFloaters.end();
- ++built_floater_it)
+ 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);
+ // child nodes are not necessarily valid attributes, so don't complain once we've recursed
+ bool silent = mCurReadDepth > 0;
+ any_parsed |= block.submitValue(mNameStack, *this, silent);
+
+ 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);
+ //RN: don't write out the color that is represented by a function
+ // rely on param block exporting to get the reference to the color settings
+ if (color.isUsingFunction()) return false;
+ 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..b9c61b1fed 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -33,68 +33,432 @@
#ifndef LLUICTRLFACTORY_H
#define LLUICTRLFACTORY_H
+#include "llcallbackmap.h"
+#include "llinitparam.h"
+#include "llxmlnode.h"
+#include "llfasttimer.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;
+ S32 mCurReadDepth;
+};
+
+// global static instance for registering all widget types
+typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc;
+
+typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t;
+
+template <typename DERIVED_TYPE>
+class LLWidgetRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE>
+{
+public:
+ typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t;
+ // local static instance for registering a particular widget
+ template<typename T, typename PARAM_BLOCK = typename T::Params>
+ class Register : public super_t::StaticRegistrar
+ {
+ public:
+ // register with either the provided builder, or the generic templated builder
+ Register(const char* tag, LLWidgetCreatorFunc func = NULL);
+ };
+
+protected:
+ LLWidgetRegistry() {}
+};
+
+class LLDefaultWidgetRegistry : public LLWidgetRegistry<LLDefaultWidgetRegistry>
+{
+protected:
+ LLDefaultWidgetRegistry() {}
+ friend class LLSingleton<LLDefaultWidgetRegistry>;
+};
+
+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>
+{};
+
+// function used to create new default widgets via LLView::getChild<T>
+typedef LLView* (*dummy_widget_creator_func_t)(const std::string&);
+
+// used to register factory functions for default widget instances
+class LLDummyWidgetRegistry
+: public LLRegistrySingleton<const std::type_info*, dummy_widget_creator_func_t, LLDummyWidgetRegistry, LLCompareTypeID>
+{};
+
+extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP;
+extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION;
+extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS;
+
+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();
- void setupPaths();
+ // 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 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);
+ const T& get() { return mPrototype; }
- void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); }
- void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); }
+ private:
+ T mPrototype;
+ };
- class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp);
- class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp);
+ // 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;
+ };
+
+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();
+
+ 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";
+
+ 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;
+ }
+
+ LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node, const widget_registry_t& );
+
+ static const widget_registry_t& getWidgetRegistry(LLView*);
+
+ template<typename T>
+ static T* createFromFile(const std::string &filename, LLView *parent, LLXMLNodePtr output_node = NULL)
+ {
+ //#pragma message("Generating LLUICtrlFactory::createFromFile")
+ T* widget = NULL;
+
+ std::string skinned_filename = findSkinnedFilename(filename);
+ getInstance()->mFileNames.push_back(skinned_filename);
+ {
+ LLXMLNodePtr root_node;
+
+ //if exporting, only load the language being exported,
+ //instead of layering localized version on top of english
+ if (output_node)
+ {
+ if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root_node))
+ {
+ llwarns << "Couldn't parse XUI file: " << filename << llendl;
+ goto fail;
+ }
+ }
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
+ {
+ llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl;
+ goto fail;
+ }
+
+ LLView* view = getInstance()->createFromXML(root_node, parent, filename, output_node, getWidgetRegistry(parent));
+ if (view)
+ {
+ widget = dynamic_cast<T*>(view);
+ // not of right type, so delete it
+ if (!widget)
+ {
+ delete view;
+ view = NULL;
+ }
+
+ }
+ }
+fail:
+ getInstance()->mFileNames.pop_back();
+ return widget;
+ }
+
+ template<class T>
+ static T* getDefaultWidget(const std::string& name)
+ {
+ dummy_widget_creator_func_t* dummy_func = LLDummyWidgetRegistry::instance().getValue(&typeid(T));
+ return dynamic_cast<T*>((*dummy_func)(name));
+ }
+
+ template <class T>
+ static LLView* createDefaultWidget(const std::string& name)
+ {
+ typename T::Params params;
+ params.name(name);
+
+ return create<T>(params);
+ }
+
+ template<typename T, typename PARAM_BLOCK>
+ static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
+ {
+ LLFastTimer timer(FTM_WIDGET_SETUP);
+
+ //#pragma message("Generating LLUICtrlFactory::defaultBuilder")
+ PARAM_BLOCK params(getDefaultParams<PARAM_BLOCK>());
+
+ LLXUIParser::instance().readXUI(node, params);
+
+ 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;
+ {
+ LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
+ widget = new T(params);
+ }
+ {
+ LLFastTimer timer(FTM_INIT_FROM_PARAMS);
+ widget->initFromParams(params);
+ }
+
+ if (parent)
+ {
+ S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
+ setCtrlParent(widget, parent, tab_group);
+ }
+
+ createChildren(widget, node, output_node);
+
+ if (!widget->postBuild())
+ {
+ delete widget;
+ return NULL;
+ }
+
+ return widget;
+ }
+
+ static void createChildren(LLView* viewp, LLXMLNodePtr node, LLXMLNodePtr output_node = NULL);
static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
+
+ static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
- static const std::vector<std::string>& getXUIPaths();
+ static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
private:
- bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root);
+ //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 DERIVED>
+template<typename T, typename PARAM_BLOCK>
+LLWidgetRegistry<DERIVED>::Register<T, PARAM_BLOCK>::Register(const char* tag, LLWidgetCreatorFunc func)
+: LLWidgetRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T, PARAM_BLOCK> : func)
+{
+ // associate parameter block type with template .xml file
+ LLWidgetTemplateRegistry::instance().defaultRegistrar().add(&typeid(PARAM_BLOCK), tag);
+ // associate widget type with factory function
+ LLDummyWidgetRegistry::instance().defaultRegistrar().add(&typeid(T), &LLUICtrlFactory::createDefaultWidget<T>);
+}
+
+
+typedef boost::function<LLPanel* (void)> LLPannelClassCreatorFunc;
- typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t;
- built_panel_t mBuiltPanels;
+// local static instance for registering a particular panel class
- typedef std::map<LLHandle<LLFloater>, std::string> built_floater_t;
- built_floater_t mBuiltFloaters;
+class LLRegisterPanelClass
+: public LLSingleton< LLRegisterPanelClass >
+{
+public:
+ // reigister with either the provided builder, or the generic templated builder
+ void addPanelClass(const std::string& tag,LLPannelClassCreatorFunc func)
+ {
+ mPannelClassesNames[tag] = func;
+ }
+
+ LLPanel* createPanelClass(const std::string& tag)
+ {
+ param_name_map_t::iterator iT = mPannelClassesNames.find(tag);
+ if(iT == mPannelClassesNames.end())
+ return 0;
+ return iT->second();
+ }
+ template<typename T>
+ static T* defaultPanelClassBuilder()
+ {
+ T* pT = new T();
+ return pT;
+ }
- std::deque<const LLCallbackMap::map_t*> mFactoryStack;
+private:
+ typedef std::map< std::string, LLPannelClassCreatorFunc> param_name_map_t;
+
+ param_name_map_t mPannelClassesNames;
+};
- static std::vector<std::string> sXUIPaths;
- LLPanel* mDummyPanel;
+// local static instance for registering a particular panel class
+template<typename T>
+class LLRegisterPanelClassWrapper
+: public LLRegisterPanelClass
+{
+public:
+ // reigister with either the provided builder, or the generic templated builder
+ LLRegisterPanelClassWrapper(const std::string& tag);
};
+template<typename T>
+LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)
+{
+ LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
+}
+
+
#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..8e0de0cb0c
--- /dev/null
+++ b/indra/llui/lluiimage.cpp
@@ -0,0 +1,166 @@
+/**
+ * @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)
+{
+}
+
+LLUIImage::~LLUIImage()
+{
+}
+
+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"
+ if (!a && !b)
+ return false;
+ else
+ return (a == b);
+ }
+}
diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h
new file mode 100644
index 0000000000..e35026cd3d
--- /dev/null
+++ b/indra/llui/lluiimage.h
@@ -0,0 +1,114 @@
+/**
+ * @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);
+ virtual ~LLUIImage();
+
+ 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; }
+
+ virtual S32 getWidth() const;
+ virtual 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 char* 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..7ce0fd7a88 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;
@@ -111,7 +112,18 @@ void LLUIString::clear()
void LLUIString::format()
{
+ // optimize for empty strings (don't attempt string replacement)
+ if (mOrig.empty())
+ {
+ mResult.clear();
+ mWResult.clear();
+ return;
+ }
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 31788da117..d225ad2767 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -56,19 +56,18 @@
#include "lltexteditor.h"
#include "lltextbox.h"
-using namespace LLOldEvents;
-
-//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;
@@ -76,77 +75,78 @@ 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),
+ top_pad("top_pad"),
+ top_delta("top_delta", S32_MAX),
+ left_pad("left_pad"),
+ left_delta("left_delta", S32_MAX),
+ center_horiz("center_horiz", false),
+ center_vert("center_vert", false),
+ 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()),
+ mDefaultWidgets(NULL)
{
+ // 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 );
}
@@ -157,16 +157,13 @@ LLView::~LLView()
mParentView->removeChild(this);
}
- dispatch_list_t::iterator itor;
- for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
+ if (mDefaultWidgets)
{
- (*itor).second->clearDispatchers();
+ std::for_each(mDefaultWidgets->begin(), mDefaultWidgets->end(),
+ DeletePairedPointer());
+ delete mDefaultWidgets;
+ mDefaultWidgets = NULL;
}
-
- std::for_each(mFloaterControls.begin(), mFloaterControls.end(),
- DeletePairedPointer());
- std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(),
- DeletePairedPointer());
}
// virtual
@@ -187,7 +184,6 @@ BOOL LLView::isPanel() const
return FALSE;
}
-// virtual
void LLView::setToolTip(const LLStringExplicit& msg)
{
mToolTipMsg = msg;
@@ -234,19 +230,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);
+ }
}
}
@@ -266,12 +274,18 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child)
}
}
-void LLView::addChild(LLView* child, S32 tab_group)
+// virtual
+bool LLView::addChild(LLView* child, S32 tab_group)
{
+ if (!child)
+ {
+ return false;
+ }
if (mParentView == child)
{
llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
}
+
// remove from current parent
if (child->mParentView)
{
@@ -284,55 +298,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
@@ -342,28 +347,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;
@@ -653,7 +636,7 @@ BOOL LLView::canSnapTo(const LLView* other_view)
}
// virtual
-void LLView::snappedTo(const LLView* snap_view)
+void LLView::setSnappedTo(const LLView* snap_view)
{
}
@@ -671,6 +654,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();
@@ -731,32 +725,32 @@ 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;
+ if(!tool_tip.empty())
+ {
+ msg = tool_tip;
+ // Convert rect local to screen coordinates
+ localPointToScreen(
+ 0, 0,
+ &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
+ localPointToScreen(
+ mRect.getWidth(), mRect.getHeight(),
+ &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+ }
// don't allow any siblings to handle this event
// even if we don't have a tooltip
- if (blockMouseEvent(x, y) || show_names_text_box)
+ if (getMouseOpaque() ||
+ (!tool_tip.empty() &&
+ (!LLUI::sShowXUINames || dynamic_cast<LLTextBox*>(this))))
{
- if(!tool_tip.empty())
- {
- msg = tool_tip;
-
- // Convert rect local to screen coordinates
- localPointToScreen(
- 0, 0,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- localPointToScreen(
- mRect.getWidth(), mRect.getHeight(),
- &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
- }
handled = TRUE;
}
@@ -922,22 +916,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;
}
@@ -1163,6 +1157,7 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
{
sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage;
}
+
handled_view = viewp;
break;
}
@@ -1325,55 +1320,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
@@ -1388,9 +1386,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
{
@@ -1413,8 +1423,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;
@@ -1424,7 +1434,7 @@ void LLView::drawDebugRect()
std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
debug_rect.getWidth(), debug_rect.getHeight());
LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
- LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
+ LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
S32_MAX, S32_MAX, NULL, FALSE);
}
}
@@ -1580,15 +1590,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();
@@ -1687,7 +1710,12 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_
if (create_if_missing)
{
- return createDummyWidget<LLView>(name);
+ LLView* view = getDefaultWidget<LLView>(name);
+ if (!view)
+ {
+ view = LLUICtrlFactory::createDefaultWidget<LLView>(name);
+ }
+ return view;
}
return NULL;
}
@@ -1776,12 +1804,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;
}
@@ -1942,132 +1990,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()
{
@@ -2104,7 +2026,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);
@@ -2352,560 +2279,482 @@ 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)
+LLControlVariable *LLView::findControl(const std::string& name)
{
- dispatch_list_t::iterator itor = mDispatchList.find(name);
- if (itor != mDispatchList.end())
+ // parse the name to locate which group it belongs to
+ std::size_t key_pos= name.find(".");
+ if(key_pos!= std::string::npos )
{
- mDispatchList.erase(itor);
+ std::string control_group_key = name.substr(0, key_pos);
+ LLControlVariable* control;
+ // check if it's in the control group that name indicated
+ if(LLUI::sSettingGroups[control_group_key])
+ {
+ control = LLUI::sSettingGroups[control_group_key]->getControl(name);
+ if (control)
+ {
+ return control;
+ }
+ }
}
+
+ LLControlGroup& control_group = LLUI::getControlControlGroup(name);
+ return control_group.getControl(name);
}
-std::string LLView::findEventListener(LLSimpleListener *listener) const
+const widget_registry_t& LLView::getChildRegistry() 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;
+ static widget_registry_t empty_registry;
+ return empty_registry;
}
-LLSimpleListener* LLView::getListenerByName(const std::string& callback_name)
+
+const S32 FLOATER_H_MARGIN = 15;
+const S32 MIN_WIDGET_HEIGHT = 10;
+const S32 VPAD = 4;
+
+void LLView::initFromParams(const LLView::Params& params)
{
- LLSimpleListener* callback = NULL;
- dispatch_list_t::iterator itor = mDispatchList.find(callback_name);
- if (itor != mDispatchList.end())
- {
- callback = itor->second;
- }
- else if (mParentView)
+ LLRect required_rect = getRequiredRect();
+
+ S32 width = llmax(getRect().getWidth(), required_rect.getWidth());
+ S32 height = llmax(getRect().getHeight(), required_rect.getHeight());
+
+ reshape(width, height);
+
+ // call virtual methods with most recent data
+ // use getters because these values might not come through parameter block
+ setEnabled(getEnabled());
+ setVisible(getVisible());
+
+ if (!params.name().empty())
{
- callback = mParentView->getListenerByName(callback_name);
+ setName(params.name());
}
- return callback;
+
+ mLayout = params.layout();
}
-LLControlVariable *LLView::findControl(const std::string& name)
+void LLView::parseFollowsFlags(const LLView::Params& params)
{
- control_map_t::iterator itor = mFloaterControls.find(name);
- if (itor != mFloaterControls.end())
+ // preserve follows flags set by code if user did not override
+ if (!params.follows.isProvided())
{
- return itor->second;
+ return;
}
- if (mParentView)
+
+ // interpret either string or bitfield version of follows
+ if (params.follows.string.isChosen())
{
- return mParentView->findControl(name);
- }
- return LLUI::sConfigGroup->getControl(name);
-}
+ setFollows(FOLLOWS_NONE);
-const S32 FLOATER_H_MARGIN = 15;
-const S32 MIN_WIDGET_HEIGHT = 10;
-const S32 VPAD = 4;
+ std::string follows = params.follows.string;
-// static
-U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect)
-{
- U32 follows = 0;
- S32 x = rect.mLeft;
- S32 y = rect.mBottom;
- S32 w = rect.getWidth();
- S32 h = rect.getHeight();
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|");
+ tokenizer tokens(follows, sep);
+ tokenizer::iterator token_iter = tokens.begin();
- U32 last_x = 0;
- U32 last_y = 0;
- if (parent_view)
- {
- last_y = parent_view->getRect().getHeight();
- child_list_t::const_iterator itor = parent_view->getChildList()->begin();
- if (itor != parent_view->getChildList()->end())
+ while(token_iter != tokens.end())
{
- LLView *last_view = (*itor);
- if (last_view->getSaveToXML())
+ const std::string& token_str = *token_iter;
+ if (token_str == "left")
+ {
+ setFollowsLeft();
+ }
+ else if (token_str == "right")
{
- last_x = last_view->getRect().mLeft;
- last_y = last_view->getRect().mBottom;
+ setFollowsRight();
+ }
+ else if (token_str == "top")
+ {
+ setFollowsTop();
+ }
+ else if (token_str == "bottom")
+ {
+ setFollowsBottom();
}
+ else if (token_str == "all")
+ {
+ setFollowsAll();
+ }
+ ++token_iter;
}
}
-
- std::string rect_control;
- node->getAttributeString("rect_control", rect_control);
- if (! rect_control.empty())
- {
- LLRect rect = LLUI::sConfigGroup->getRect(rect_control);
- x = rect.mLeft;
- y = rect.mBottom;
- w = rect.getWidth();
- h = rect.getHeight();
- }
-
- if (node->hasAttribute("left"))
+ else if (params.follows.flags.isChosen())
{
- node->getAttributeS32("left", x);
- }
- if (node->hasAttribute("bottom"))
- {
- node->getAttributeS32("bottom", y);
+ setFollows(params.follows.flags);
}
+}
- // Make your width the width of the containing
- // view if you don't specify a width.
- if (parent_view)
- {
- if(w == 0)
- {
- w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
- }
- if(h == 0)
- {
- h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
+// static
+//LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
+//{
+// LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
+//
+// if (node->hasAttribute("halign"))
+// {
+// std::string horizontal_align_name;
+// node->getAttributeString("halign", horizontal_align_name);
+// gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
+// }
+// return gl_hfont_align;
+//}
+
+// Return the rectangle of the last-constructed child,
+// if present and a first-class widget (eg, not a close box or drag handle)
+// Returns true if found
+static bool get_last_child_rect(LLView* parent, LLRect *rect)
+{
+ if (!parent) return false;
+
+ LLView::child_list_t::const_iterator itor =
+ parent->getChildList()->begin();
+ for (;itor != parent->getChildList()->end(); ++itor)
+ {
+ LLView *last_view = (*itor);
+ if (last_view->getSaveToXML())
+ {
+ *rect = last_view->getRect();
+ return true;
}
}
+ return false;
+}
- if (node->hasAttribute("width"))
- {
- node->getAttributeS32("width", w);
- }
- if (node->hasAttribute("height"))
+//static
+void LLView::setupParams(LLView::Params& p, LLView* parent)
+{
+ const S32 VPAD = 4;
+ const S32 MIN_WIDGET_HEIGHT = 10;
+
+ p.serializable(true);
+
+ // *NOTE: This will confuse export of floater/panel coordinates unless
+ // the default is also "topleft". JC
+ if (p.layout().empty() && parent)
{
- node->getAttributeS32("height", h);
+ p.layout = parent->getLayout();
}
- if (parent_view)
+ if (parent)
{
- if (node->hasAttribute("left_delta"))
- {
- S32 left_delta = 0;
- node->getAttributeS32("left_delta", left_delta);
- x = last_x + left_delta;
- }
- else if (node->hasAttribute("left") && node->hasAttribute("right"))
+ LLRect parent_rect = parent->getLocalRect();
+ // overwrite uninitialized rect params, using context
+ LLRect last_rect = parent->getLocalRect();
+
+ bool layout_topleft = (p.layout() == "topleft");
+ if (layout_topleft)
{
- // compute width based on left and right
- S32 right = 0;
- node->getAttributeS32("right", right);
- if (right < 0)
- {
- right = parent_view->getRect().getWidth() + right;
- }
- w = right - x;
+ //invert top to bottom
+ if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top;
+ if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom;
}
- else if (node->hasAttribute("left"))
+
+ // convert negative or centered coordinates to parent relative values
+ // Note: some of this logic matches the logic in TypedParam<LLRect>::getValueFromBlock()
+
+ if (p.center_horiz)
{
- if (x < 0)
+ if (p.rect.left.isProvided() && p.rect.right.isProvided())
{
- x = parent_view->getRect().getWidth() + x;
- follows |= FOLLOWS_RIGHT;
+ S32 width = p.rect.right - p.rect.left;
+ width = llmax(width, 0);
+ S32 offset = parent_rect.getWidth()/2 - width/2;
+ p.rect.left = p.rect.left + offset;
+ p.rect.right = p.rect.right + offset;
}
else
{
- follows |= FOLLOWS_LEFT;
+ p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2;
}
}
- else if (node->hasAttribute("width") && node->hasAttribute("right"))
+ else
+ {
+ 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();
+ }
+ if (p.center_vert)
{
- S32 right = 0;
- node->getAttributeS32("right", right);
- if (right < 0)
+ 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
{
- right = parent_view->getRect().getWidth() + right;
+ p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2;
}
- x = right - w;
}
else
{
- // left not specified, same as last
- x = last_x;
+ 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();
}
- if (node->hasAttribute("bottom_delta"))
+
+ // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels
+ if (!p.rect.height.isProvided() && !p.rect.top.isProvided())
{
- S32 bottom_delta = 0;
- node->getAttributeS32("bottom_delta", bottom_delta);
- y = last_y + bottom_delta;
+ p.rect.height = MIN_WIDGET_HEIGHT;
}
- else if (node->hasAttribute("top"))
+
+ last_rect.translate(0, last_rect.getHeight());
+
+ // If there was a recently constructed child, use its rectangle
+ get_last_child_rect(parent, &last_rect);
+
+ if (layout_topleft)
{
- // compute height based on top
- S32 top = 0;
- node->getAttributeS32("top", top);
- if (top < 0)
+ p.bottom_delta.setIfNotProvided(0, false);
+
+ // Invert the sense of bottom_delta for topleft layout
+ if (p.bottom_delta.isProvided())
{
- top = parent_view->getRect().getHeight() + top;
+ p.bottom_delta = -p.bottom_delta;
}
- h = top - y;
- }
- else if (node->hasAttribute("bottom"))
- {
- if (y < 0)
+ else if (p.top_pad.isProvided())
{
- y = parent_view->getRect().getHeight() + y;
- follows |= FOLLOWS_TOP;
+ p.bottom_delta = -(p.rect.height + p.top_pad);
}
- else
+ else if (p.top_delta.isProvided())
{
- follows |= FOLLOWS_BOTTOM;
+ p.bottom_delta =
+ -(p.top_delta + p.rect.height - last_rect.getHeight());
}
- }
- else
- {
- // if bottom not specified, generate automatically
- if (last_y == 0)
+ else if (!p.bottom_delta.isProvided()
+ && !p.left_delta.isProvided()
+ && !p.top_pad.isProvided()
+ && !p.left_pad.isProvided())
{
- // treat first child as "bottom"
- y = parent_view->getRect().getHeight() - (h + VPAD);
- follows |= FOLLOWS_TOP;
+ // set default position is just below last rect
+ p.bottom_delta.set(-(p.rect.height + VPAD), false);
}
- else
+
+ // default to same left edge
+ p.left_delta.setIfNotProvided(0, false);
+ if (p.left_pad.isProvided())
{
- // treat subsequent children as "bottom_delta"
- y = last_y - (h + VPAD);
+ // left_pad is based on prior widget's right edge
+ p.left_delta.set(p.left_pad + last_rect.getWidth(), false);
}
+
+ last_rect.translate(p.left_delta, p.bottom_delta);
+ }
+ else
+ {
+ // set default position is just below last rect
+ p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false);
+ p.left_delta.setIfNotProvided(0, false);
+ last_rect.translate(p.left_delta, p.bottom_delta);
}
- }
- else
- {
- x = llmax(x, 0);
- y = llmax(y, 0);
- follows = FOLLOWS_LEFT | FOLLOWS_TOP;
- }
- rect.setOriginAndSize(x, y, w, h);
-
- return follows;
-}
-
-void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
-{
- // create rect first, as this will supply initial follows flags
- LLRect view_rect;
- U32 follows_flags = createRect(node, view_rect, parent, getRequiredRect());
- // call reshape in case there are any child elements that need to be layed out
- reshape(view_rect.getWidth(), view_rect.getHeight());
- setRect(view_rect);
- setFollows(follows_flags);
-
- parseFollowsFlags(node);
- if (node->hasAttribute("control_name"))
- {
- std::string control_name;
- node->getAttributeString("control_name", control_name);
- setControlName(control_name, NULL);
- }
+ // this handles case where *both* x and x_delta are provided
+ // ignore x in favor of default x + x_delta
+ if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false);
+ if (p.left_delta.isProvided()) p.rect.left.set(0, false);
- if (node->hasAttribute("tool_tip"))
- {
- std::string tool_tip_msg;
- node->getAttributeString("tool_tip", tool_tip_msg);
- setToolTip(tool_tip_msg);
+ // selectively apply rectangle defaults, making sure that
+ // params are not flagged as having been "provided"
+ // as rect params are overconstrained and rely on provided flags
+ p.rect.left.setIfNotProvided(last_rect.mLeft, false);
+ p.rect.bottom.setIfNotProvided(last_rect.mBottom, false);
+ p.rect.top.setIfNotProvided(last_rect.mTop, false);
+ p.rect.right.setIfNotProvided(last_rect.mRight, false);
+ p.rect.width.setIfNotProvided(last_rect.getWidth(), false);
+ p.rect.height.setIfNotProvided(last_rect.getHeight(), false);
}
+}
- if (node->hasAttribute("enabled"))
- {
- BOOL enabled;
- node->getAttributeBOOL("enabled", enabled);
- setEnabled(enabled);
- }
-
- if (node->hasAttribute("visible"))
+static S32 invert_vertical(S32 y, LLView* parent)
+{
+ if (y < 0)
{
- BOOL visible;
- node->getAttributeBOOL("visible", visible);
- setVisible(visible);
+ // already based on top-left, just invert
+ return -y;
}
-
- if (node->hasAttribute("hover_cursor"))
+ else if (parent)
{
- std::string cursor_string;
- node->getAttributeString("hover_cursor", cursor_string);
- mHoverCursor = getCursorFromString(cursor_string);
+ // use parent to flip coordinate
+ S32 parent_height = parent->getRect().getHeight();
+ return parent_height - y;
}
-
- node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect);
- node->getAttributeBOOL("mouse_opaque", mMouseOpaque);
-
- node->getAttributeS32("default_tab_group", mDefaultTabGroup);
-
- reshape(view_rect.getWidth(), view_rect.getHeight());
-}
-
-void LLView::parseFollowsFlags(LLXMLNodePtr node)
-{
- if (node->hasAttribute("follows"))
+ else
{
- setFollowsNone();
-
- std::string follows;
- node->getAttributeString("follows", follows);
-
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("|");
- tokenizer tokens(follows, sep);
- tokenizer::iterator token_iter = tokens.begin();
-
- while(token_iter != tokens.end())
- {
- const std::string& token_str = *token_iter;
- if (token_str == "left")
+ llwarns << "Attempting to convert layout to top-left with no parent" << llendl;
+ return y;
+ }
+}
+
+// Assumes that input is in bottom-left coordinates, hence must call
+// _before_ convert_coords_to_top_left().
+static void convert_to_relative_layout(LLView::Params& p, LLView* parent)
+{
+ // Use setupParams to get the final widget rectangle
+ // according to our wacky layout rules.
+ LLView::Params final = p;
+ LLView::setupParams(final, parent);
+ // Must actually extract the rectangle to get consistent
+ // right = left+width, top = bottom+height
+ LLRect final_rect = final.rect;
+
+ // We prefer to write out top edge instead of bottom, regardless
+ // of whether we use relative positioning
+ bool converted_top = false;
+
+ // Look for a last rectangle
+ LLRect last_rect;
+ if (get_last_child_rect(parent, &last_rect))
+ {
+ // ...we have a previous widget to compare to
+ const S32 EDGE_THRESHOLD_PIXELS = 4;
+ S32 left_pad = final_rect.mLeft - last_rect.mRight;
+ S32 left_delta = final_rect.mLeft - last_rect.mLeft;
+ S32 top_pad = final_rect.mTop - last_rect.mBottom;
+ S32 top_delta = final_rect.mTop - last_rect.mTop;
+ // If my left edge is almost the same, or my top edge is
+ // almost the same...
+ if (llabs(left_delta) <= EDGE_THRESHOLD_PIXELS
+ || llabs(top_delta) <= EDGE_THRESHOLD_PIXELS)
+ {
+ // ...use relative positioning
+ // prefer top_pad if widgets are stacking vertically
+ // (coordinate system is still bottom-left here)
+ if (top_pad < 0)
{
- setFollowsLeft();
+ p.top_pad = top_pad;
+ p.top_delta.setProvided(false);
}
- else if (token_str == "right")
+ else
{
- setFollowsRight();
+ p.top_pad.setProvided(false);
+ p.top_delta = top_delta;
}
- else if (token_str == "top")
+ // null out other vertical specifiers
+ p.rect.top.setProvided(false);
+ p.rect.bottom.setProvided(false);
+ p.bottom_delta.setProvided(false);
+ converted_top = true;
+
+ // prefer left_pad if widgets are stacking horizontally
+ if (left_pad > 0)
{
- setFollowsTop();
+ p.left_pad = left_pad;
+ p.left_delta.setProvided(false);
}
- else if (token_str == "bottom")
- {
- setFollowsBottom();
- }
- else if (token_str == "all")
+ else
{
- setFollowsAll();
+ p.left_pad.setProvided(false);
+ p.left_delta = left_delta;
}
- ++token_iter;
+ p.rect.left.setProvided(false);
+ p.rect.right.setProvided(false);
}
}
-}
-
-// 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"))
+ if (!converted_top)
{
- node->getAttributeString("font_style", font_style);
- style = LLFontGL::getStyleFromString(font_style);
+ // ...this is the first widget, or one that wasn't aligned
+ // prefer top/left specification
+ p.rect.top = final_rect.mTop;
+ p.rect.bottom.setProvided(false);
+ p.bottom_delta.setProvided(false);
+ p.top_pad.setProvided(false);
+ p.top_delta.setProvided(false);
}
-
- if (node->hasAttribute("font-style"))
- {
- node->getAttributeString("font-style", font_style);
- style = LLFontGL::getStyleFromString(font_style);
- }
-
- 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)
+static void convert_coords_to_top_left(LLView::Params& p, LLView* parent)
{
- LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
-
- if (node->hasAttribute("halign"))
+ // Convert the coordinate system to be top-left based.
+ if (p.rect.top.isProvided())
{
- std::string horizontal_align_name;
- node->getAttributeString("halign", horizontal_align_name);
- gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
+ p.rect.top = invert_vertical(p.rect.top, parent);
}
- return gl_hfont_align;
-}
-
-// static
-LLFontGL::VAlign LLView::selectFontVAlign(LLXMLNodePtr node)
-{
- LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
-
- if (node->hasAttribute("valign"))
+ if (p.rect.bottom.isProvided())
{
- std::string vert_align_name;
- node->getAttributeString("valign", vert_align_name);
- gl_vfont_align = LLFontGL::vAlignFromName(vert_align_name);
+ p.rect.bottom = invert_vertical(p.rect.bottom, parent);
}
- return gl_vfont_align;
-}
-
-// static
-LLFontGL::StyleFlags LLView::selectFontStyle(LLXMLNodePtr node)
-{
- LLFontGL::StyleFlags gl_font_style = LLFontGL::NORMAL;
-
- if (node->hasAttribute("style"))
+ if (p.top_pad.isProvided())
{
- std::string style_flags_name;
- node->getAttributeString("style", style_flags_name);
-
- if (style_flags_name == "normal")
- {
- gl_font_style = LLFontGL::NORMAL;
- }
- else if (style_flags_name == "bold")
- {
- gl_font_style = LLFontGL::BOLD;
- }
- else if (style_flags_name == "italic")
- {
- gl_font_style = LLFontGL::ITALIC;
- }
- else if (style_flags_name == "underline")
- {
- gl_font_style = LLFontGL::UNDERLINE;
- }
- //else leave left
+ p.top_pad = -p.top_pad;
}
- return gl_font_style;
-}
-
-bool LLView::setControlValue(const LLSD& value)
-{
- std::string ctrlname = getControlName();
- if (!ctrlname.empty())
+ if (p.top_delta.isProvided())
{
- LLUI::sConfigGroup->setValue(ctrlname, value);
- return true;
+ p.top_delta = -p.top_delta;
}
- return false;
-}
-
-//virtual
-void LLView::setControlName(const std::string& control_name, LLView *context)
-{
- if (context == NULL)
+ if (p.bottom_delta.isProvided())
{
- context = this;
+ p.bottom_delta = -p.bottom_delta;
}
+ p.layout = "topleft";
+}
- 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())
+//static
+void LLView::setupParamsForExport(Params& p, LLView* parent)
+{
+ // Don't convert if already top-left based
+ if (p.layout() == "topleft")
{
- LLControlVariable *control = context->findControl(control_name);
- if (control)
- {
- mControlName = control_name;
- mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _1, getHandle(), std::string("value")));
- setValue(control->getValue());
- }
+ return;
}
-}
-// static
-bool LLView::controlListener(const LLSD& newvalue, LLHandle<LLView> handle, std::string type)
-{
- LLView* view = handle.get();
- if (view)
+ // heuristic: Many of our floaters and panels were bulk-exported.
+ // These specify exactly bottom/left and height/width.
+ // Others were done by hand using bottom_delta and/or left_delta.
+ // Some rely on not specifying left to mean align with left edge.
+ // Try to convert both to use relative layout, but using top-left
+ // coordinates.
+ // Avoid rectangles where top/bottom/left/right was specified.
+ if (p.rect.height.isProvided() && p.rect.width.isProvided())
{
- if (type == "value")
+ if (p.rect.bottom.isProvided() && p.rect.left.isProvided())
{
- view->setValue(newvalue);
- return true;
+ // standard bulk export, convert it
+ convert_to_relative_layout(p, parent);
}
- else if (type == "enabled")
+ else if (p.rect.bottom.isProvided() && p.left_delta.isProvided())
{
- view->setEnabled(newvalue.asBoolean());
- return true;
+ // hand layout with left_delta
+ convert_to_relative_layout(p, parent);
}
- else if (type == "visible")
+ else if (p.bottom_delta.isProvided())
{
- view->setVisible(newvalue.asBoolean());
- return true;
+ // hand layout with bottom_delta
+ // don't check for p.rect.left or p.left_delta because sometimes
+ // this layout doesn't set it for widgets that are left-aligned
+ convert_to_relative_layout(p, parent);
}
}
- 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"));
-}
-
-LLControlVariable *LLView::getControl(const std::string& name)
-{
- control_map_t::iterator itor = mFloaterControls.find(name);
- if (itor != mFloaterControls.end())
- {
- return itor->second;
- }
- return NULL;
-}
-//virtual
-void LLView::setValue(const LLSD& value)
-{
+ convert_coords_to_top_left(p, parent);
}
-//virtual
-LLSD LLView::getValue() const
-{
- return LLSD();
-}
-
-LLView* LLView::createWidget(LLXMLNodePtr xml_node) const
-{
- // forward requests to ui ctrl factory
- return LLUICtrlFactory::getInstance()->createCtrlWidget(NULL, xml_node);
-}
-
-//
-// LLWidgetClassRegistry
-//
-
-LLWidgetClassRegistry::LLWidgetClassRegistry()
+LLView::tree_iterator_t LLView::beginTree()
{
+ return tree_iterator_t(this,
+ boost::bind(boost::mem_fn(&LLView::beginChild), _1),
+ boost::bind(boost::mem_fn(&LLView::endChild), _1));
}
-void LLWidgetClassRegistry::registerCtrl(const std::string& tag, LLWidgetClassRegistry::factory_func_t function)
+LLView::tree_iterator_t LLView::endTree()
{
- std::string lower_case_tag = tag;
- LLStringUtil::toLower(lower_case_tag);
-
- mCreatorFunctions[lower_case_tag] = function;
+ // an empty iterator is an "end" iterator
+ return tree_iterator_t();
}
-BOOL LLWidgetClassRegistry::isTagRegistered(const std::string &tag)
-{
- return mCreatorFunctions.find(tag) != mCreatorFunctions.end();
-}
-
-LLWidgetClassRegistry::factory_func_t LLWidgetClassRegistry::getCreatorFunc(const std::string& ctrl_type)
-{
- factory_map_t::const_iterator found_it = mCreatorFunctions.find(ctrl_type);
- if (found_it == mCreatorFunctions.end())
+// only create maps on demand, as they incur heap allocation/deallocation cost
+// when a view is constructed/deconstructed
+LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const
+{
+ if (!mDefaultWidgets)
{
- return NULL;
+ mDefaultWidgets = new default_widget_map_t();
}
- return found_it->second;
+ return *mDefaultWidgets;
}
-
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 721fe99f4a..422f62f602 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -37,6 +37,7 @@
// the HUD or a dialog box or a button. It can also contain sub-views
// and child widgets
+#include "stdtypes.h"
#include "llcoord.h"
#include "llfontgl.h"
#include "llmortician.h"
@@ -47,12 +48,14 @@
#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);
@@ -122,24 +122,14 @@ 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
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,69 @@ 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;
+ Alternative<std::string> string;
+ Alternative<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;
+ // Historical bottom-left layout used bottom_delta and left_delta
+ // for relative positioning. New layout "topleft" prefers specifying
+ // based on top edge.
+ Optional<S32> bottom_delta, // deprecated
+ top_pad, // from last bottom to my top
+ top_delta, // from last top to my top
+ left_pad, // from last right to my left
+ left_delta; // from last left to my left
+
+ Optional<bool> center_horiz,
+ center_vert;
+
+ // these are nested attributes for LLLayoutPanel
+ //FIXME: get parent context involved in parsing traversal
+ Ignored 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 +245,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 +288,19 @@ public:
void sendChildToBack(LLView* child);
void moveChildToFrontOfTabGroup(LLUICtrl* child);
void moveChildToBackOfTabGroup(LLUICtrl* child);
+
+ 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 +308,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 +340,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 +354,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 +369,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 +392,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 +406,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 +435,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)
- LLOldEvents::LLSimpleListener* getListenerByName(const std::string& callback_name);
- void registerEventListener(std::string name, LLOldEvents::LLSimpleListener* function);
- void deregisterEventListener(std::string name);
- std::string findEventListener(LLOldEvents::LLSimpleListener *listener) const;
- void addListenerToControl(LLOldEvents::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 +465,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,72 +486,24 @@ 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
+ template <class T> T* getDefaultWidget(const std::string& name) const
{
- dummy_widget_map_t::const_iterator found_it = mDummyWidgets.find(name);
- if (found_it == mDummyWidgets.end())
+ default_widget_map_t::const_iterator found_it = getDefaultWidgetMap().find(name);
+ if (found_it == getDefaultWidgetMap().end())
{
return NULL;
}
return dynamic_cast<T*>(found_it->second);
}
- LLView* createWidget(LLXMLNodePtr xml_node) const;
-
+ // determines allowable children when parsing XUI
+ virtual const widget_registry_t& getChildRegistry() 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);
-
+ //////////////////////////////////////////////
+ //static LLFontGL::HAlign selectFontHAlign(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 +514,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);
+
+protected:
void drawDebugRect();
void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE);
@@ -612,11 +554,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 +564,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 +592,12 @@ private:
static LLWindow* sWindow; // All root views must know about their window.
- typedef std::map<std::string, LLPointer<LLOldEvents::LLSimpleListener> > dispatch_list_t;
- dispatch_list_t mDispatchList;
-
- std::string mControlName;
+ typedef std::map<std::string, LLView*> default_widget_map_t;
+ // allocate this map no demand, as it is rarely needed
+ mutable default_widget_map_t* mDefaultWidgets;
- typedef std::map<std::string, LLView*> dummy_widget_map_t;
- mutable dummy_widget_map_t mDummyWidgets;
+ default_widget_map_t& getDefaultWidgetMap() const;
- boost::signals2::connection mControlConnection;
-
- ECursorType mHoverCursor;
-
public:
static BOOL sDebugRects; // Draw debug rects behind everything.
static BOOL sDebugKeys;
@@ -670,8 +605,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 +627,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 = getDefaultWidget<T>(name);
+ if (!result)
+ {
+ result = LLUICtrlFactory::getDefaultWidget<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;
+ }
+
+ getDefaultWidgetMap()[name] = result;
+ }
+ }
+ }
+ return result;
+}
#endif //LL_LLVIEW_H
diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp
index d4a9e9d1bf..a5b09671bb 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 )
+static LLDefaultWidgetRegistry::Register<LLViewBorder> r("view_border");
+
+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()
{
- setFollowsAll();
+ 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")
+{
+ 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;