From a4000c3744e42fcbb638e742f3b63fa31a0dee15 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Fri, 8 May 2009 07:43:08 +0000 Subject: merge trunk@116587 skinning-7@119389 -> viewer-2.0.0-skinning-7 --- indra/llui/CMakeLists.txt | 48 +- indra/llui/llbutton.cpp | 680 ++++---- indra/llui/llbutton.h | 195 ++- indra/llui/llcallbackmap.h | 19 +- indra/llui/llcheckboxctrl.cpp | 278 +-- indra/llui/llcheckboxctrl.h | 73 +- indra/llui/llcombobox.cpp | 555 ++---- indra/llui/llcombobox.h | 126 +- indra/llui/llconsole.cpp | 393 +++++ indra/llui/llconsole.h | 162 ++ indra/llui/llcontainerview.cpp | 301 ++++ indra/llui/llcontainerview.h | 92 + indra/llui/lldraghandle.cpp | 105 +- indra/llui/lldraghandle.h | 44 +- indra/llui/llf32uictrl.cpp | 57 + indra/llui/llf32uictrl.h | 83 + indra/llui/llfloater.cpp | 1649 ++++++------------ indra/llui/llfloater.h | 297 ++-- indra/llui/llfloaterreg.cpp | 423 +++++ indra/llui/llfloaterreg.h | 149 ++ indra/llui/llflyoutbutton.cpp | 94 + indra/llui/llflyoutbutton.h | 71 + indra/llui/llfocusmgr.cpp | 20 +- indra/llui/llfunctorregistry.h | 2 +- indra/llui/lliconctrl.cpp | 126 +- indra/llui/lliconctrl.h | 32 +- indra/llui/llkeywords.cpp | 4 +- indra/llui/lllayoutstack.cpp | 718 ++++++++ indra/llui/lllayoutstack.h | 102 ++ indra/llui/lllazyvalue.h | 83 + indra/llui/lllineeditor.cpp | 690 ++------ indra/llui/lllineeditor.h | 177 +- indra/llui/llmenugl.cpp | 3256 ++++++++++++----------------------- indra/llui/llmenugl.h | 583 ++++--- indra/llui/llmodaldialog.cpp | 48 +- indra/llui/llmodaldialog.h | 2 +- indra/llui/llmultifloater.cpp | 510 ++++++ indra/llui/llmultifloater.h | 107 ++ indra/llui/llmultislider.cpp | 218 +-- indra/llui/llmultislider.h | 97 +- indra/llui/llmultisliderctrl.cpp | 392 ++--- indra/llui/llmultisliderctrl.h | 71 +- indra/llui/llnotifications.cpp | 164 +- indra/llui/llnotifications.h | 97 +- indra/llui/llpanel.cpp | 1133 ++---------- indra/llui/llpanel.h | 164 +- indra/llui/llprogressbar.cpp | 135 +- indra/llui/llprogressbar.h | 45 +- indra/llui/llradiogroup.cpp | 248 +-- indra/llui/llradiogroup.h | 74 +- indra/llui/llresizebar.cpp | 37 +- indra/llui/llresizebar.h | 26 +- indra/llui/llresizehandle.cpp | 57 +- indra/llui/llresizehandle.h | 13 +- indra/llui/llresmgr.cpp | 147 +- indra/llui/llresmgr.h | 25 +- indra/llui/llscrollbar.cpp | 237 ++- indra/llui/llscrollbar.h | 72 +- indra/llui/llscrollcontainer.cpp | 303 ++-- indra/llui/llscrollcontainer.h | 36 +- indra/llui/llscrollingpanellist.cpp | 62 +- indra/llui/llscrollingpanellist.h | 30 +- indra/llui/llscrolllistcell.cpp | 413 +++++ indra/llui/llscrolllistcell.h | 223 +++ indra/llui/llscrolllistcolumn.cpp | 320 ++++ indra/llui/llscrolllistcolumn.h | 189 ++ indra/llui/llscrolllistctrl.cpp | 1884 ++++---------------- indra/llui/llscrolllistctrl.h | 433 ++--- indra/llui/llscrolllistitem.cpp | 157 ++ indra/llui/llscrolllistitem.h | 129 ++ indra/llui/llsdparam.cpp | 158 ++ indra/llui/llsdparam.h | 107 ++ indra/llui/llsearcheditor.cpp | 124 ++ indra/llui/llsearcheditor.h | 98 ++ indra/llui/llslider.cpp | 155 +- indra/llui/llslider.h | 71 +- indra/llui/llsliderctrl.cpp | 339 ++-- indra/llui/llsliderctrl.h | 119 +- indra/llui/llspinctrl.cpp | 371 ++-- indra/llui/llspinctrl.h | 74 +- indra/llui/llstatbar.cpp | 295 ++++ indra/llui/llstatbar.h | 108 ++ indra/llui/llstatgraph.cpp | 163 ++ indra/llui/llstatgraph.h | 76 + indra/llui/llstatview.cpp | 66 + indra/llui/llstatview.h | 63 + indra/llui/llstyle.cpp | 32 +- indra/llui/llstyle.h | 9 +- indra/llui/lltabcontainer.cpp | 790 ++++----- indra/llui/lltabcontainer.h | 119 +- indra/llui/lltextbox.cpp | 245 ++- indra/llui/lltextbox.h | 81 +- indra/llui/lltexteditor.cpp | 572 +++--- indra/llui/lltexteditor.h | 110 +- indra/llui/lltextparser.cpp | 55 +- indra/llui/lltextparser.h | 34 +- indra/llui/llui.cpp | 386 +++-- indra/llui/llui.h | 312 ++-- indra/llui/lluictrl.cpp | 354 +++- indra/llui/lluictrl.h | 179 +- indra/llui/lluictrlfactory.cpp | 984 ++++++++--- indra/llui/lluictrlfactory.h | 320 +++- indra/llui/lluifwd.h | 1 - indra/llui/lluiimage.cpp | 158 ++ indra/llui/lluiimage.h | 113 ++ indra/llui/lluistring.cpp | 7 +- indra/llui/llview.cpp | 1226 +++++-------- indra/llui/llview.h | 345 ++-- indra/llui/llviewborder.cpp | 139 +- indra/llui/llviewborder.h | 57 +- indra/llui/llviewmodel.cpp | 163 ++ indra/llui/llviewmodel.h | 219 +++ indra/llui/llviewquery.h | 2 +- 113 files changed, 15755 insertions(+), 13629 deletions(-) create mode 100644 indra/llui/llconsole.cpp create mode 100644 indra/llui/llconsole.h create mode 100644 indra/llui/llcontainerview.cpp create mode 100644 indra/llui/llcontainerview.h create mode 100644 indra/llui/llf32uictrl.cpp create mode 100644 indra/llui/llf32uictrl.h create mode 100644 indra/llui/llfloaterreg.cpp create mode 100644 indra/llui/llfloaterreg.h create mode 100644 indra/llui/llflyoutbutton.cpp create mode 100644 indra/llui/llflyoutbutton.h create mode 100644 indra/llui/lllayoutstack.cpp create mode 100644 indra/llui/lllayoutstack.h create mode 100644 indra/llui/lllazyvalue.h create mode 100644 indra/llui/llmultifloater.cpp create mode 100644 indra/llui/llmultifloater.h create mode 100644 indra/llui/llscrolllistcell.cpp create mode 100644 indra/llui/llscrolllistcell.h create mode 100644 indra/llui/llscrolllistcolumn.cpp create mode 100644 indra/llui/llscrolllistcolumn.h create mode 100644 indra/llui/llscrolllistitem.cpp create mode 100644 indra/llui/llscrolllistitem.h create mode 100644 indra/llui/llsdparam.cpp create mode 100644 indra/llui/llsdparam.h create mode 100644 indra/llui/llsearcheditor.cpp create mode 100644 indra/llui/llsearcheditor.h create mode 100644 indra/llui/llstatbar.cpp create mode 100644 indra/llui/llstatbar.h create mode 100644 indra/llui/llstatgraph.cpp create mode 100644 indra/llui/llstatgraph.h create mode 100644 indra/llui/llstatview.cpp create mode 100644 indra/llui/llstatview.h create mode 100644 indra/llui/lluiimage.cpp create mode 100644 indra/llui/lluiimage.h create mode 100644 indra/llui/llviewmodel.cpp create mode 100644 indra/llui/llviewmodel.h (limited to 'indra/llui') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 5de8dc76af..f3595a7b05 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -31,17 +31,25 @@ set(llui_SOURCE_FILES llcheckboxctrl.cpp llclipboard.cpp llcombobox.cpp + llconsole.cpp + llcontainerview.cpp llctrlselectioninterface.cpp lldraghandle.cpp lleditmenuhandler.cpp + llf32uictrl.cpp llfloater.cpp + llfloaterreg.cpp + llflyoutbutton.cpp llfocusmgr.cpp llfunctorregistry.cpp lliconctrl.cpp + llinitparam.cpp llkeywords.cpp + lllayoutstack.cpp lllineeditor.cpp llmenugl.cpp llmodaldialog.cpp + llmultifloater.cpp llmultislider.cpp llmultisliderctrl.cpp llnotifications.cpp @@ -51,27 +59,35 @@ set(llui_SOURCE_FILES llresizebar.cpp llresizehandle.cpp llresmgr.cpp - llrootview.cpp llscrollbar.cpp llscrollcontainer.cpp llscrollingpanellist.cpp + llscrolllistcell.cpp + llscrolllistcolumn.cpp llscrolllistctrl.cpp + llscrolllistitem.cpp + llsdparam.cpp + llsearcheditor.cpp llslider.cpp llsliderctrl.cpp llspinctrl.cpp + llstatbar.cpp + llstatgraph.cpp + llstatview.cpp llstyle.cpp lltabcontainer.cpp - lltabcontainervertical.cpp lltextbox.cpp lltexteditor.cpp lltextparser.cpp + lltrans.cpp llui.cpp lluictrl.cpp lluictrlfactory.cpp + lluiimage.cpp lluistring.cpp - lluitrans.cpp llundo.cpp llviewborder.cpp + llviewmodel.cpp llview.cpp llviewquery.cpp ) @@ -85,52 +101,68 @@ set(llui_HEADER_FILES llcheckboxctrl.h llclipboard.h llcombobox.h + llconsole.h + llcontainerview.h llctrlselectioninterface.h lldraghandle.h lleditmenuhandler.h + llf32uictrl.h llfloater.h + llfloaterreg.h + llflyoutbutton.h llfocusmgr.h llfunctorregistry.h llhtmlhelp.h lliconctrl.h + llinitparam.h llkeywords.h + lllayoutstack.h + lllazyvalue.h lllineeditor.h - llmemberlistener.h llmenugl.h llmodaldialog.h + llmultifloater.h llmultisliderctrl.h llmultislider.h llnotifications.h llpanel.h llprogressbar.h llradiogroup.h + llregistry.h llresizebar.h llresizehandle.h llresmgr.h - llrootview.h + llsearcheditor.h llscrollbar.h llscrollcontainer.h llscrollingpanellist.h + llscrolllistcell.h + llscrolllistcolumn.h llscrolllistctrl.h + llscrolllistitem.h + llsdparam.h llsliderctrl.h llslider.h llspinctrl.h + llstatbar.h + llstatgraph.h + llstatview.h llstyle.h lltabcontainer.h - lltabcontainervertical.h lltextbox.h lltexteditor.h lltextparser.h + lltrans.h lluiconstants.h lluictrlfactory.h lluictrl.h lluifwd.h llui.h + lluiimage.h lluistring.h - lluitrans.h - lluixmltags.h llundo.h llviewborder.h + llviewmodel.h llview.h llviewquery.h ) diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 2c2c1c25d8..1f6cd6ddf9 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -32,6 +32,7 @@ #include "linden_common.h" +#define INSTANTIATE_GETCHILD_BUTTON #include "llbutton.h" // Linden library includes @@ -45,183 +46,167 @@ #include "lluiconstants.h" #include "llresmgr.h" #include "llcriticaldamp.h" +#include "llfloater.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llwindow.h" #include "llrender.h" +#include "lluictrlfactory.h" static LLRegisterWidget 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( const std::string& name, BOOL recurse, BOOL create_if_missing ) const; + +LLButton::Params::Params() +: label_selected("label_selected"), // requires is_toggle true + label_dropshadow("label_shadow", true), + auto_resize("auto_resize", false), + image_unselected("image_unselected"), + image_selected("image_selected"), + image_hover_selected("image_hover_selected"), + image_hover_unselected("image_hover_unselected"), + image_disabled_selected("image_disabled_selected"), + image_disabled("image_disabled"), + image_overlay("image_overlay"), + image_overlay_alignment("image_overlay_alignment", std::string("center")), + label_color("label_color"), + label_color_selected("label_color_selected"), // requires is_toggle true + label_color_disabled("label_color_disabled"), + label_color_disabled_selected("label_color_disabled_selected"), + highlight_color("highlight_color"), + image_color("image_color"), + image_color_disabled("image_color_disabled"), + image_overlay_color("image_overlay_color", LLColor4::white), + flash_color("flash_color"), + pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), + pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), + click_callback("click_callback"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + mouse_held_callback("mouse_held_callback"), + mouse_held_once_callback("mouse_held_once_callback"), + is_toggle("is_toggle", false), + scale_image("scale_image", true), + help_url("help_url"), + hover_glow_amount("hover_glow_amount"), + commit_on_return("commit_on_return", true), + picture_style("picture_style", false) { - mUnselectedLabel = name; - mSelectedLabel = name; - - setImageUnselected(std::string("button_enabled_32x128.tga")); - setImageSelected(std::string("button_enabled_selected_32x128.tga")); - setImageDisabled(std::string("button_disabled_32x128.tga")); - setImageDisabledSelected(std::string("button_disabled_32x128.tga")); - - mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - - init(click_callback, callback_data, NULL, control_name); + addSynonym(is_toggle, "toggle"); + held_down_delay.seconds = 0.5f; + initial_value.set(LLSD(false), false); } -LLButton::LLButton(const std::string& name, const LLRect& rect, - const std::string &unselected_image_name, - const std::string &selected_image_name, - const std::string& control_name, - void (*click_callback)(void*), - void *callback_data, - const LLFontGL *font, - const std::string& unselected_label, - const std::string& selected_label ) -: LLUICtrl(name, rect, TRUE, NULL, NULL), - mClickedCallback( click_callback ), - mMouseDownCallback( NULL ), - mMouseUpCallback( NULL ), - mHeldDownCallback( NULL ), - mGLFont( NULL ), - mMouseDownFrame( 0 ), - mHeldDownDelay( 0.5f ), // seconds until held-down callback is called - mHeldDownFrameDelay( 0 ), - mImageUnselected( NULL ), - mImageSelected( NULL ), - mImageHoverSelected( NULL ), - mImageHoverUnselected( NULL ), - mImageDisabled( NULL ), - mImageDisabledSelected( NULL ), - mToggleState( FALSE ), - mIsToggle( FALSE ), - mScaleImage( TRUE ), - mDropShadowedText( TRUE ), +LLButton::LLButton(const LLButton::Params& p) +: LLUICtrl(p), + mMouseDownFrame(0), + mMouseHeldDownCount(0), mBorderEnabled( FALSE ), mFlashing( FALSE ), - mHAlign( LLFontGL::HCENTER ), - mLeftHPad( LLBUTTON_H_PAD ), - mRightHPad( LLBUTTON_H_PAD ), - mHoverGlowStrength(0.25f), mCurGlowStrength(0.f), mNeedsHighlight(FALSE), - mCommitOnReturn(TRUE), - mImagep( NULL ) + mImagep( NULL ), + mUnselectedLabel(p.label()), + mSelectedLabel(p.label_selected()), + mGLFont(p.font), + mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called + mHeldDownFrameDelay(p.held_down_delay.frames), + mImageUnselected(p.image_unselected), + mImageSelected(p.image_selected), + mImageDisabled(p.image_disabled), + mImageDisabledSelected(p.image_disabled_selected), + mImageHoverSelected(p.image_hover_selected), + mImageHoverUnselected(p.image_hover_unselected), + mUnselectedLabelColor(p.label_color()), + mSelectedLabelColor(p.label_color_selected()), + mDisabledLabelColor(p.label_color_disabled()), + mDisabledSelectedLabelColor(p.label_color_disabled_selected()), + mHighlightColor(p.highlight_color()), + mImageColor(p.image_color()), + mFlashBgColor(p.flash_color()), + mDisabledImageColor(p.image_color_disabled()), + mImageOverlay(p.image_overlay()), + mImageOverlayColor(p.image_overlay_color()), + mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)), + mIsToggle(p.is_toggle), + mScaleImage(p.scale_image), + mDropShadowedText(p.label_dropshadow), + mAutoResize(p.auto_resize), + mHAlign(p.font_halign), + mLeftHPad(p.pad_left), + mRightHPad(p.pad_right), + mHoverGlowStrength(p.hover_glow_amount), + mCommitOnReturn(p.commit_on_return), + mFadeWhenDisabled(FALSE) { - mUnselectedLabel = unselected_label; - mSelectedLabel = selected_label; + static LLUICachedControl llbutton_orig_h_pad ("UIButtonOrigHPad", 0); + static LLButton::Params default_params(LLUICtrlFactory::getDefaultParams()); - // by default, disabled color is same as enabled - mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - - if( unselected_image_name != "" ) - { - // user-specified image - don't use fixed borders unless requested - setImageUnselected(unselected_image_name); - setImageDisabled(unselected_image_name); - - mDisabledImageColor.mV[VALPHA] = 0.5f; - mScaleImage = FALSE; - } - else + //if we aren't a picture_style button set label as name if not provided + if (!p.picture_style.isProvided() || !p.picture_style) { - setImageUnselected(std::string("button_enabled_32x128.tga")); - setImageDisabled(std::string("button_disabled_32x128.tga")); - } - - if( selected_image_name != "" ) - { - // user-specified image - don't use fixed borders unless requested - setImageSelected(selected_image_name); - setImageDisabledSelected(selected_image_name); - - mDisabledImageColor.mV[VALPHA] = 0.5f; - mScaleImage = FALSE; - } - else - { - setImageSelected(std::string("button_enabled_selected_32x128.tga")); - setImageDisabledSelected(std::string("button_disabled_32x128.tga")); + if (!p.label.isProvided()) + { + mUnselectedLabel = p.name(); + } + if (!p.label_selected.isProvided()) + { + mSelectedLabel = mUnselectedLabel.getString(); + } } - init(click_callback, callback_data, font, control_name); -} - -void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name) -{ - mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); - // Hack to make sure there is space for at least one character if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) { // Use old defaults - mLeftHPad = LLBUTTON_ORIG_H_PAD; - mRightHPad = LLBUTTON_ORIG_H_PAD; + mLeftHPad = llbutton_orig_h_pad; + mRightHPad = llbutton_orig_h_pad; } - mCallbackUserData = callback_data; mMouseDownTimer.stop(); - setControlName(control_name, NULL); - - mUnselectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelColor" ) ); - mSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedColor" ) ); - mDisabledLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelDisabledColor" ) ); - mDisabledSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedDisabledColor" ) ); - mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) ); - mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) ); - mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) ); - mFlashBgColor = ( LLUI::sColorsGroup->getColor( "ButtonFlashBgColor" ) ); + if (p.help_url.isProvided()) + { + setHelpURLCallback(p.help_url); + } - mImageOverlayAlignment = LLFontGL::HCENTER; - mImageOverlayColor = LLColor4::white; -} + // if custom unselected button image provided... + if (p.image_unselected != default_params.image_unselected) + { + //...fade it out for disabled image by default... + if (p.image_disabled() == default_params.image_disabled() ) + { + mImageDisabled = p.image_unselected; + mFadeWhenDisabled = TRUE; + } + } -LLButton::~LLButton() -{ - if( hasMouseCapture() ) + // if custom selected button image provided... + if (p.image_selected != default_params.image_selected) { - gFocusMgr.setMouseCapture( NULL ); + //...fade it out for disabled image by default... + if (p.image_disabled_selected() == default_params.image_disabled_selected()) + { + mImageDisabledSelected = p.image_selected; + mFadeWhenDisabled = TRUE; + } } + + if (p.click_callback.isProvided()) + initCommitCallback(p.click_callback, mCommitSignal); // alias -> commit_callback + if (p.mouse_down_callback.isProvided()) + initCommitCallback(p.mouse_down_callback, mMouseDownSignal); + if (p.mouse_up_callback.isProvided()) + initCommitCallback(p.mouse_up_callback, mMouseUpSignal); + if (p.mouse_held_callback.isProvided()) + initCommitCallback(p.mouse_held_callback, mHeldDownSignal); } // HACK: Committing a button is the same as instantly clicking it. @@ -229,19 +214,12 @@ LLButton::~LLButton() void LLButton::onCommit() { // WARNING: Sometimes clicking a button destroys the floater or - // panel containing it. Therefore we need to call mClickedCallback + // panel containing it. Therefore we need to call LLUICtrl::onCommit() // LAST, otherwise this becomes deleted memory. - LLUICtrl::onCommit(); - if (mMouseDownCallback) - { - (*mMouseDownCallback)(mCallbackUserData); - } + mMouseDownSignal(this, LLSD()); - if (mMouseUpCallback) - { - (*mMouseUpCallback)(mCallbackUserData); - } + mMouseUpSignal(this, LLSD()); if (getSoundFlags() & MOUSE_DOWN) { @@ -259,14 +237,49 @@ void LLButton::onCommit() } // do this last, as it can result in destroying this button - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } +boost::signals::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) +{ + return mCommitSignal.connect(cb); +} +boost::signals::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) +{ + return mMouseDownSignal.connect(cb); +} +boost::signals::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb ) +{ + return mMouseUpSignal.connect(cb); +} +boost::signals::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb ) +{ + return mHeldDownSignal.connect(cb); +} +// *TODO: Deprecate (for backwards compatability only) +boost::signals::connection LLButton::setClickedCallback( button_callback_t cb, void* data ) +{ + return setClickedCallback(boost::bind(cb, data)); +} +boost::signals::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data ) +{ + return setMouseDownCallback(boost::bind(cb, data)); +} +boost::signals::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data ) +{ + return setMouseUpCallback(boost::bind(cb, data)); +} +boost::signals::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data ) +{ + return setHeldDownCallback(boost::bind(cb, data)); +} +BOOL LLButton::postBuild() +{ + autoResize(); + return TRUE; +} BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) { BOOL handled = FALSE; @@ -278,10 +291,8 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) toggleState(); } - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); + handled = TRUE; } return handled; @@ -299,10 +310,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask ) handled = TRUE; - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } return handled; } @@ -318,13 +326,11 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) setFocus(TRUE); } - if (mMouseDownCallback) - { - (*mMouseDownCallback)(mCallbackUserData); - } + mMouseDownSignal(this, LLSD()); mMouseDownTimer.start(); mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); + mMouseHeldDownCount = 0; if (getSoundFlags() & MOUSE_DOWN) { @@ -344,13 +350,9 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) gFocusMgr.setMouseCapture( NULL ); // Regardless of where mouseup occurs, handle callback - if (mMouseUpCallback) - { - (*mMouseUpCallback)(mCallbackUserData); - } + mMouseUpSignal(this, LLSD()); - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + resetMouseDownTimer(); // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. // If mouseup in the widget, it's been clicked @@ -366,10 +368,7 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) toggleState(); } - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } } @@ -377,20 +376,27 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) } -BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) +void LLButton::onMouseEnter(S32 x, S32 y, MASK mask) { - LLMouseHandler* other_captor = gFocusMgr.getMouseCapture(); - mNeedsHighlight = other_captor == NULL || - other_captor == this || - // this following bit is to support modal dialogs - (other_captor->isView() && hasAncestor((LLView*)other_captor)); + if (getEnabled()) + mNeedsHighlight = TRUE; +} - if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback) +void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mNeedsHighlight = FALSE; +} + +BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) +{ + if (mMouseDownTimer.getStarted()) { F32 elapsed = getHeldDownTime(); if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) { - mHeldDownCallback( mCallbackUserData ); + LLSD param; + param["count"] = mMouseHeldDownCount++; + mHeldDownSignal(this, param); } } @@ -406,12 +412,15 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) void LLButton::draw() { BOOL flash = FALSE; + static LLUICachedControl button_flash_rate("ButtonFlashRate", 0); + static LLUICachedControl button_flash_count("ButtonFlashCount", 0); + if( mFlashing ) { F32 elapsed = mFlashingTimer.getElapsedTimeF32(); - S32 flash_count = S32(elapsed * LLUI::sConfigGroup->getF32("ButtonFlashRate") * 2.f); + S32 flash_count = S32(elapsed * button_flash_rate * 2.f); // flash on or off? - flash = (flash_count % 2 == 0) || flash_count > S32((F32)LLUI::sConfigGroup->getS32("ButtonFlashCount") * 2.f); + flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f); } BOOL pressed_by_keyboard = FALSE; @@ -427,7 +436,7 @@ void LLButton::draw() BOOL pressed = pressed_by_keyboard || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)) - || mToggleState; + || getToggleState(); BOOL use_glow_effect = FALSE; LLColor4 glow_color = LLColor4::white; @@ -470,12 +479,14 @@ void LLButton::draw() if (mFlashing) { + LLColor4 flash_color = mFlashBgColor.get(); use_glow_effect = TRUE; glow_type = LLRender::BT_ALPHA; // blend the glow + if (mNeedsHighlight) // highlighted AND flashing - glow_color = (glow_color*0.5f + mFlashBgColor*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity + glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity else - glow_color = mFlashBgColor; + glow_color = flash_color; } // Override if more data is available @@ -508,31 +519,31 @@ void LLButton::draw() // label changes when button state changes, not when pressed if ( getEnabled() ) { - if ( mToggleState ) + if ( getToggleState() ) { - label_color = mSelectedLabelColor; + label_color = mSelectedLabelColor.get(); } else { - label_color = mUnselectedLabelColor; + label_color = mUnselectedLabelColor.get(); } } else { - if ( mToggleState ) + if ( getToggleState() ) { - label_color = mDisabledSelectedLabelColor; + label_color = mDisabledSelectedLabelColor.get(); } else { - label_color = mDisabledLabelColor; + label_color = mDisabledLabelColor.get(); } } // Unselected label assignments LLWString label; - if( mToggleState ) + if( getToggleState() ) { if( getEnabled() || mDisabledSelectedLabel.empty() ) { @@ -578,9 +589,11 @@ void LLButton::draw() // Otherwise draw basic rectangular button. if (mImagep.notNull()) { + // apply automatic 50% alpha fade to disabled image + LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get(); if ( mScaleImage) { - mImagep->draw(getLocalRect(), getEnabled() ? mImageColor : mDisabledImageColor ); + mImagep->draw(getLocalRect(), getEnabled() ? mImageColor.get() : disabled_color ); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); @@ -590,7 +603,7 @@ void LLButton::draw() } else { - mImagep->draw(0, 0, getEnabled() ? mImageColor : mDisabledImageColor ); + mImagep->draw(0, 0, getEnabled() ? mImageColor.get() : disabled_color ); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); @@ -634,7 +647,7 @@ void LLButton::draw() } // fade out overlay images on disabled buttons - LLColor4 overlay_color = mImageOverlayColor; + LLColor4 overlay_color = mImageOverlayColor.get(); if (!getEnabled()) { overlay_color.mV[VALPHA] = 0.5f; @@ -707,23 +720,18 @@ void LLButton::draw() mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset), label_color, mHAlign, LLFontGL::BOTTOM, - mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL, + LLFontGL::NORMAL, + mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, U32_MAX, text_width, NULL, FALSE, FALSE); } - if (sDebugRects - || (LLView::sEditingUI && this == LLView::sEditingUIView)) - { - drawDebugRect(); - } - - // reset hover status for next frame - mNeedsHighlight = FALSE; + LLView::draw(); } void LLButton::drawBorder(const LLColor4& color, S32 size) { + if (mImagep.isNull()) return; if (mScaleImage) { mImagep->drawBorder(getLocalRect(), color, size); @@ -734,22 +742,19 @@ void LLButton::drawBorder(const LLColor4& color, S32 size) } } -void LLButton::setClickedCallback(void (*cb)(void*), void* userdata) +BOOL LLButton::getToggleState() const { - mClickedCallback = cb; - if (userdata) - { - mCallbackUserData = userdata; - } + return getValue().asBoolean(); } - void LLButton::setToggleState(BOOL b) { - if( b != mToggleState ) + if( b != getToggleState() ) { setControlValue(b); // will fire LLControlVariable callbacks (if any) - mToggleState = b; // may or may not be redundant + setValue(b); // may or may not be redundant + // Unselected label assignments + autoResize(); } } @@ -764,19 +769,11 @@ void LLButton::setFlashing( BOOL b ) BOOL LLButton::toggleState() -{ - setToggleState( !mToggleState ); - return mToggleState; -} - -void LLButton::setValue(const LLSD& value ) { - mToggleState = value.asBoolean(); -} + bool flipped = ! getToggleState(); + setToggleState(flipped); -LLSD LLButton::getValue() const -{ - return mToggleState == TRUE; + return flipped; } void LLButton::setLabel( const LLStringExplicit& label ) @@ -818,6 +815,49 @@ void LLButton::setImageUnselected(LLPointer image) mImageUnselected = image; } +void LLButton::autoResize() +{ + LLUIString label; + if(getToggleState()) + { + if( getEnabled() || mDisabledSelectedLabel.empty() ) + { + label = mSelectedLabel; + } + else + { + label = mDisabledSelectedLabel; + } + } + else + { + if( getEnabled() || mDisabledLabel.empty() ) + { + label = mUnselectedLabel; + } + else + { + label = mDisabledLabel; + } + } + resize(label); +} + +void LLButton::resize(LLUIString label) +{ + // get label length + S32 label_width = mGLFont->getWidth(label.getString()); + // get current btn length + S32 btn_width =getRect().getWidth(); + // check if it need resize + if (mAutoResize == TRUE) + { + if (btn_width - (mRightHPad + mLeftHPad) < label_width) + { + setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight+ label_width + mLeftHPad + mRightHPad , getRect().mBottom)); + } + } +} void LLButton::setImages( const std::string &image_name, const std::string &selected_name ) { setImageUnselected(image_name); @@ -845,14 +885,20 @@ void LLButton::setImageDisabled(LLPointer image) { mImageDisabled = image; mDisabledImageColor = mImageColor; - mDisabledImageColor.mV[VALPHA] *= 0.5f; + mFadeWhenDisabled = TRUE; } void LLButton::setImageDisabledSelected(LLPointer image) { mImageDisabledSelected = image; mDisabledImageColor = mImageColor; - mDisabledImageColor.mV[VALPHA] *= 0.5f; + mFadeWhenDisabled = TRUE; +} + +void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name) +{ + setDisabledImages( image_name, selected_name, mImageColor.get()); + mFadeWhenDisabled = TRUE; } void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name, const LLColor4& c ) @@ -867,13 +913,6 @@ void LLButton::setImageHoverSelected(LLPointer 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 image) { mImageHoverUnselected = image; @@ -899,11 +938,9 @@ void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign a } } - void LLButton::onMouseCaptureLost() { - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + resetMouseDownTimer(); } //------------------------------------------------------------------------- @@ -975,28 +1012,6 @@ void LLButton::addImageAttributeToXML(LLXMLNodePtr node, } } -// virtual -LLXMLNodePtr LLButton::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("label", TRUE)->setStringValue(getLabelUnselected()); - node->createChild("label_selected", TRUE)->setStringValue(getLabelSelected()); - node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont)); - node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign)); - - addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,std::string("image_unselected")); - addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,std::string("image_selected")); - addImageAttributeToXML(node,mImageHoverSelectedName,mImageHoverSelectedID,std::string("image_hover_selected")); - addImageAttributeToXML(node,mImageHoverUnselectedName,mImageHoverUnselectedID,std::string("image_hover_unselected")); - addImageAttributeToXML(node,mImageDisabledName,mImageDisabledID,std::string("image_disabled")); - addImageAttributeToXML(node,mImageDisabledSelectedName,mImageDisabledSelectedID,std::string("image_disabled_selected")); - - node->createChild("scale_image", TRUE)->setBoolValue(mScaleImage); - - return node; -} - void clicked_help(void* data) { LLButton* self = (LLButton*)data; @@ -1010,114 +1025,53 @@ void clicked_help(void* data) LLUI::sHtmlHelp->show(self->getHelpURL()); } -// static -LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +void LLButton::setHelpURLCallback(const std::string &help_url) { - std::string name("button"); - node->getAttributeString("name", name); - - std::string label = name; - node->getAttributeString("label", label); - - std::string label_selected = label; - node->getAttributeString("label_selected", label_selected); - - LLFontGL* font = selectFont(node); - - std::string image_unselected; - if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected); - - std::string image_selected; - if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected); - - std::string image_hover_selected; - if (node->hasAttribute("image_hover_selected")) node->getAttributeString("image_hover_selected",image_hover_selected); - - std::string image_hover_unselected; - if (node->hasAttribute("image_hover_unselected")) node->getAttributeString("image_hover_unselected",image_hover_unselected); - - std::string image_disabled_selected; - if (node->hasAttribute("image_disabled_selected")) node->getAttributeString("image_disabled_selected",image_disabled_selected); - - std::string image_disabled; - if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled); - - std::string image_overlay; - node->getAttributeString("image_overlay", image_overlay); - - LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER; - std::string image_overlay_alignment_string; - if (node->hasAttribute("image_overlay_alignment")) - { - node->getAttributeString("image_overlay_alignment", image_overlay_alignment_string); - image_overlay_alignment = LLFontGL::hAlignFromName(image_overlay_alignment_string); - } - - - LLButton *button = new LLButton(name, - LLRect(), - image_unselected, - image_selected, - LLStringUtil::null, - NULL, - parent, - font, - label, - label_selected); - - node->getAttributeS32("pad_right", button->mRightHPad); - node->getAttributeS32("pad_left", button->mLeftHPad); + mHelpURL = help_url; + setClickedCallback(clicked_help,this); +} - BOOL is_toggle = button->getIsToggle(); - node->getAttributeBOOL("toggle", is_toggle); - button->setIsToggle(is_toggle); +// static +void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname) +{ + bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString()); + LLButton* button = dynamic_cast(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(ctrl); + if (!button) + return; + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) + button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); + // Set the clicked callback to toggle the floater + button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname)); +} - if (node->hasAttribute("halign")) - { - LLFontGL::HAlign halign = selectFontHAlign(node); - button->setHAlign(halign); - } +void LLButton::resetMouseDownTimer() +{ + mMouseDownTimer.stop(); + mMouseDownTimer.reset(); +} - if (node->hasAttribute("scale_image")) - { - BOOL needsScale = FALSE; - node->getAttributeBOOL("scale_image",needsScale); - button->setScaleImage( needsScale ); - } - if(label.empty()) - { - button->setLabelUnselected(node->getTextContents()); - } - if (label_selected.empty()) - { - button->setLabelSelected(node->getTextContents()); - } - - if (node->hasAttribute("help_url")) +// *TODO: Remove this function after the initial XUI XML re-export pass. +// static +void LLButton::setupParamsForExport(Params& p, LLView* parent) +{ + std::string label = p.label; + if (label.empty()) { - std::string help_url; - node->getAttributeString("help_url",help_url); - button->setHelpURLCallback(help_url); + //if our label is empty this is a picture style button + p.picture_style = true; } - button->initFromXML(node, parent); - - return button; -} - -void LLButton::setHelpURLCallback(const std::string &help_url) -{ - mHelpURL = help_url; - setClickedCallback(clicked_help,this); + LLUICtrl::setupParamsForExport(p, parent); } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 724b77541a..f146ef9dc2 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -39,7 +39,7 @@ #include "v4color.h" #include "llframetimer.h" #include "llfontgl.h" -#include "llimage.h" +#include "lluiimage.h" #include "lluistring.h" // @@ -53,9 +53,6 @@ extern S32 LLBUTTON_V_PAD; extern S32 BTN_HEIGHT_SMALL; extern S32 BTN_HEIGHT; -// All button widths should be rounded up to this size -extern S32 BTN_GRID; - // // Helpful functions // @@ -72,36 +69,80 @@ class LLButton : public LLUICtrl { public: - // simple button with text label - LLButton(const std::string& name, const LLRect &rect, const std::string& control_name = std::string(), - void (*on_click)(void*) = NULL, void *data = NULL); - - LLButton(const std::string& name, const LLRect& rect, - const std::string &unselected_image, - const std::string &selected_image, - const std::string& control_name, - void (*click_callback)(void*), - void *callback_data = NULL, - const LLFontGL* mGLFont = NULL, - const std::string& unselected_label = LLStringUtil::null, - const std::string& selected_label = LLStringUtil::null ); - - virtual ~LLButton(); - void init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name); - + struct Params + : public LLInitParam::Block + { + // text label + Optional label_selected; + Optional label_dropshadow; + Optional auto_resize; + + // images + Optional image_unselected, + image_selected, + image_hover_selected, + image_hover_unselected, + image_disabled_selected, + image_disabled, + image_overlay; + + Optional image_overlay_alignment; + + // colors + Optional 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 pad_right; + Optional pad_left; + + // callbacks + Optional click_callback, // alias -> commit_callback + mouse_down_callback, + mouse_up_callback, + mouse_held_callback, + mouse_held_once_callback; + + // misc + Optional is_toggle, + scale_image, + commit_on_return, + picture_style; //if true, don't display label + + Optional help_url; + Optional hover_glow_amount; + Optional held_down_delay; + + Params(); + }; +protected: + friend class LLUICtrlFactory; + LLButton(const Params&); + +public: + // For backward compatability only + typedef boost::function button_callback_t; + void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, const LLUUID& imageID,const std::string& xmlTagName) const; - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual void draw(); + /*virtual*/ BOOL postBuild(); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); virtual void onMouseCaptureLost(); virtual void onCommit(); @@ -109,18 +150,24 @@ public: void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } - void setClickedCallback( void (*cb)(void *data), void* data = NULL ); // mouse down and up within button - void setMouseDownCallback( void (*cb)(void *data) ) { mMouseDownCallback = cb; } // mouse down within button - void setMouseUpCallback( void (*cb)(void *data) ) { mMouseUpCallback = cb; } // mouse up, EVEN IF NOT IN BUTTON - void setHeldDownCallback( void (*cb)(void *data) ) { mHeldDownCallback = cb; } // Mouse button held down and in button + boost::signals::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button + boost::signals::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON + // Passes a 'count' parameter in the commit param payload, i.e. param["count"]) + boost::signals::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button + + // *TODO: Deprecate (for backwards compatability only) + boost::signals::connection setClickedCallback( button_callback_t cb, void* data ); + boost::signals::connection setMouseDownCallback( button_callback_t cb, void* data ); + boost::signals::connection setMouseUpCallback( button_callback_t cb, void* data ); + boost::signals::connection setHeldDownCallback( button_callback_t cb, void* data ); + void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; } - + F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); } - BOOL getIsToggle() const { return mIsToggle; } - void setIsToggle(BOOL is_toggle) { mIsToggle = is_toggle; } BOOL toggleState(); - BOOL getToggleState() const { return mToggleState; } + BOOL getToggleState() const; void setToggleState(BOOL b); void setFlashing( BOOL b ); @@ -150,11 +197,9 @@ public: void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); LLPointer getImageOverlay() { return mImageOverlay; } - - - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; + void autoResize(); // resize with label of current btn state + void resize(LLUIString label); // resize with label input void setLabel( const LLStringExplicit& label); virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); void setLabelUnselected(const LLStringExplicit& label); @@ -172,8 +217,6 @@ public: void setBorderEnabled(BOOL b) { mBorderEnabled = b; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks - void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; } void setImageUnselected(const std::string &image_name); @@ -198,6 +241,10 @@ public: void setHelpURLCallback(const std::string &help_url); const std::string& getHelpURL() const { return mHelpURL; } + static void onHeldDown(void *userdata); // to be called by gIdleCallbacks + static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); + static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); + protected: virtual void drawBorder(const LLColor4& color, S32 size); @@ -212,45 +259,48 @@ protected: void setImageDisabledSelectedID(const LLUUID &image_id); const LLPointer& getImageUnselected() const { return mImageUnselected; } const LLPointer& 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 mImageOverlay; - LLFontGL::HAlign mImageOverlayAlignment; - LLColor4 mImageOverlayColor; + LLPointer mImageOverlay; + LLFontGL::HAlign mImageOverlayAlignment; + LLUIColor mImageOverlayColor; - LLPointer mImageUnselected; - LLUIString mUnselectedLabel; - LLColor4 mUnselectedLabelColor; + LLPointer mImageUnselected; + LLUIString mUnselectedLabel; + LLUIColor mUnselectedLabelColor; - LLPointer mImageSelected; - LLUIString mSelectedLabel; - LLColor4 mSelectedLabelColor; + LLPointer mImageSelected; + LLUIString mSelectedLabel; + LLUIColor mSelectedLabelColor; - LLPointer mImageHoverSelected; + LLPointer mImageHoverSelected; - LLPointer mImageHoverUnselected; + LLPointer mImageHoverUnselected; - LLPointer mImageDisabled; - LLUIString mDisabledLabel; - LLColor4 mDisabledLabelColor; + LLPointer mImageDisabled; + LLUIString mDisabledLabel; + LLUIColor mDisabledLabelColor; - LLPointer mImageDisabledSelected; - LLUIString mDisabledSelectedLabel; - LLColor4 mDisabledSelectedLabelColor; + LLPointer mImageDisabledSelected; + LLUIString mDisabledSelectedLabel; + LLUIColor mDisabledSelectedLabelColor; LLUUID mImageUnselectedID; LLUUID mImageSelectedID; @@ -265,20 +315,17 @@ private: std::string mImageDisabledName; std::string mImageDisabledSelectedName; - LLColor4 mHighlightColor; - LLColor4 mUnselectedBgColor; - LLColor4 mSelectedBgColor; - LLColor4 mFlashBgColor; + LLUIColor mHighlightColor; + LLUIColor mFlashBgColor; - LLColor4 mImageColor; - LLColor4 mDisabledImageColor; + LLUIColor mImageColor; + LLUIColor mDisabledImageColor; BOOL mIsToggle; - BOOL mToggleState; BOOL mScaleImage; BOOL mDropShadowedText; - + BOOL mAutoResize; BOOL mBorderEnabled; BOOL mFlashing; @@ -292,6 +339,7 @@ private: BOOL mNeedsHighlight; BOOL mCommitOnReturn; + BOOL mFadeWhenDisabled; std::string mHelpURL; @@ -300,4 +348,11 @@ private: LLFrameTimer mFlashingTimer; }; +#ifdef LL_WINDOWS +#ifndef INSTANTIATE_GETCHILD_BUTTON +#pragma warning (disable : 4231) +extern template LLButton* LLView::getChild( 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 -#include "llstring.h" +#include class LLCallbackMap { @@ -45,12 +45,19 @@ public: typedef std::map map_t; typedef map_t::iterator map_iter_t; typedef map_t::const_iterator map_const_iter_t; - + + template + static void* buildPanel(void* data) + { + T* panel = new T(); + return (void*)panel; + } + LLCallbackMap() : mCallback(NULL), mData(NULL) { } - LLCallbackMap(callback_t callback, void* data) : mCallback(callback), mData(data) { } + LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { } callback_t mCallback; void* mData; }; -#endif // LL_CALLBACK_MAP_H +#endif // LLCALLBACKMAP_H diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index eda9467d87..7b37344db7 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -31,6 +31,7 @@ */ // The mutants are coming! +#define INSTANTIATE_GETCHILD_CHECKBOX #include "linden_common.h" @@ -49,101 +50,88 @@ const U32 MAX_STRING_LENGTH = 10; +template LLCheckBoxCtrl* LLView::getChild( const std::string& name, BOOL recurse, BOOL create_if_missing ) const; + static LLRegisterWidget r("check_box"); - -LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect, - const std::string& label, - const LLFontGL* font, - void (*commit_callback)(LLUICtrl* ctrl, void* userdata), - void* callback_user_data, - BOOL initial_value, - BOOL use_radio_style, - const std::string& control_which) -: LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data, FOLLOWS_LEFT | FOLLOWS_TOP), - mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), - mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), - mRadioStyle( use_radio_style ), - mInitialValue( initial_value ), - mSetValue( initial_value ) +LLCheckBoxCtrl::Params::Params() +: text_enabled_color("text_enabled_color"), + text_disabled_color("text_disabled_color"), + initial_value("initial_value", false), + label_text("label_text"), + check_button("check_button"), + radio_style("radio_style") +{} + + +LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) +: LLUICtrl(p), + mTextEnabledColor(p.text_enabled_color()), + mTextDisabledColor(p.text_disabled_color()), + mFont(p.font()) { - if (font) - { - mFont = font; - } - else - { - mFont = LLFontGL::getFontSansSerifSmall(); - } + mViewModel->setValue(LLSD(p.initial_value)); + mViewModel->resetDirty(); + static LLUICachedControl llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); + static LLUICachedControl llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); + static LLUICachedControl llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); + static LLUICachedControl 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 (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(params); addChild(mButton); } @@ -154,24 +142,14 @@ LLCheckBoxCtrl::~LLCheckBoxCtrl() // static -void LLCheckBoxCtrl::onButtonPress( void *userdata ) +void LLCheckBoxCtrl::onButtonPress( const LLSD& data ) { - LLCheckBoxCtrl* self = (LLCheckBoxCtrl*) userdata; + //if (mRadioStyle) + //{ + // setValue(TRUE); + //} - if (self->mRadioStyle) - { - self->setValue(TRUE); - } - - self->setControlValue(self->getValue()); - // HACK: because buttons don't normally commit - self->onCommit(); - - if (self->mKeyboardFocusOnClick) - { - self->setFocus( TRUE ); - self->onFocusReceived(); - } + onCommit(); } void LLCheckBoxCtrl::onCommit() @@ -179,6 +157,7 @@ void LLCheckBoxCtrl::onCommit() if( getEnabled() ) { setTentative(FALSE); + setControlValue(getValue()); LLUICtrl::onCommit(); } } @@ -187,6 +166,15 @@ void LLCheckBoxCtrl::setEnabled(BOOL b) { LLView::setEnabled(b); mButton->setEnabled(b); + + if (b) + { + mLabel->setColor( mTextEnabledColor.get() ); + } + else + { + mLabel->setColor( mTextDisabledColor.get() ); + } } void LLCheckBoxCtrl::clear() @@ -197,43 +185,33 @@ void LLCheckBoxCtrl::clear() void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) { //stretch or shrink bounding rectangle of label when rebuilding UI at new scale + static LLUICachedControl llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); + static LLUICachedControl llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); + static LLUICachedControl llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); + static LLUICachedControl llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); + const S32 FUDGE = 10; S32 text_width = mFont->getWidth( mLabel->getText() ) + FUDGE; S32 text_height = llround(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( - LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING, - LLCHECKBOXCTRL_VPAD, + llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, + llcheckboxctrl_vpad, text_width, text_height ); mLabel->setRect(label_rect); LLRect btn_rect; btn_rect.setOriginAndSize( - LLCHECKBOXCTRL_HPAD, - LLCHECKBOXCTRL_VPAD, - LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING + text_width, - llmax( text_height, LLCHECKBOXCTRL_BTN_SIZE ) ); + llcheckboxctrl_hpad, + llcheckboxctrl_vpad, + llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width, + llmax( text_height, llcheckboxctrl_btn_size() ) ); mButton->setRect( btn_rect ); LLUICtrl::reshape(width, height, called_from_parent); } -void LLCheckBoxCtrl::draw() -{ - if (getEnabled()) - { - mLabel->setColor( mTextEnabledColor ); - } - else - { - mLabel->setColor( mTextDisabledColor ); - } - - // Draw children - LLUICtrl::draw(); -} - //virtual void LLCheckBoxCtrl::setValue(const LLSD& value ) { @@ -246,6 +224,18 @@ LLSD LLCheckBoxCtrl::getValue() const return mButton->getValue(); } +//virtual +void LLCheckBoxCtrl::setTentative(BOOL b) +{ + mButton->setTentative(b); +} + +//virtual +BOOL LLCheckBoxCtrl::getTentative() const +{ + return mButton->getTentative(); +} + void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label ) { mLabel->setText( label ); @@ -264,12 +254,6 @@ BOOL LLCheckBoxCtrl::setLabelArg( const std::string& key, const LLStringExplicit return res; } -//virtual -std::string LLCheckBoxCtrl::getControlName() const -{ - return mButton->getControlName(); -} - // virtual void LLCheckBoxCtrl::setControlName(const std::string& control_name, LLView* context) { @@ -282,7 +266,7 @@ BOOL LLCheckBoxCtrl::isDirty() const { if ( mButton ) { - return (mSetValue != mButton->getToggleState()); + return mButton->isDirty(); } return FALSE; // Shouldn't get here } @@ -293,78 +277,6 @@ void LLCheckBoxCtrl::resetDirty() { if ( mButton ) { - mSetValue = mButton->getToggleState(); - } -} - - - -// virtual -LLXMLNodePtr LLCheckBoxCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("label", TRUE)->setStringValue(mLabel->getText()); - - std::string control_name = mButton->getControlName(); - - node->createChild("initial_value", TRUE)->setBoolValue(mInitialValue); - - node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mFont)); - - node->createChild("radio_style", TRUE)->setBoolValue(mRadioStyle); - - return node; -} - -// static -LLView* LLCheckBoxCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("checkbox"); - node->getAttributeString("name", name); - - std::string label(""); - node->getAttributeString("label", label); - - LLFontGL* font = LLView::selectFont(node); - - BOOL radio_style = FALSE; - node->getAttributeBOOL("radio_style", radio_style); - - LLUICtrlCallback callback = NULL; - - if (label.empty()) - { - label.assign(node->getTextContents()); + mButton->resetDirty(); } - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - LLCheckBoxCtrl* checkbox = new LLCheckboxCtrl(name, - rect, - label, - font, - callback, - NULL, - FALSE, - radio_style); // if true, draw radio button style icons - - BOOL initial_value = checkbox->getValue().asBoolean(); - node->getAttributeBOOL("initial_value", initial_value); - - LLColor4 color; - color = LLUI::sColorsGroup->getColor( "LabelTextColor" ); - LLUICtrlFactory::getAttributeColor(node,"text_enabled_color", color); - checkbox->setEnabledColor(color); - - color = LLUI::sColorsGroup->getColor( "LabelDisabledColor" ); - LLUICtrlFactory::getAttributeColor(node,"text_disabled_color", color); - checkbox->setDisabledColor(color); - - checkbox->setValue(initial_value); - - checkbox->initFromXML(node, parent); - - return checkbox; } diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index ff867f5193..fe719e3b6a 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -33,24 +33,14 @@ #ifndef LL_LLCHECKBOXCTRL_H #define LL_LLCHECKBOXCTRL_H - -#include "stdtypes.h" #include "lluictrl.h" #include "llbutton.h" +#include "lltextbox.h" #include "v4color.h" -#include "llrect.h" // // Constants // -const S32 LLCHECKBOXCTRL_BTN_SIZE = 13; -const S32 LLCHECKBOXCTRL_VPAD = 2; -const S32 LLCHECKBOXCTRL_HPAD = 2; -const S32 LLCHECKBOXCTRL_SPACING = 5; -const S32 LLCHECKBOXCTRL_HEIGHT = 16; - -// Deprecated, don't use. -#define CHECKBOXCTRL_HEIGHT LLCHECKBOXCTRL_HEIGHT const BOOL RADIO_STYLE = TRUE; const BOOL CHECK_STYLE = FALSE; @@ -59,30 +49,38 @@ const BOOL CHECK_STYLE = FALSE; // Classes // class LLFontGL; -class LLTextBox; class LLViewBorder; class LLCheckBoxCtrl : public LLUICtrl { public: - LLCheckBoxCtrl(const std::string& name, const LLRect& rect, const std::string& label, - const LLFontGL* font = NULL, - void (*commit_callback)(LLUICtrl*, void*) = NULL, - void* callback_userdata = NULL, - BOOL initial_value = FALSE, - BOOL use_radio_style = FALSE, // if true, draw radio button style icons - const std::string& control_which = LLStringUtil::null); + struct Params + : public LLInitParam::Block + { + Optional text_enabled_color; + Optional text_disabled_color; + Optional initial_value; // override LLUICtrl initial_value + + Optional label_text; + Optional check_button; + + Deprecated radio_style; + + Params(); + }; + virtual ~LLCheckBoxCtrl(); - // LLView interface +protected: + LLCheckBoxCtrl(const Params&); + friend class LLUICtrlFactory; - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); +public: + // LLView interface virtual void setEnabled( BOOL b ); - virtual void draw(); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); // LLUICtrl interface @@ -91,8 +89,8 @@ public: BOOL get() { return (BOOL)getValue().asBoolean(); } void set(BOOL value) { setValue(value); } - virtual void setTentative(BOOL b) { mButton->setTentative(b); } - virtual BOOL getTentative() const { return mButton->getTentative(); } + virtual void setTentative(BOOL b); + virtual BOOL getTentative() const; virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); @@ -108,10 +106,11 @@ public: void setLabel( const LLStringExplicit& label ); std::string getLabel() const; + void setFont( const LLFontGL* font ) { mFont = font; } + virtual void setControlName(const std::string& control_name, LLView* context); - virtual std::string getControlName() const; - static void onButtonPress(void *userdata); + void onButtonPress(const LLSD& data); virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. virtual void resetDirty(); // Clear dirty state @@ -121,19 +120,17 @@ protected: LLButton* mButton; LLTextBox* mLabel; const LLFontGL* mFont; - LLColor4 mTextEnabledColor; - LLColor4 mTextDisabledColor; - BOOL mRadioStyle; - BOOL mInitialValue; // Value set in constructor - BOOL mSetValue; // Value set programmatically - BOOL mKeyboardFocusOnClick; - LLViewBorder* mBorder; -}; + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; +}; -// HACK: fix old capitalization problem -//typedef LLCheckBoxCtrl LLCheckboxCtrl; -#define LLCheckboxCtrl LLCheckBoxCtrl +#ifdef LL_WINDOWS +#ifndef INSTANTIATE_GETCHILD_CHECKBOX +#pragma warning (disable : 4231) +extern template LLCheckBoxCtrl* LLView::getChild( const std::string& name, BOOL recurse, BOOL create_if_missing ) const; +#endif +#endif #endif // LL_LLCHECKBOXCTRL_H diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 28a05c13f5..09f7a6c813 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -33,6 +33,8 @@ // A control that displays the name of the chosen item, which when // clicked shows a scrolling box of options. +#define INSTANTIATE_GETCHILD_COMBOBOX + #include "linden_common.h" // file includes @@ -48,167 +50,128 @@ #include "llwindow.h" #include "llfloater.h" #include "llscrollbar.h" +#include "llscrolllistcell.h" +#include "llscrolllistitem.h" #include "llcontrol.h" #include "llfocusmgr.h" #include "lllineeditor.h" #include "v2math.h" +#include "lluictrlfactory.h" // Globals S32 LLCOMBOBOX_HEIGHT = 0; S32 LLCOMBOBOX_WIDTH = 0; S32 MAX_COMBO_WIDTH = 500; -static LLRegisterWidget r1("combo_box"); +template LLComboBox* LLView::getChild( const std::string& name, BOOL recurse, BOOL create_if_missing ) const; -LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std::string& label, - void (*commit_callback)(LLUICtrl*,void*), - void *callback_userdata - ) -: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata, - FOLLOWS_LEFT | FOLLOWS_TOP), - mTextEntry(NULL), - mArrowImage(NULL), - mAllowTextEntry(FALSE), - mMaxChars(20), - mTextEntryTentative(TRUE), - mListPosition(BELOW), - mPrearrangeCallback( NULL ), - mTextEntryCallback( NULL ), - mLabel(label) -{ - // Always use text box - // Text label button - mButton = new LLButton(mLabel, - LLRect(), - LLStringUtil::null, - NULL, this); - mButton->setImageUnselected(std::string("square_btn_32x128.tga")); - mButton->setImageSelected(std::string("square_btn_selected_32x128.tga")); - mButton->setImageDisabled(std::string("square_btn_32x128.tga")); - mButton->setImageDisabledSelected(std::string("square_btn_selected_32x128.tga")); - mButton->setScaleImage(TRUE); - - mButton->setMouseDownCallback(onButtonDown); - mButton->setFont(LLFontGL::getFontSansSerifSmall()); - mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); - mButton->setHAlign( LLFontGL::LEFT ); - mButton->setRightHPad(2); - addChild(mButton); +static LLRegisterWidget register_combo_box("combo_box"); - // disallow multiple selection - mList = new LLScrollListCtrl(std::string("ComboBox"), LLRect(), - &LLComboBox::onItemSelected, this, FALSE); - mList->setVisible(FALSE); - mList->setBgWriteableColor( LLColor4(1,1,1,1) ); - mList->setCommitOnKeyboardMovement(FALSE); - addChild(mList); - - mArrowImage = LLUI::sImageProvider->getUIImage("combobox_arrow.tga"); - mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT); +void LLComboBox::PreferredPositionValues::declareValues() +{ + declare("above", ABOVE); + declare("below", BELOW); +} - updateLayout(); +LLComboBox::ItemParams::ItemParams() +: label("label") +{ } -LLComboBox::~LLComboBox() +LLComboBox::Params::Params() +: allow_text_entry("allow_text_entry", false), + show_text_as_tentative("show_text_as_tentative", true), + max_chars("max_chars", 20), + arrow_image("arrow_image"), + list_position("list_position", BELOW), + items("item"), + combo_button("combo_button"), + combo_list("combo_list"), + combo_editor("combo_editor") { - // children automatically deleted, including mMenu, mButton + addSynonym(items, "combo_item"); } -// virtual -LLXMLNodePtr LLComboBox::getXML(bool save_children) const + +LLComboBox::LLComboBox(const LLComboBox::Params& p) +: LLUICtrl(p), + mTextEntry(NULL), + mTextEntryTentative(p.show_text_as_tentative), + mAllowTextEntry(p.allow_text_entry), + mMaxChars(p.max_chars), + mPrearrangeCallback(p.prearrange_callback()), + mTextEntryCallback(p.text_entry_callback()), + mSelectionCallback(p.selection_callback()), + mArrowImage(p.arrow_image), + mListPosition(p.list_position) { - LLXMLNodePtr node = LLUICtrl::getXML(); + // Text label button - // Attributes + LLButton::Params button_params = p.combo_button; + button_params.mouse_down_callback.function(boost::bind(&LLComboBox::onButtonDown, this)); + button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT); + button_params.rect(p.rect); + button_params.pad_right(2); - node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry); + mButton = LLUICtrlFactory::create(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(params); + addChild(mList); - std::vector data_list = mList->getAllData(); - std::vector::iterator data_itor; - for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor) + for (LLInitParam::ParamIterator::const_iterator it = p.items().begin(); + it != p.items().end(); + ++it) { - LLScrollListItem* item = *data_itor; - LLScrollListCell* cell = item->getColumn(0); - if (cell) + LLScrollListItem::Params item_params = *it; + if (it->label.isProvided()) { - LLXMLNodePtr item_node = node->createChild("combo_item", FALSE); - LLSD value = item->getValue(); - item_node->createChild("value", TRUE)->setStringValue(value.asString()); - item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled()); - item_node->setStringValue(cell->getValue().asString()); + item_params.cells.add().value(it->label()); } + + mList->addRow(item_params); } - return node; + createLineEditor(p); + + setTopLostCallback(boost::bind(&LLComboBox::hideList, this)); } -// static -LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +void LLComboBox::initFromParams(const LLComboBox::Params& p) { - std::string name("combo_box"); - node->getAttributeString("name", name); - - std::string label(""); - node->getAttributeString("label", label); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - BOOL allow_text_entry = FALSE; - node->getAttributeBOOL("allow_text_entry", allow_text_entry); - - S32 max_chars = 20; - node->getAttributeS32("max_chars", max_chars); - - LLUICtrlCallback callback = NULL; - - LLComboBox* combo_box = new LLComboBox(name, - rect, - label, - callback, - NULL); - combo_box->setAllowTextEntry(allow_text_entry, max_chars); + LLUICtrl::initFromParams(p); - combo_box->initFromXML(node, parent); - - const std::string& contents = node->getValue(); - - if (contents.find_first_not_of(" \n\t") != contents.npos) - { - llerrs << "Legacy combo box item format used! Please convert to tags!" << llendl; - } - else + if (!acceptsTextInput() && mLabel.empty()) { - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("combo_item")) - { - std::string label = child->getTextContents(); - - std::string value = label; - child->getAttributeString("value", value); - - combo_box->add(label, LLSD(value) ); - } - } + selectFirstItem(); } +} - // if providing user text entry or descriptive label - // don't select an item under the hood - if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty()) +// virtual +BOOL LLComboBox::postBuild() +{ + if (mControlVariable) { - combo_box->selectFirstItem(); + setValue(mControlVariable->getValue()); // selects the appropriate item } + return TRUE; +} + - return combo_box; +LLComboBox::~LLComboBox() +{ + // children automatically deleted, including mMenu, mButton } + void LLComboBox::setEnabled(BOOL enabled) { LLView::setEnabled(enabled); @@ -237,6 +200,7 @@ void LLComboBox::onCommit() mTextEntry->setValue(getSimple()); mTextEntry->setTentative(FALSE); } + setControlValue(getValue()); LLUICtrl::onCommit(); } @@ -431,6 +395,7 @@ BOOL LLComboBox::remove(S32 index) if (index < mList->getItemCount()) { mList->deleteSingleItem(index); + setLabel(mList->getSelectedItemLabel()); return TRUE; } return FALSE; @@ -448,21 +413,17 @@ void LLComboBox::onFocusLost() LLUICtrl::onFocusLost(); } -void LLComboBox::onLostTop() -{ - hideList(); -} - - void LLComboBox::setButtonVisible(BOOL visible) { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); + mButton->setVisible(visible); if (mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); if (visible) { - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * drop_shadow_button; } //mTextEntry->setRect(text_entry_rect); mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); @@ -498,54 +459,48 @@ S32 LLComboBox::getCurrentIndex() const } -void LLComboBox::updateLayout() +void LLComboBox::createLineEditor(const LLComboBox::Params& p) { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); LLRect rect = getLocalRect(); if (mAllowTextEntry) { - S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton"); + S32 shadow_size = drop_shadow_button; mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); mButton->setTabStop(FALSE); + mButton->setHAlign(LLFontGL::HCENTER); - if (!mTextEntry) - { - LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); - // clear label on button - std::string cur_label = mButton->getLabelSelected(); - mTextEntry = new LLLineEditor(std::string("combo_text_entry"), - text_entry_rect, - LLStringUtil::null, - LLFontGL::getFontSansSerifSmall(), - mMaxChars, - onTextCommit, - onTextEntry, - NULL, - this); - mTextEntry->setSelectAllonFocusReceived(TRUE); - mTextEntry->setHandleEditKeysDirectly(TRUE); - mTextEntry->setCommitOnFocusLost(FALSE); - mTextEntry->setText(cur_label); - mTextEntry->setIgnoreTab(TRUE); - mTextEntry->setFollowsAll(); - addChild(mTextEntry); - } - else - { - mTextEntry->setVisible(TRUE); - mTextEntry->setMaxTextLength(mMaxChars); - } + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * drop_shadow_button; + // clear label on button + std::string cur_label = mButton->getLabelSelected(); + LLLineEditor::Params params = p.combo_editor; + params.rect(text_entry_rect); + params.default_text(LLStringUtil::null); + params.max_length_bytes(mMaxChars); + params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); + params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); + params.focus_lost_callback(NULL); + params.select_on_focus(true); + params.handle_edit_keys_directly(true); + params.commit_on_focus_lost(false); + params.follows.flags(FOLLOWS_ALL); + mTextEntry = LLUICtrlFactory::create (params); + mTextEntry->setText(cur_label); + mTextEntry->setIgnoreTab(TRUE); + addChild(mTextEntry); // clear label on button setLabel(LLStringUtil::null); mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT); } - else if (!mAllowTextEntry) + else { mButton->setRect(rect); mButton->setTabStop(TRUE); + mButton->setHAlign(LLFontGL::LEFT); if (mTextEntry) { @@ -672,7 +627,7 @@ void LLComboBox::hideList() mButton->setToggleState(FALSE); mList->setVisible(FALSE); - mList->highlightNthItem(-1); + mList->mouseOverHighlightNthItem(-1); setUseBoundingRect(FALSE); if( gFocusMgr.getTopCtrl() == this ) @@ -681,74 +636,74 @@ void LLComboBox::hideList() } } -//------------------------------------------------------------------ -// static functions -//------------------------------------------------------------------ - -// static -void LLComboBox::onButtonDown(void *userdata) +void LLComboBox::onButtonDown() { - LLComboBox *self = (LLComboBox *)userdata; - - if (!self->mList->getVisible()) + if (!mList->getVisible()) { - LLScrollListItem* last_selected_item = self->mList->getLastSelectedItem(); + LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); if (last_selected_item) { // highlight the original selection before potentially selecting a new item - self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item)); + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); } - if( self->mPrearrangeCallback ) + if( mPrearrangeCallback ) { - self->mPrearrangeCallback( self, self->mCallbackUserData ); + mPrearrangeCallback( this, LLSD() ); } - if (self->mList->getItemCount() != 0) + if (mList->getItemCount() != 0) { - self->showList(); + showList(); } - self->setFocus( TRUE ); + setFocus( TRUE ); // pass mouse capture on to list if button is depressed - if (self->mButton->hasMouseCapture()) + if (mButton->hasMouseCapture()) { - gFocusMgr.setMouseCapture(self->mList); + gFocusMgr.setMouseCapture(mList); } } else { - self->hideList(); + hideList(); } } -// static -void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata) -{ - // Note: item is the LLScrollListCtrl - LLComboBox *self = (LLComboBox *) userdata; - const std::string name = self->mList->getSelectedItemLabel(); +//------------------------------------------------------------------ +// static functions +//------------------------------------------------------------------ - S32 cur_id = self->getCurrentIndex(); +void LLComboBox::onItemSelected(const LLSD& data) +{ + const std::string name = mList->getSelectedItemLabel(); + + S32 cur_id = getCurrentIndex(); if (cur_id != -1) { - self->setLabel(name); + setLabel(name); - if (self->mAllowTextEntry) + if (mAllowTextEntry) { - gFocusMgr.setKeyboardFocus(self->mTextEntry); - self->mTextEntry->selectAll(); + gFocusMgr.setKeyboardFocus(mTextEntry); + mTextEntry->selectAll(); } } // hiding the list reasserts the old value stored in the text editor/dropdown button - self->hideList(); + hideList(); // commit does the reverse, asserting the value in the list - self->onCommit(); + onCommit(); + + // call the callback if it exists + if(mSelectionCallback) + { + mSelectionCallback(this, data); + } } BOOL LLComboBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) @@ -804,7 +759,7 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask) if (last_selected_item) { // highlight the original selection before potentially selecting a new item - mList->highlightNthItem(mList->getItemIndex(last_selected_item)); + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); } result = mList->handleKeyHere(key, mask); @@ -838,7 +793,7 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) if (last_selected_item) { // highlight the original selection before potentially selecting a new item - mList->highlightNthItem(mList->getItemIndex(last_selected_item)); + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); } result = mList->handleUnicodeCharHere(uni_char); if (mList->getLastSelectedItem() != last_selected_item) @@ -850,15 +805,6 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) return result; } -void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative) -{ - mAllowTextEntry = allow; - mTextEntryTentative = set_tentative; - mMaxChars = max_chars; - - updateLayout(); -} - void LLComboBox::setTextEntry(const LLStringExplicit& text) { if (mTextEntry) @@ -868,28 +814,25 @@ void LLComboBox::setTextEntry(const LLStringExplicit& text) } } -//static -void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) +void LLComboBox::onTextEntry(LLLineEditor* line_editor) { - LLComboBox* self = (LLComboBox*)user_data; - - if (self->mTextEntryCallback) + if (mTextEntryCallback != NULL) { - (*self->mTextEntryCallback)(line_editor, self->mCallbackUserData); + (mTextEntryCallback)(line_editor, LLSD()); } KEY key = gKeyboard->currentKey(); if (key == KEY_BACKSPACE || key == KEY_DELETE) { - if (self->mList->selectItemByLabel(line_editor->getText(), FALSE)) + if (mList->selectItemByLabel(line_editor->getText(), FALSE)) { line_editor->setTentative(FALSE); } else { - line_editor->setTentative(self->mTextEntryTentative); - self->mList->deselectAllItems(); + line_editor->setTentative(mTextEntryTentative); + mList->deselectAllItems(); } return; } @@ -902,17 +845,17 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) if (key == KEY_DOWN) { - self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1)); - if (!self->mList->getVisible()) + setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1)); + if (!mList->getVisible()) { - if( self->mPrearrangeCallback ) + if( mPrearrangeCallback ) { - self->mPrearrangeCallback( self, self->mCallbackUserData ); + mPrearrangeCallback( this, LLSD() ); } - if (self->mList->getItemCount() != 0) + if (mList->getItemCount() != 0) { - self->showList(); + showList(); } } line_editor->selectAll(); @@ -920,17 +863,17 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) } else if (key == KEY_UP) { - self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1)); - if (!self->mList->getVisible()) + setCurrentByIndex(llmax(0, getCurrentIndex() - 1)); + if (!mList->getVisible()) { - if( self->mPrearrangeCallback ) + if( mPrearrangeCallback ) { - self->mPrearrangeCallback( self, self->mCallbackUserData ); + mPrearrangeCallback( this, LLSD() ); } - if (self->mList->getItemCount() != 0) + if (mList->getItemCount() != 0) { - self->showList(); + showList(); } } line_editor->selectAll(); @@ -939,7 +882,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) else { // RN: presumably text entry - self->updateSelection(); + updateSelection(); } } @@ -958,7 +901,7 @@ void LLComboBox::updateSelection() { if (mPrearrangeCallback) { - mPrearrangeCallback( this, mCallbackUserData ); + mPrearrangeCallback( this, LLSD() ); } } @@ -983,14 +926,12 @@ void LLComboBox::updateSelection() } } -//static -void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data) +void LLComboBox::onTextCommit(const LLSD& data) { - LLComboBox* self = (LLComboBox*)user_data; - std::string text = self->mTextEntry->getText(); - self->setSimple(text); - self->onCommit(); - self->mTextEntry->selectAll(); + std::string text = mTextEntry->getText(); + setSimple(text); + onCommit(); + mTextEntry->selectAll(); } void LLComboBox::setFocus(BOOL b) @@ -1114,155 +1055,3 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last ) { return mList->selectItemRange(first, last); } - - -// -// LLFlyoutButton -// - -static LLRegisterWidget 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(NULL)); - - mButton->setImageSelected(mExpanderButtonImageSelected); - mButton->setImageUnselected(mExpanderButtonImage); - mButton->setImageDisabled(mExpanderButtonImageDisabled); - mButton->setImageDisabledSelected(LLPointer(NULL)); - mButton->setRightHPad(6); - - updateLayout(); -} - -//static -LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name = "flyout_button"; - node->getAttributeString("name", name); - - std::string label(""); - node->getAttributeString("label", label); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - LLUICtrlCallback callback = NULL; - - LLFlyoutButton* flyout_button = new LLFlyoutButton(name, - rect, - label, - callback, - NULL); - - std::string list_position; - node->getAttributeString("list_position", list_position); - if (list_position == "below") - { - flyout_button->mListPosition = BELOW; - } - else if (list_position == "above") - { - flyout_button->mListPosition = ABOVE; - } - - - flyout_button->initFromXML(node, parent); - - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("flyout_button_item")) - { - std::string label = child->getTextContents(); - - std::string value = label; - child->getAttributeString("value", value); - - flyout_button->add(label, LLSD(value) ); - } - } - - flyout_button->updateLayout(); - - return flyout_button; -} - -void LLFlyoutButton::updateLayout() -{ - LLComboBox::updateLayout(); - - mButton->setOrigin(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0); - mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight()); - mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - mButton->setTabStop(FALSE); - mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT); - - mActionButton->setOrigin(0, 0); - mActionButton->reshape(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight()); -} - -//static -void LLFlyoutButton::onActionButtonClick(void *user_data) -{ - LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data; - // remember last list selection? - buttonp->mList->deselect(); - buttonp->onCommit(); -} - -void LLFlyoutButton::draw() -{ - mActionButton->setToggleState(mToggleState); - mButton->setToggleState(mToggleState); - - //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or - // the label reflects the last selected item, for now we have to manually remove the label - mButton->setLabel(LLStringUtil::null); - LLComboBox::draw(); -} - -void LLFlyoutButton::setEnabled(BOOL enabled) -{ - mActionButton->setEnabled(enabled); - LLComboBox::setEnabled(enabled); -} - - -void LLFlyoutButton::setToggleState(BOOL state) -{ - mToggleState = state; -} - diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 33e1baa748..e7a864eb82 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -41,14 +41,13 @@ #include "llctrlselectioninterface.h" #include "llimagegl.h" #include "llrect.h" +#include "llscrolllistctrl.h" +#include "lllineeditor.h" +#include // Classes class LLFontGL; -class LLButton; -class LLSquareButton; -class LLScrollListCtrl; -class LLLineEditor; class LLViewBorder; extern S32 LLCOMBOBOX_HEIGHT; @@ -57,30 +56,61 @@ extern S32 LLCOMBOBOX_WIDTH; class LLComboBox : public LLUICtrl, public LLCtrlListInterface { -public: +public: typedef enum e_preferred_position { ABOVE, BELOW } EPreferredPosition; - LLComboBox( - const std::string& name, - const LLRect &rect, - const std::string& label, - void (*commit_callback)(LLUICtrl*, void*) = NULL, - void *callback_userdata = NULL - ); - virtual ~LLComboBox(); + struct PreferredPositionValues : public LLInitParam::TypeValuesHelper + { + 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 + { + Optional label; + ItemParams(); + }; + + struct Params + : public LLInitParam::Block + { + Optional allow_text_entry, + show_text_as_tentative; + Optional max_chars; + Optional prearrange_callback, + text_entry_callback, + selection_callback; + Optional arrow_image; + + Optional list_position; + + // components + Optional combo_button; + Optional combo_list; + Optional combo_editor; + + Multiple items; + + Params(); + }; + + virtual ~LLComboBox(); + /*virtual*/ BOOL postBuild(); + +protected: + friend class LLUICtrlFactory; + LLComboBox(const Params&); + void initFromParams(const Params&); + +public: + // LLView interface virtual void draw(); virtual void onFocusLost(); - virtual void onLostTop(); virtual void setEnabled(BOOL enabled); @@ -105,7 +135,6 @@ public: // items, this is just the label. virtual LLSD getValue() const; - void setAllowTextEntry(BOOL allow, S32 max_chars = 50, BOOL make_tentative = TRUE); void setTextEntry(const LLStringExplicit& text); LLScrollListItem* add(const std::string& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); // add item "name" to menu @@ -134,7 +163,7 @@ public: BOOL setCurrentByIndex( S32 index ); S32 getCurrentIndex() const; - virtual void updateLayout(); + void createLineEditor(const Params&); //======================================================================== LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; @@ -170,26 +199,28 @@ public: void* getCurrentUserdata(); - void setPrearrangeCallback( void (*cb)(LLUICtrl*,void*) ) { mPrearrangeCallback = cb; } - void setTextEntryCallback( void (*cb)(LLLineEditor*, void*) ) { mTextEntryCallback = cb; } + void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; } + void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; } + void setSelectionCallback( commit_callback_t cb ) { mSelectionCallback = cb; } void setButtonVisible(BOOL visible); - static void onButtonDown(void *userdata); - static void onItemSelected(LLUICtrl* item, void *userdata); - static void onTextEntry(LLLineEditor* line_editor, void* user_data); - static void onTextCommit(LLUICtrl* caller, void* user_data); + void onButtonDown(); + void onItemSelected(const LLSD& data); + void onTextCommit(const LLSD& data); void updateSelection(); virtual void showList(); virtual void hideList(); - + + void onTextEntry(LLLineEditor* line_editor); + protected: LLButton* mButton; LLScrollListCtrl* mList; EPreferredPosition mListPosition; LLPointer mArrowImage; - std::string mLabel; + LLUIString mLabel; private: S32 mButtonPadding; @@ -197,39 +228,16 @@ private: BOOL mAllowTextEntry; S32 mMaxChars; BOOL mTextEntryTentative; - void (*mPrearrangeCallback)(LLUICtrl*,void*); - void (*mTextEntryCallback)(LLLineEditor*, void*); + commit_callback_t mPrearrangeCallback; + commit_callback_t mTextEntryCallback; + commit_callback_t mSelectionCallback; }; -class LLFlyoutButton : public LLComboBox -{ -public: - LLFlyoutButton( - const std::string& name, - const LLRect &rect, - const std::string& label, - void (*commit_callback)(LLUICtrl*, void*) = NULL, - void *callback_userdata = NULL); - - virtual void updateLayout(); - virtual void draw(); - virtual void setEnabled(BOOL enabled); - - void setToggleState(BOOL state); - - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - static void onActionButtonClick(void *userdata); - static void onSelectAction(LLUICtrl* ctrl, void *userdata); - -protected: - LLButton* mActionButton; - LLPointer mActionButtonImage; - LLPointer mExpanderButtonImage; - LLPointer mActionButtonImageSelected; - LLPointer mExpanderButtonImageSelected; - LLPointer mActionButtonImageDisabled; - LLPointer mExpanderButtonImageDisabled; - BOOL mToggleState; -}; +#ifdef LL_WINDOWS +#ifndef INSTANTIATE_GETCHILD_COMBOBOX +#pragma warning (disable : 4231) +extern template LLComboBox* LLView::getChild( 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;igetF32("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 + +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 + { + Optional max_lines; + Optional persist_time; + Optional 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 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 lines_t; + typedef std::list 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_t; + paragraph_t mParagraphs; + + ~LLConsole(){}; + + // each line lasts this long after being added + void setLinePersistTime(F32 seconds); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + // -1 = monospace, 0 means small, font size = 1 means big + void setFontSize(S32 size_index); + + void addLine(const std::string& utf8line, F32 size, const LLColor4 &color); + void addLine(const LLWString& wline, F32 size, const LLColor4 &color); + + // Overrides + /*virtual*/ void draw(); + /*virtual*/ void addLine(const std::string& utf8line); + /*virtual*/ void addLine(const LLWString& line); +private: + F32 mLinePersistTime; // Age at which to stop drawing. + F32 mFadeTime; // Age at which to start fading + const LLFontGL* mFont; + S32 mLastBoxHeight; + S32 mLastBoxWidth; + S32 mConsoleWidth; + S32 mConsoleHeight; + +}; + +extern LLConsole* gConsole; + +#endif diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp new file mode 100644 index 0000000000..a63023e35c --- /dev/null +++ b/indra/llui/llcontainerview.cpp @@ -0,0 +1,301 @@ +/** + * @file llcontainerview.cpp + * @brief Container for all statistics info + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llcontainerview.h" + +#include "llerror.h" +#include "llfontgl.h" +#include "llgl.h" +#include "llui.h" +#include "llstring.h" +#include "llscrollcontainer.h" +#include "lluictrlfactory.h" + +static LLRegisterWidget 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(getRect()).mBottom = getRect().mTop - total_height; + } + else + { + // HACK: casting away const. Should use setRect or some helper function instead. + const_cast(getRect()).mTop = getRect().mBottom + total_height; + } + // HACK: casting away const. Should use setRect or some helper function instead. + const_cast(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 + { + Optional label; + Optional show_label; + Optional 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 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 (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 + { + Optional label; + Optional drag_highlight_color; + Optional 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 + { + Optional min_value, + max_value, + increment; + + Params() + : min_value("min_val", 0.f), + max_value("max_val", 1.f), + increment("increment", 0.1f) + {} + }; + +protected: + LLF32UICtrl(const Params& p); + +public: + virtual F32 getValueF32() const; + + virtual void setValue(const LLSD& value ) { mViewModel->setValue(value); } + virtual LLSD getValue() const { return LLSD(getValueF32()); } + + virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } + virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } + + virtual F32 getInitialValue() const { return mInitialValue; } + virtual F32 getMinValue() const { return mMinValue; } + virtual F32 getMaxValue() const { return mMaxValue; } + virtual F32 getIncrement() const { return mIncrement; } + virtual void setMinValue(F32 min_value) { mMinValue = min_value; } + virtual void setMaxValue(F32 max_value) { mMaxValue = max_value; } + virtual void setIncrement(F32 increment) { mIncrement = increment;} + +protected: + F32 mInitialValue; + F32 mMinValue; + F32 mMaxValue; + F32 mIncrement; +}; + +#endif /* ! defined(LL_LLF32UICTRL_H) */ diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 21f8f6e5f7..be7e050b58 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -43,11 +43,13 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "lldraghandle.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llresizebar.h" #include "llresizehandle.h" #include "llkeyboard.h" #include "llmenugl.h" // MENU_BAR_HEIGHT +#include "llmodaldialog.h" #include "lltextbox.h" #include "llresmgr.h" #include "llui.h" @@ -56,37 +58,37 @@ #include "llcontrol.h" #include "lltabcontainer.h" #include "v2math.h" +#include "lltrans.h" +#include "llmultifloater.h" -const S32 MINIMIZED_WIDTH = 160; -const S32 CLOSE_BOX_FROM_TOP = 1; // use this to control "jumping" behavior when Ctrl-Tabbing const S32 TABBED_FLOATER_OFFSET = 0; std::string LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = { - "UIImgBtnCloseActiveUUID", //BUTTON_CLOSE - "UIImgBtnRestoreActiveUUID", //BUTTON_RESTORE - "UIImgBtnMinimizeActiveUUID", //BUTTON_MINIMIZE - "UIImgBtnTearOffActiveUUID", //BUTTON_TEAR_OFF - "UIImgBtnCloseActiveUUID", //BUTTON_EDIT + "closebox.tga", //BUTTON_CLOSE + "restore.tga", //BUTTON_RESTORE + "minimize.tga", //BUTTON_MINIMIZE + "tearoffbox.tga", //BUTTON_TEAR_OFF + "closebox.tga", //BUTTON_EDIT }; std::string LLFloater::sButtonInactiveImageNames[BUTTON_COUNT] = { - "UIImgBtnCloseInactiveUUID", //BUTTON_CLOSE - "UIImgBtnRestoreInactiveUUID", //BUTTON_RESTORE - "UIImgBtnMinimizeInactiveUUID", //BUTTON_MINIMIZE - "UIImgBtnTearOffInactiveUUID", //BUTTON_TEAR_OFF - "UIImgBtnCloseInactiveUUID", //BUTTON_EDIT + "close_inactive_blue.tga", //BUTTON_CLOSE + "restore_inactive.tga", //BUTTON_RESTORE + "minimize_inactive.tga", //BUTTON_MINIMIZE + "tearoffbox.tga", //BUTTON_TEAR_OFF + "close_inactive_blue.tga", //BUTTON_EDIT }; std::string LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = { - "UIImgBtnClosePressedUUID", //BUTTON_CLOSE - "UIImgBtnRestorePressedUUID", //BUTTON_RESTORE - "UIImgBtnMinimizePressedUUID", //BUTTON_MINIMIZE - "UIImgBtnTearOffPressedUUID", //BUTTON_TEAR_OFF - "UIImgBtnClosePressedUUID", //BUTTON_EDIT + "close_in_blue.tga", //BUTTON_CLOSE + "restore_pressed.tga", //BUTTON_RESTORE + "minimize_pressed.tga", //BUTTON_MINIMIZE + "tearoff_pressed.tga", //BUTTON_TEAR_OFF + "close_in_blue.tga", //BUTTON_EDIT }; std::string LLFloater::sButtonNames[BUTTON_COUNT] = @@ -98,17 +100,20 @@ std::string LLFloater::sButtonNames[BUTTON_COUNT] = "llfloater_edit_btn", //BUTTON_EDIT }; -std::string LLFloater::sButtonToolTips[BUTTON_COUNT] = +std::string LLFloater::sButtonToolTips[BUTTON_COUNT] = {}; + + +std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]= { #ifdef LL_DARWIN - "Close (Cmd-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_DARWIN",//LLTrans::getString("BUTTON_CLOSE_DARWIN"), //"Close (Cmd-W)", //BUTTON_CLOSE #else - "Close (Ctrl-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_WIN", //LLTrans::getString("BUTTON_CLOSE_WIN"), //"Close (Ctrl-W)", //BUTTON_CLOSE #endif - "Restore", //BUTTON_RESTORE - "Minimize", //BUTTON_MINIMIZE - "Tear Off", //BUTTON_TEAR_OFF - "Edit", //BUTTON_EDIT + "BUTTON_RESTORE",//LLTrans::getString("BUTTON_RESTORE"), //"Restore", //BUTTON_RESTORE + "BUTTON_MINIMIZE",//LLTrans::getString("BUTTON_MINIMIZE"), //"Minimize", //BUTTON_MINIMIZE + "BUTTON_TEAR_OFF",//LLTrans::getString("BUTTON_TEAR_OFF"), //"Tear Off", //BUTTON_TEAR_OFF + "BUTTON_EDIT", //LLTrans::getString("BUTTON_EDIT"), // "Edit", //BUTTON_EDIT }; LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = @@ -126,59 +131,118 @@ LLFloater::handle_map_t LLFloater::sFloaterMap; LLFloaterView* gFloaterView = NULL; -LLFloater::LLFloater() : - //FIXME: we should initialize *all* member variables here - LLPanel(), mAutoFocus(TRUE), - mResizable(FALSE), - mDragOnLeft(FALSE), - mMinWidth(0), - mMinHeight(0) -{ - // automatically take focus when opened - mAutoFocus = TRUE; +//static +bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b) +{ + if (a.type() != b.type()) + { + //llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl; + return false; + } + else if (a.isUndefined()) + return false; + else if (a.isInteger()) + return a.asInteger() < b.asInteger(); + else if (a.isReal()) + return a.asReal() < b.asReal(); + else if (a.isString()) + return a.asString() < b.asString(); + else if (a.isUUID()) + return a.asUUID() < b.asUUID(); + else if (a.isDate()) + return a.asDate() < b.asDate(); + else if (a.isURI()) + return a.asString() < b.asString(); // compare URIs as strings + else if (a.isBoolean()) + return a.asBoolean() < b.asBoolean(); + else + return false; // no valid operation for Binary +} + +bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b) +{ + if (a.type() != b.type()) + { + //llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl; + return false; + } + else if (a.isUndefined()) + return true; + else if (a.isInteger()) + return a.asInteger() == b.asInteger(); + else if (a.isReal()) + return a.asReal() == b.asReal(); + else if (a.isString()) + return a.asString() == b.asString(); + else if (a.isUUID()) + return a.asUUID() == b.asUUID(); + else if (a.isDate()) + return a.asDate() == b.asDate(); + else if (a.isURI()) + return a.asString() == b.asString(); // compare URIs as strings + else if (a.isBoolean()) + return a.asBoolean() == b.asBoolean(); + else + return false; // no valid operation for Binary +} + +//************************************ + +LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) + : LLPanel(), + mDragHandle(NULL), + mTitle(p.title), + mShortTitle(p.short_title), + mSingleInstance(p.single_instance), + mKey(key), + mAutoTile(p.auto_tile), + mCanTearOff(p.can_tear_off), + mCanMinimize(p.can_minimize), + mCanClose(p.can_close), + mDragOnLeft(p.can_drag_on_left), + mResizable(p.can_resize), + mMinWidth(p.min_width), + mMinHeight(p.min_height), + mMinimized(FALSE), + mForeground(FALSE), + mFirstLook(TRUE), + mEditing(FALSE), + mButtonScale(1.0f), + mAutoFocus(TRUE), // automatically take focus when opened + mHasBeenDraggedWhileMinimized(FALSE), + mPreviousMinimizedBottom(0), + mPreviousMinimizedLeft(0), + mNotificationContext(NULL) +{ + static LLUICachedControl default_background_color ("FloaterDefaultBackgroundColor", *(new LLColor4)); + static LLUICachedControl focus_background_color ("FloaterFocusBackgroundColor", *(new LLColor4)); + for (S32 i = 0; i < BUTTON_COUNT; i++) { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; - } - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; + sButtonToolTips[i] =LLTrans::getString( sButtonToolTipsIndex[i]); } - mDragHandle = NULL; + mHandle.bind(this); mNotificationContext = new LLFloaterNotificationContext(getHandle()); -} + mBgColorAlpha = default_background_color; + mBgColorOpaque = focus_background_color; -LLFloater::LLFloater(const std::string& name) -: LLPanel(name), mAutoFocus(TRUE) // automatically take focus when opened -{ - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; - } for (S32 i = 0; i < 4; i++) { - mResizeBar[i] = NULL; + mResizeBar[i] = NULL; mResizeHandle[i] = NULL; } - std::string title; // null string - initFloater(title, FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, TRUE, TRUE); // defaults -} + // Clicks stop here. + setMouseOpaque(TRUE); + + // Floaters always draw their background, unlike every other panel. + setBackgroundVisible(TRUE); -LLFloater::LLFloater(const std::string& name, const LLRect& rect, const std::string& title, - BOOL resizable, - S32 min_width, - S32 min_height, - BOOL drag_on_left, - BOOL minimizable, - BOOL close_btn, - BOOL bordered) -: LLPanel(name, rect, bordered), mAutoFocus(TRUE) // automatically take focus when opened -{ + // Floaters start not minimized. When minimized, they save their + // prior rectangle to be used on restore. + mExpandedRect.set(0,0,0,0); + for (S32 i = 0; i < BUTTON_COUNT; i++) { mButtonsEnabled[i] = FALSE; @@ -189,259 +253,176 @@ LLFloater::LLFloater(const std::string& name, const LLRect& rect, const std::str mResizeBar[i] = NULL; mResizeHandle[i] = NULL; } - initFloater( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn); -} + + initFromParams(p); + + // chrome floaters don't take focus at all + setFocusRoot(!getIsChrome()); -LLFloater::LLFloater(const std::string& name, const std::string& rect_control, const std::string& title, - BOOL resizable, - S32 min_width, - S32 min_height, - BOOL drag_on_left, - BOOL minimizable, - BOOL close_btn, - BOOL bordered) -: LLPanel(name, rect_control, bordered), mAutoFocus(TRUE) // automatically take focus when opened -{ - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; - } - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; - } - initFloater( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn); + initFloater(); } - // Note: Floaters constructed from XML call init() twice! -void LLFloater::initFloater(const std::string& title, - BOOL resizable, S32 min_width, S32 min_height, - BOOL drag_on_left, BOOL minimizable, BOOL close_btn) +void LLFloater::initFloater() { - mHandle.bind(this); - mNotificationContext = new LLFloaterNotificationContext(getHandle()); - - // Init function can be called more than once, so clear out old data. - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - if (mButtons[i] != NULL) - { - removeChild(mButtons[i]); - delete mButtons[i]; - mButtons[i] = NULL; - } - } - mButtonScale = 1.f; + addDragHandle(); + + addResizeCtrls(); - //sjb: Thia is a bit of a hack: - BOOL need_border = hasBorder(); - // remove the border since deleteAllChildren() will also delete the border (but not clear mBorder) - removeBorder(); - // this will delete mBorder too - deleteAllChildren(); - // add the border back if we want it - if (need_border) + // Close button. + if (mCanClose) { - addBorder(); + mButtonsEnabled[BUTTON_CLOSE] = TRUE; } - // chrome floaters don't take focus at all - setFocusRoot(!getIsChrome()); - - // Reset cached pointers - mDragHandle = NULL; - for (S32 i = 0; i < 4; i++) + // Minimize button only for top draggers + if ( !mDragOnLeft && mCanMinimize ) { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; + mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; } - mCanTearOff = TRUE; - mEditing = FALSE; - // Clicks stop here. - setMouseOpaque(TRUE); + buildButtons(); - mFirstLook = TRUE; - mForeground = FALSE; - mDragOnLeft = drag_on_left == TRUE; + // Floaters are created in the invisible state + setVisible(FALSE); - // Floaters always draw their background, unlike every other panel. - setBackgroundVisible(TRUE); + // add self to handle->floater map + sFloaterMap[mHandle] = this; - // Floaters start not minimized. When minimized, they save their - // prior rectangle to be used on restore. - mMinimized = FALSE; - mExpandedRect.set(0,0,0,0); - - S32 close_pad; // space to the right of close box - S32 close_box_size; // For layout purposes, how big is the close box? - if (close_btn) - { - close_box_size = LLFLOATER_CLOSE_BOX_SIZE; - close_pad = 0; - } - else + if (!getParent()) { - close_box_size = 0; - close_pad = 0; + gFloaterView->addChild(this); } +} - S32 minimize_box_size; - S32 minimize_pad; - if (minimizable && !drag_on_left) - { - minimize_box_size = LLFLOATER_CLOSE_BOX_SIZE; - minimize_pad = 0; - } - else +void LLFloater::addDragHandle() +{ + static LLUICachedControl 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(p); + } + else // drag on top + { + LLDragHandleTop::Params p; + p.name("Drag Handle"); + p.follows.flags(FOLLOWS_ALL); + p.label(mTitle); + mDragHandle = LLUICtrlFactory::create(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(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(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(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(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(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(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(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(handle_p); + addChild(mResizeHandle[3]); } // virtual LLFloater::~LLFloater() { + LLFloaterReg::removeInstance(mInstanceName, mKey); + delete mNotificationContext; mNotificationContext = NULL; - control_map_t::iterator itor; - for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor) - { - delete itor->second; - } - mFloaterControls.clear(); - //// am I not hosted by another floater? //if (mHostHandle.isDead()) //{ @@ -469,8 +450,27 @@ LLFloater::~LLFloater() delete mResizeBar[i]; delete mResizeHandle[i]; } + + storeRectControl(); + setVisible(false); // We're not visible if we're destroyed + storeVisibilityControl(); +} + +void LLFloater::storeRectControl() +{ + if( mRectControl.size() > 1 ) + { + LLUI::sSettingGroups["floater"]->setRect( mRectControl, getRect() ); + } } +void LLFloater::storeVisibilityControl() +{ + if( mVisibilityControl.size() > 1 ) + { + LLUI::sSettingGroups["floater"]->setBOOL( mVisibilityControl, getVisible() ); + } +} void LLFloater::setVisible( BOOL visible ) { @@ -504,10 +504,25 @@ void LLFloater::setVisible( BOOL visible ) } ++dependent_it; } + + storeVisibilityControl(); +} + +// virtual +void LLFloater::onVisibilityChange ( BOOL new_visibility ) +{ + if (new_visibility) + { + if (getHost()) + getHost()->setFloaterFlashing(this, FALSE); + } + LLPanel::onVisibilityChange ( new_visibility ); } -void LLFloater::open() /* Flawfinder: ignore */ +void LLFloater::openFloater(const LLSD& key) { + mKey = key; // in case we need to open ourselves again + if (getSoundFlags() != SILENT // don't play open sound for hosted (tabbed) windows && !getHost() @@ -525,9 +540,11 @@ void LLFloater::open() /* Flawfinder: ignore */ // only select tabs if window they are hosted in is visible getFloaterHost()->addFloater(this, getFloaterHost()->getVisible()); } - else if (getHost() != NULL) + + if (getHost() != NULL) { - // already hosted + getHost()->setMinimized(FALSE); + getHost()->setVisibleAndFrontmost(mAutoFocus); getHost()->showFloater(this); } else @@ -536,10 +553,10 @@ void LLFloater::open() /* Flawfinder: ignore */ setVisibleAndFrontmost(mAutoFocus); } - onOpen(); + onOpen(key); } -void LLFloater::close(bool app_quitting) +void LLFloater::closeFloater(bool app_quitting) { // Always unminimize before trying to close. // Most of the time the user will never see this state. @@ -570,7 +587,7 @@ void LLFloater::close(bool app_quitting) if (floaterp) { ++dependent_it; - floaterp->close(); + floaterp->closeFloater(app_quitting); } else { @@ -597,7 +614,7 @@ void LLFloater::close(bool app_quitting) } } } - + // Let floater do cleanup. onClose(app_quitting); } @@ -607,6 +624,7 @@ void LLFloater::close(bool app_quitting) void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent) { LLPanel::reshape(width, height, called_from_parent); + storeRectControl(); } void LLFloater::releaseFocus() @@ -664,15 +682,23 @@ void LLFloater::center() centerWithin(gFloaterView->getRect()); } +LLMultiFloater* LLFloater::getHost() +{ + return (LLMultiFloater*)mHostHandle.get(); +} + void LLFloater::applyRectControl() { - if (!getRectControl().empty()) + if (mRectControl.size() > 1) { - const LLRect& rect = LLUI::sConfigGroup->getRect(getRectControl()); - translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); - if (mResizable) + const LLRect& rect = LLUI::sSettingGroups["floater"]->getRect(mRectControl); + if (rect.getWidth() > 0 && rect.getHeight() > 0) { - reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); + if (mResizable) + { + reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + } } } } @@ -763,7 +789,7 @@ BOOL LLFloater::canSnapTo(const LLView* other_view) return LLPanel::canSnapTo(other_view); } -void LLFloater::snappedTo(const LLView* snap_view) +void LLFloater::setSnappedTo(const LLView* snap_view) { if (!snap_view || snap_view == getParent()) { @@ -778,10 +804,10 @@ void LLFloater::snappedTo(const LLView* snap_view) } } -void LLFloater::userSetShape(const LLRect& new_rect) +void LLFloater::handleReshape(const LLRect& new_rect, bool by_user) { const LLRect old_rect = getRect(); - LLView::userSetShape(new_rect); + LLView::handleReshape(new_rect, by_user); // if not minimized, adjust all snapped dependents to new shape if (!isMinimized()) @@ -816,7 +842,7 @@ void LLFloater::userSetShape(const LLRect& new_rect) delta_y += new_rect.mBottom - old_rect.mBottom; dependent_rect.translate(delta_x, delta_y); - floaterp->userSetShape(dependent_rect); + floaterp->setShape(dependent_rect, by_user); } } } @@ -834,6 +860,9 @@ void LLFloater::userSetShape(const LLRect& new_rect) void LLFloater::setMinimized(BOOL minimize) { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + static LLUICachedControl minimized_width ("UIMinimizedWidth", 0); + if (minimize == mMinimized) return; if (minimize) @@ -902,7 +931,7 @@ void LLFloater::setMinimized(BOOL minimize) mMinimized = TRUE; // Reshape *after* setting mMinimized - reshape( MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE, TRUE); + reshape( minimized_width, floater_header_size, TRUE); } else { @@ -995,6 +1024,13 @@ void LLFloater::setFocus( BOOL b ) } } +// virtual +void LLFloater::setRect(const LLRect &rect) +{ + LLPanel::setRect(rect); + addDragHandle(); // re-add drag handle, sized based on rect +} + // virtual void LLFloater::setIsChrome(BOOL is_chrome) { @@ -1276,19 +1312,18 @@ void LLFloater::setEditModeEnabled(BOOL enable) // static -void LLFloater::onClickMinimize(void *userdata) +void LLFloater::onClickMinimize(LLFloater* self) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - + if (!self) + return; self->setMinimized( !self->isMinimized() ); } -void LLFloater::onClickTearOff(void *userdata) +void LLFloater::onClickTearOff(LLFloater* self) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + if (!self) + return; LLMultiFloater* host_floater = self->getHost(); if (host_floater) //Tear off { @@ -1297,12 +1332,12 @@ void LLFloater::onClickTearOff(void *userdata) // reparent to floater view gFloaterView->addChild(self); - self->open(); /* Flawfinder: ignore */ + self->openFloater(self->getKey()); // only force position for floaters that don't have that data saved - if (self->getRectControl().empty()) + if (self->mRectControl.size() <= 1) { - new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->getRect().getWidth(), self->getRect().getHeight()); + new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight()); self->setRect(new_rect); } gFloaterView->adjustToFitScreen(self, FALSE); @@ -1317,17 +1352,16 @@ void LLFloater::onClickTearOff(void *userdata) self->setMinimized(FALSE); // to reenable minimize button if it was minimized new_host->showFloater(self); // make sure host is visible - new_host->open(); + new_host->openFloater(new_host->getKey()); } } } // static -void LLFloater::onClickEdit(void *userdata) +void LLFloater::onClickEdit(LLFloater* self) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - + if (!self) + return; self->mEditing = self->mEditing ? FALSE : TRUE; } @@ -1373,7 +1407,7 @@ void LLFloater::closeFocusedFloater() LLFloater* floater_to_close = LLFloater::getClosableFloaterFromFocus(); if(floater_to_close) { - floater_to_close->close(); + floater_to_close->closeFloater(); } // if nothing took focus after closing focused floater @@ -1388,12 +1422,11 @@ void LLFloater::closeFocusedFloater() // static -void LLFloater::onClickClose( void* userdata ) +void LLFloater::onClickClose( LLFloater* self ) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - - self->close(); + if (!self) + return; + self->closeFloater(false); } @@ -1408,8 +1441,11 @@ void LLFloater::draw() S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH; S32 bottom = LLPANEL_BORDER_WIDTH; - LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow"); - F32 shadow_offset = (F32)LLUI::sConfigGroup->getS32("DropShadowFloater"); + static LLUICachedControl shadow_offset_S32 ("DropShadowFloater", 0); + static LLUICachedControl shadow_color_cached ("ColorDropShadow", *(new LLColor4)); + LLColor4 shadow_color = shadow_color_cached; + F32 shadow_offset = (F32)shadow_offset_S32; + if (!isBackgroundOpaque()) { shadow_offset *= 0.2f; @@ -1422,20 +1458,21 @@ void LLFloater::draw() // No transparent windows in simple UI if (isBackgroundOpaque()) { - gl_rect_2d( left, top, right, bottom, getBackgroundColor() ); + gl_rect_2d( left, top, right, bottom, mBgColorOpaque ); } else { - gl_rect_2d( left, top, right, bottom, getTransparentColor() ); + gl_rect_2d( left, top, right, bottom, mBgColorAlpha ); } if(gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() && !getCurrentTitle().empty()) { + static LLUICachedControl titlebar_focus_color ("TitleBarFocusColor", *(new LLColor4)); // draw highlight on title bar to indicate focus. RDW - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); LLRect r = getRect(); gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1, - LLUI::sColorsGroup->getColor("TitleBarFocusColor"), 0, TRUE); + titlebar_focus_color, 0, TRUE); } } @@ -1489,8 +1526,10 @@ void LLFloater::draw() { // add in a border to improve spacialized visual aclarity ;) // use lines instead of gl_rect_2d so we can round the edges as per james' recommendation + static LLUICachedControl focus_border_color ("FloaterFocusBorderColor", *(new LLColor4)); + static LLUICachedControl unfocus_border_color ("FloaterUnfocusBorderColor", *(new LLColor4)); LLUI::setLineWidth(1.5f); - LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? LLUI::sColorsGroup->getColor("FloaterFocusBorderColor") : LLUI::sColorsGroup->getColor("FloaterUnfocusBorderColor"); + LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? focus_border_color() : unfocus_border_color; gl_rect_2d_offset_local(0, getRect().getHeight() + 1, getRect().getWidth() + 1, 0, outlineColor, -LLPANEL_BORDER_WIDTH, FALSE); LLUI::setLineWidth(1.f); } @@ -1511,6 +1550,7 @@ void LLFloater::setCanMinimize(BOOL can_minimize) { // if removing minimize/restore button programmatically, // go ahead and unminimize floater + mCanMinimize = can_minimize; if (!can_minimize) { setMinimized(FALSE); @@ -1524,6 +1564,7 @@ void LLFloater::setCanMinimize(BOOL can_minimize) void LLFloater::setCanClose(BOOL can_close) { + mCanClose = can_close; mButtonsEnabled[BUTTON_CLOSE] = can_close; updateButtons(); @@ -1538,83 +1579,10 @@ void LLFloater::setCanTearOff(BOOL can_tear_off) } -void LLFloater::setCanResize(BOOL can_resize) +void LLFloater::setCanResize(BOOL can_resize) { - if (mResizable && !can_resize) - { - for (S32 i = 0; i < 4; i++) - { - removeChild(mResizeBar[i], TRUE); - mResizeBar[i] = NULL; - - removeChild(mResizeHandle[i], TRUE); - mResizeHandle[i] = NULL; - } - } - else if (!mResizable && can_resize) - { - // Resize bars (sides) - const S32 RESIZE_BAR_THICKNESS = 3; - mResizeBar[0] = new LLResizeBar( - std::string("resizebar_left"), - this, - LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0), - mMinWidth, S32_MAX, LLResizeBar::LEFT ); - addChild( mResizeBar[0] ); - - mResizeBar[1] = new LLResizeBar( - std::string("resizebar_top"), - this, - LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS), - mMinHeight, S32_MAX, LLResizeBar::TOP ); - addChild( mResizeBar[1] ); - - mResizeBar[2] = new LLResizeBar( - std::string("resizebar_right"), - this, - LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0), - mMinWidth, S32_MAX, LLResizeBar::RIGHT ); - addChild( mResizeBar[2] ); - - mResizeBar[3] = new LLResizeBar( - std::string("resizebar_bottom"), - this, - LLRect( 0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0), - mMinHeight, S32_MAX, LLResizeBar::BOTTOM ); - addChild( mResizeBar[3] ); - - - // Resize handles (corners) - mResizeHandle[0] = new LLResizeHandle( - std::string("Resize Handle"), - LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0), - mMinWidth, - mMinHeight, - LLResizeHandle::RIGHT_BOTTOM); - addChild(mResizeHandle[0]); - - mResizeHandle[1] = new LLResizeHandle( std::string("resize"), - LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT), - mMinWidth, - mMinHeight, - LLResizeHandle::RIGHT_TOP ); - addChild(mResizeHandle[1]); - - mResizeHandle[2] = new LLResizeHandle( std::string("resize"), - LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ), - mMinWidth, - mMinHeight, - LLResizeHandle::LEFT_BOTTOM ); - addChild(mResizeHandle[2]); - - mResizeHandle[3] = new LLResizeHandle( std::string("resize"), - LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ), - mMinWidth, - mMinHeight, - LLResizeHandle::LEFT_TOP ); - addChild(mResizeHandle[3]); - } mResizable = can_resize; + addResizeCtrls(); } void LLFloater::setCanDrag(BOOL can_drag) @@ -1633,6 +1601,8 @@ void LLFloater::setCanDrag(BOOL can_drag) void LLFloater::updateButtons() { + static LLUICachedControl floater_close_box_size ("UIFloaterCloseBoxSize", 0); + static LLUICachedControl close_box_from_top ("UICloseBoxFromTop", 0); S32 button_count = 0; for (S32 i = 0; i < BUTTON_COUNT; i++) { @@ -1652,17 +1622,17 @@ void LLFloater::updateButtons() { btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH, - getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count, - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count, + llround((F32)floater_close_box_size * mButtonScale), + llround((F32)floater_close_box_size * mButtonScale)); } else { btn_rect.setLeftTopAndSize( - getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count, - getRect().getHeight() - CLOSE_BOX_FROM_TOP, - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count, + getRect().getHeight() - close_box_from_top, + llround((F32)floater_close_box_size * mButtonScale), + llround((F32)floater_close_box_size * mButtonScale)); } mButtons[i]->setRect(btn_rect); @@ -1676,50 +1646,56 @@ void LLFloater::updateButtons() } } if (mDragHandle) - mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (LLFLOATER_CLOSE_BOX_SIZE + 1))); + mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (floater_close_box_size + 1))); } void LLFloater::buildButtons() { + static LLUICachedControl floater_close_box_size ("UIFloaterCloseBoxSize", 0); + static LLUICachedControl 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(p); addChild(buttonp); mButtons[i] = buttonp; } @@ -1730,13 +1706,11 @@ void LLFloater::buildButtons() ///////////////////////////////////////////////////// // LLFloaterView -LLFloaterView::LLFloaterView( const std::string& name, const LLRect& rect ) -: LLUICtrl( name, rect, FALSE, NULL, NULL, FOLLOWS_ALL ), +LLFloaterView::LLFloaterView (const Params& p) +: LLUICtrl (p), mFocusCycleMode(FALSE), mSnapOffsetBottom(0) { - setTabStop(FALSE); - resetStartingFloaterPosition(); } // By default, adjust vertical. @@ -1830,69 +1804,6 @@ void LLFloaterView::restoreAll() } -void LLFloaterView::getNewFloaterPosition(S32* left,S32* top) -{ - // Workaround: mRect may change between when this object is created and the first time it is used. - static BOOL first = TRUE; - if( first ) - { - resetStartingFloaterPosition(); - first = FALSE; - } - - const S32 FLOATER_PAD = 16; - LLCoordWindow window_size; - getWindow()->getSize(&window_size); - LLRect full_window(0, window_size.mY, window_size.mX, 0); - LLRect floater_creation_rect( - 160, - full_window.getHeight() - 2 * MENU_BAR_HEIGHT, - full_window.getWidth() * 2 / 3, - 130 ); - floater_creation_rect.stretch( -FLOATER_PAD ); - - *left = mNextLeft; - *top = mNextTop; - - const S32 STEP = 25; - S32 bottom = floater_creation_rect.mBottom + 2 * STEP; - S32 right = floater_creation_rect.mRight - 4 * STEP; - - mNextTop -= STEP; - mNextLeft += STEP; - - if( (mNextTop < bottom ) || (mNextLeft > right) ) - { - mColumn++; - mNextTop = floater_creation_rect.mTop; - mNextLeft = STEP * mColumn; - - if( (mNextTop < bottom) || (mNextLeft > right) ) - { - // Advancing the column didn't work, so start back at the beginning - resetStartingFloaterPosition(); - } - } -} - -void LLFloaterView::resetStartingFloaterPosition() -{ - const S32 FLOATER_PAD = 16; - LLCoordWindow window_size; - getWindow()->getSize(&window_size); - LLRect full_window(0, window_size.mY, window_size.mX, 0); - LLRect floater_creation_rect( - 160, - full_window.getHeight() - 2 * MENU_BAR_HEIGHT, - full_window.getWidth() * 2 / 3, - 130 ); - floater_creation_rect.stretch( -FLOATER_PAD ); - - mNextLeft = floater_creation_rect.mLeft; - mNextTop = floater_creation_rect.mTop; - mColumn = 0; -} - LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ) { LLRect base_rect = reference_floater->getRect(); @@ -2104,15 +2015,17 @@ void LLFloaterView::focusFrontFloater() void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom) { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + static LLUICachedControl minimized_width ("UIMinimizedWidth", 0); S32 col = 0; LLRect snap_rect_local = getLocalSnapRect(); for(S32 row = snap_rect_local.mBottom; - row < snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE; - row += LLFLOATER_HEADER_SIZE ) //loop rows + row < snap_rect_local.getHeight() - floater_header_size; + row += floater_header_size ) //loop rows { for(col = snap_rect_local.mLeft; - col < snap_rect_local.getWidth() - MINIMIZED_WIDTH; - col += MINIMIZED_WIDTH) + col < snap_rect_local.getWidth() - minimized_width; + col += minimized_width) { bool foundGap = TRUE; for(child_list_const_iter_t child_it = getChildList()->begin(); @@ -2124,10 +2037,10 @@ void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom) if(floater->isMinimized()) { LLRect r = floater->getRect(); - if((r.mBottom < (row + LLFLOATER_HEADER_SIZE)) - && (r.mBottom > (row - LLFLOATER_HEADER_SIZE)) - && (r.mLeft < (col + MINIMIZED_WIDTH)) - && (r.mLeft > (col - MINIMIZED_WIDTH))) + if((r.mBottom < (row + floater_header_size)) + && (r.mBottom > (row - floater_header_size)) + && (r.mLeft < (col + minimized_width)) + && (r.mLeft > (col - minimized_width))) { // needs the check for off grid. can't drag, // but window resize makes them off @@ -2179,7 +2092,7 @@ void LLFloaterView::closeAllChildren(bool app_quitting) // dialogs to appear. if (floaterp->canClose() && !floaterp->isDead()) { - floaterp->close(app_quitting); + floaterp->closeFloater(app_quitting); } } } @@ -2202,14 +2115,13 @@ BOOL LLFloaterView::allChildrenClosed() return true; } - void LLFloaterView::refresh() { // Constrain children to be entirely on the screen for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { - LLFloater* floaterp = (LLFloater*)*child_it; - if( floaterp->getVisible() ) + LLFloater* floaterp = dynamic_cast(*child_it); + if (floaterp && floaterp->getVisible() ) { // minimized floaters are kept fully onscreen adjustToFitScreen(floaterp, !floaterp->isMinimized()); @@ -2306,7 +2218,7 @@ LLRect LLFloaterView::getSnapRect() const return snap_rect; } -LLFloater *LLFloaterView::getFocusedFloater() +LLFloater *LLFloaterView::getFocusedFloater() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { @@ -2319,7 +2231,7 @@ LLFloater *LLFloaterView::getFocusedFloater() return NULL; } -LLFloater *LLFloaterView::getFrontmost() +LLFloater *LLFloaterView::getFrontmost() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { @@ -2332,7 +2244,7 @@ LLFloater *LLFloaterView::getFrontmost() return NULL; } -LLFloater *LLFloaterView::getBackmost() +LLFloater *LLFloaterView::getBackmost() const { LLFloater* back_most = NULL; for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) @@ -2348,18 +2260,51 @@ LLFloater *LLFloaterView::getBackmost() void LLFloaterView::syncFloaterTabOrder() { - // bring focused floater to front - for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) + // look for a visible modal dialog, starting from first (should be only one) + LLModalDialog* modal_dialog = NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { - LLFloater* floaterp = (LLFloater*)*child_it; - if (gFocusMgr.childHasKeyboardFocus(floaterp)) + LLModalDialog* dialog = dynamic_cast(*child_it); + if (dialog && dialog->isModal() && dialog->getVisible()) { - bringToFront(floaterp, FALSE); + modal_dialog = dialog; break; } } - // then sync draw order to tab order + if (modal_dialog) + { + // If we have a visible modal dialog, make sure that it has focus + if( gFocusMgr.getTopCtrl() != modal_dialog ) + { + gFocusMgr.setTopCtrl( modal_dialog ); + } + + if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) ) + { + modal_dialog->setFocus(TRUE); + } + + if( !gFocusMgr.childHasMouseCapture( modal_dialog ) ) + { + gFocusMgr.setMouseCapture( modal_dialog ); + } + } + else + { + // otherwise, make sure the focused floater is in the front of the child list + for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) + { + LLFloater* floaterp = (LLFloater*)*child_it; + if (gFocusMgr.childHasKeyboardFocus(floaterp)) + { + bringToFront(floaterp, FALSE); + break; + } + } + } + + // sync draw order to tab order for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) { LLFloater* floaterp = (LLFloater*)*child_it; @@ -2367,7 +2312,7 @@ void LLFloaterView::syncFloaterTabOrder() } } -LLFloater* LLFloaterView::getParentFloater(LLView* viewp) +LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const { LLView* parentp = viewp->getParent(); @@ -2426,641 +2371,137 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list) } } -// -// LLMultiFloater -// - -LLMultiFloater::LLMultiFloater() : - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(TRUE), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ - -} - -LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos) : - mTabContainer(NULL), - mTabPos(tab_pos), - mAutoResize(TRUE), - mOrigMinWidth(0), - mOrigMinHeight(0) +void LLFloater::setInstanceName(const std::string& name) { - -} - -LLMultiFloater::LLMultiFloater(const std::string &name) : - LLFloater(name), - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(FALSE), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ -} - -LLMultiFloater::LLMultiFloater( - const std::string& name, - const LLRect& rect, - LLTabContainer::TabPosition tab_pos, - BOOL auto_resize) : - LLFloater(name, rect, name), - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(auto_resize), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ - mTabContainer = new LLTabContainer(std::string("Preview Tabs"), - LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0), - mTabPos, - FALSE, - FALSE); - mTabContainer->setFollowsAll(); - if (isResizable()) - { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - - addChild(mTabContainer); -} - -LLMultiFloater::LLMultiFloater( - const std::string& name, - const std::string& rect_control, - LLTabContainer::TabPosition tab_pos, - BOOL auto_resize) : - LLFloater(name, rect_control, name), - mTabContainer(NULL), - mTabPos(tab_pos), - mAutoResize(auto_resize), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ - mTabContainer = new LLTabContainer(std::string("Preview Tabs"), - LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0), - mTabPos, - FALSE, - FALSE); - mTabContainer->setFollowsAll(); - if (isResizable() && mTabPos == LLTabContainer::BOTTOM) - { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - - addChild(mTabContainer); - -} - - -void LLMultiFloater::open() /* Flawfinder: ignore */ -{ - if (mTabContainer->getTabCount() > 0) - { - LLFloater::open(); /* Flawfinder: ignore */ - } - else - { - // for now, don't allow multifloaters - // without any child floaters - close(); - } -} - -void LLMultiFloater::onClose(bool app_quitting) -{ - if(closeAllFloaters() == TRUE) - { - LLFloater::onClose(app_quitting); - }//else not all tabs could be closed... -} - -void LLMultiFloater::draw() -{ - if (mTabContainer->getTabCount() == 0) - { - //RN: could this potentially crash in draw hierarchy? - close(); - } - else + if (name == mInstanceName) + return; + llassert_always(mInstanceName.empty()); + mInstanceName = name; + if (!mInstanceName.empty()) { - for (S32 i = 0; i < mTabContainer->getTabCount(); i++) + // save_rect and save_visibility only apply to registered floaters + if (!mRectControl.empty()) { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i); - if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i)) - { - mTabContainer->setPanelTitle(i, floaterp->getShortTitle()); - } + mRectControl = LLFloaterReg::declareRectControl(mInstanceName); } - LLFloater::draw(); - } -} - -BOOL LLMultiFloater::closeAllFloaters() -{ - S32 tabToClose = 0; - S32 lastTabCount = mTabContainer->getTabCount(); - while (tabToClose < mTabContainer->getTabCount()) - { - LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose); - first_floater->close(); - if(lastTabCount == mTabContainer->getTabCount()) + if (!mVisibilityControl.empty()) { - //Tab did not actually close, possibly due to a pending Save Confirmation dialog.. - //so try and close the next one in the list... - tabToClose++; - }else - { - //Tab closed ok. - lastTabCount = mTabContainer->getTabCount(); + mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName); } } - if( mTabContainer->getTabCount() != 0 ) - return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE. - return TRUE; //else all tabs were successfully closed... } -void LLMultiFloater::growToFit(S32 content_width, S32 content_height) +void LLFloater::setKey(const LLSD& newkey) { - S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2); - S32 new_height = llmax(getRect().getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); - - if (isMinimized()) - { - LLRect newrect; - newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height); - setExpandedRect(newrect); - } - else - { - S32 old_height = getRect().getHeight(); - reshape(new_width, new_height); - // keep top left corner in same position - translate(0, old_height - new_height); - } + // Note: We don't have to do anything special with registration when we change keys + mKey = newkey; } -/** - void addFloater(LLFloater* floaterp, BOOL select_added_floater) - - Adds the LLFloater pointed to by floaterp to this. - If floaterp is already hosted by this, then it is re-added to get - new titles, etc. - If select_added_floater is true, the LLFloater pointed to by floaterp will - become the selected tab in this - - Affects: mTabContainer, floaterp -**/ -void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point) +void LLFloater::initFromParams(const LLFloater::Params& p) { - if (!floaterp) - { - return; - } - - if (!mTabContainer) - { - llerrs << "Tab Container used without having been initialized." << llendl; - return; - } - - if (floaterp->getHost() == this) - { - // already hosted by me, remove - // do this so we get updated title, etc. - mFloaterDataMap.erase(floaterp->getHandle()); - mTabContainer->removeTabPanel(floaterp); - } - else if (floaterp->getHost()) - { - // floaterp is hosted by somebody else and - // this is adding it, so remove it from it's old host - floaterp->getHost()->removeFloater(floaterp); - } - else if (floaterp->getParent() == gFloaterView) - { - // rehost preview floater as child panel - gFloaterView->removeChild(floaterp); - } - - // store original configuration - LLFloaterData floater_data; - floater_data.mWidth = floaterp->getRect().getWidth(); - floater_data.mHeight = floaterp->getRect().getHeight(); - floater_data.mCanMinimize = floaterp->isMinimizeable(); - floater_data.mCanResize = floaterp->isResizable(); - - // remove minimize and close buttons - floaterp->setCanMinimize(FALSE); - floaterp->setCanResize(FALSE); - floaterp->setCanDrag(FALSE); - floaterp->storeRectControl(); - // avoid double rendering of floater background (makes it more opaque) - floaterp->setBackgroundVisible(FALSE); - - if (mAutoResize) - { - growToFit(floater_data.mWidth, floater_data.mHeight); - } + // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible + LLPanel::initFromParams(p); - //add the panel, add it to proper maps - mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); - mFloaterDataMap[floaterp->getHandle()] = floater_data; + mTitle = p.title; + mShortTitle = p.short_title; + applyTitle(); - updateResizeLimits(); + setCanTearOff(p.can_tear_off); + setCanMinimize(p.can_minimize); + setCanClose(p.can_close); + + mDragOnLeft = p.can_drag_on_left; + mResizable = p.can_resize; + mMinWidth = p.min_width; + mMinHeight = p.min_height; + mSingleInstance = p.single_instance; + mAutoTile = p.auto_tile; - if ( select_added_floater ) + if (p.save_rect) { - mTabContainer->selectTabPanel(floaterp); + mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set } - else + if (p.save_visibility) { - // reassert visible tab (hiding new floater if necessary) - mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex()); + mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set } - - floaterp->setHost(this); - if (isMinimized()) - { - floaterp->setVisible(FALSE); - } -} - -/** - BOOL selectFloater(LLFloater* floaterp) - - If the LLFloater pointed to by floaterp is hosted by this, - then its tab is selected and returns true. Otherwise returns false. - - Affects: mTabContainer -**/ -BOOL LLMultiFloater::selectFloater(LLFloater* floaterp) -{ - return mTabContainer->selectTabPanel(floaterp); -} - -// virtual -void LLMultiFloater::selectNextFloater() -{ - mTabContainer->selectNextTab(); } -// virtual -void LLMultiFloater::selectPrevFloater() +void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater, LLXMLNodePtr output_node) { - mTabContainer->selectPrevTab(); -} + Params params(LLUICtrlFactory::getDefaultParams()); + LLXUIParser::instance().readXUI(node, params); -void LLMultiFloater::showFloater(LLFloater* floaterp) -{ - // we won't select a panel that already is selected - // it is hard to do this internally to tab container - // as tab selection is handled via index and the tab at a given - // index might have changed - if (floaterp != mTabContainer->getCurrentPanel() && - !mTabContainer->selectTabPanel(floaterp)) + if (output_node) { - addFloater(floaterp, TRUE); + Params output_params(params); + setupParamsForExport(output_params, parent); + Params default_params(LLUICtrlFactory::getDefaultParams()); + output_node->setName(node->getName()->mString); + LLXUIParser::instance().writeXUI( + output_node, output_params, &default_params); } -} -void LLMultiFloater::removeFloater(LLFloater* floaterp) -{ - if ( floaterp->getHost() != this ) - return; - - floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle()); - if (found_data_it != mFloaterDataMap.end()) + setupParams(params, parent); + initFromParams(params); + + initFloater(); + + LLMultiFloater* last_host = LLFloater::getFloaterHost(); + if (node->hasName("multi_floater")) { - LLFloaterData& floater_data = found_data_it->second; - floaterp->setCanMinimize(floater_data.mCanMinimize); - if (!floater_data.mCanResize) - { - // restore original size - floaterp->reshape(floater_data.mWidth, floater_data.mHeight); - } - floaterp->setCanResize(floater_data.mCanResize); - mFloaterDataMap.erase(found_data_it); + LLFloater::setFloaterHost((LLMultiFloater*) this); } - mTabContainer->removeTabPanel(floaterp); - floaterp->setBackgroundVisible(TRUE); - floaterp->setCanDrag(TRUE); - floaterp->setHost(NULL); - floaterp->applyRectControl(); - - updateResizeLimits(); - - tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); -} -void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click) -{ - // default implementation does nothing -} + addChildren(node, output_node); -void LLMultiFloater::tabClose() -{ - if (mTabContainer->getTabCount() == 0) + if (node->hasName("multi_floater")) { - // no more children, close myself - close(); + LLFloater::setFloaterHost(last_host); } -} - -void LLMultiFloater::setVisible(BOOL visible) -{ - // *FIX: shouldn't have to do this, fix adding to minimized multifloater - LLFloater::setVisible(visible); - if (mTabContainer) - { - LLPanel* cur_floaterp = mTabContainer->getCurrentPanel(); - - if (cur_floaterp) - { - cur_floaterp->setVisible(visible); - } - - // if no tab selected, and we're being shown, - // select last tab to be added - if (visible && !cur_floaterp) - { - mTabContainer->selectLastTab(); - } - } -} + BOOL result = postBuild(); -BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask) -{ - if (key == 'W' && mask == MASK_CONTROL) + if (!result) { - LLFloater* floater = getActiveFloater(); - // is user closeable and is system closeable - if (floater && floater->canClose() && floater->isCloseable()) - { - floater->close(); - } - return TRUE; + llerrs << "Failed to construct floater " << getName() << llendl; } - return LLFloater::handleKeyHere(key, mask); -} - -LLFloater* LLMultiFloater::getActiveFloater() -{ - return (LLFloater*)mTabContainer->getCurrentPanel(); -} - -S32 LLMultiFloater::getFloaterCount() -{ - return mTabContainer->getTabCount(); -} - -/** - BOOL isFloaterFlashing(LLFloater* floaterp) - - Returns true if the LLFloater pointed to by floaterp - is currently in a flashing state and is hosted by this. - False otherwise. - - Requires: floaterp != NULL -**/ -BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp) -{ - if ( floaterp && floaterp->getHost() == this ) - return mTabContainer->getTabPanelFlashing(floaterp); - - return FALSE; -} - -/** - BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing) - - Sets the current flashing state of the LLFloater pointed - to by floaterp to be the BOOL flashing if the LLFloater pointed - to by floaterp is hosted by this. - - Requires: floaterp != NULL -**/ -void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) -{ - if ( floaterp && floaterp->getHost() == this ) - mTabContainer->setTabPanelFlashing(floaterp, flashing); -} - -//static -void LLMultiFloater::onTabSelected(void* userdata, bool from_click) -{ - LLMultiFloater* floaterp = (LLMultiFloater*)userdata; - - floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click); -} + applyRectControl(); // If we have a saved rect control, apply it + gFloaterView->adjustToFitScreen(this, FALSE); // Floaters loaded from XML should all fit on screen -void LLMultiFloater::setCanResize(BOOL can_resize) -{ - LLFloater::setCanResize(can_resize); - if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM) + if (open_floater) { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - else - { - mTabContainer->setRightTabBtnOffset(0); + this->openFloater(getKey()); } + + moveResizeHandlesToFront(); } -BOOL LLMultiFloater::postBuild() +// visibility methods +bool VisibilityPolicy::visible(LLFloater* instance, const LLSD& key) { - // remember any original xml minimum size - getResizeLimits(&mOrigMinWidth, &mOrigMinHeight); - - if (mTabContainer) - { - return TRUE; - } - - requires("Preview Tabs"); - if (checkRequirements()) + if (instance) { - mTabContainer = getChild("Preview Tabs"); - return TRUE; + return !instance->isMinimized() && instance->isInVisibleChain(); } - return FALSE; } -void LLMultiFloater::updateResizeLimits() +void VisibilityPolicy::show(LLFloater* instance, const LLSD& key) { - // initialize minimum size constraint to the original xml values. - S32 new_min_width = mOrigMinWidth; - S32 new_min_height = mOrigMinHeight; - // possibly increase minimum size constraint due to children's minimums. - for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + if (instance) { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx); - if (floaterp) + instance->openFloater(key); + if (instance->getHost()) { - new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2); - new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); + instance->getHost()->openFloater(key); } } - setResizeLimits(new_min_width, new_min_height); - - S32 cur_height = getRect().getHeight(); - S32 new_width = llmax(getRect().getWidth(), new_min_width); - S32 new_height = llmax(getRect().getHeight(), new_min_height); - - if (isMinimized()) - { - const LLRect& expanded = getExpandedRect(); - LLRect newrect; - newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height)); - setExpandedRect(newrect); - } - else - { - reshape(new_width, new_height); - - // make sure upper left corner doesn't move - translate(0, cur_height - getRect().getHeight()); - - // make sure this window is visible on screen when it has been modified - // (tab added, etc) - gFloaterView->adjustToFitScreen(this, TRUE); - } -} - -// virtual -LLXMLNodePtr LLFloater::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLPanel::getXML(); - - node->createChild("title", TRUE)->setStringValue(getCurrentTitle()); - - node->createChild("can_resize", TRUE)->setBoolValue(isResizable()); - - node->createChild("can_minimize", TRUE)->setBoolValue(isMinimizeable()); - - node->createChild("can_close", TRUE)->setBoolValue(isCloseable()); - - node->createChild("can_drag_on_left", TRUE)->setBoolValue(isDragOnLeft()); - - node->createChild("min_width", TRUE)->setIntValue(getMinWidth()); - - node->createChild("min_height", TRUE)->setIntValue(getMinHeight()); - - node->createChild("can_tear_off", TRUE)->setBoolValue(mCanTearOff); - - return node; } -// static -LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +void VisibilityPolicy::hide(LLFloater* instance, const LLSD& key) { - std::string name("floater"); - node->getAttributeString("name", name); - - LLFloater *floaterp = new LLFloater(name); - - std::string filename; - node->getAttributeString("filename", filename); - - if (filename.empty()) - { - // Load from node - floaterp->initFloaterXML(node, parent, factory); - } - else - { - // Load from file - factory->buildFloater(floaterp, filename); - } - - return floaterp; + if (instance) instance->closeFloater(); } -void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open) /* Flawfinder: ignore */ -{ - std::string name(getName()); - std::string title(getCurrentTitle()); - std::string short_title(getShortTitle()); - std::string rect_control(""); - BOOL resizable = isResizable(); - S32 min_width = getMinWidth(); - S32 min_height = getMinHeight(); - BOOL drag_on_left = isDragOnLeft(); - BOOL minimizable = isMinimizeable(); - BOOL close_btn = isCloseable(); - LLRect rect; - - node->getAttributeString("name", name); - node->getAttributeString("title", title); - node->getAttributeString("short_title", short_title); - node->getAttributeString("rect_control", rect_control); - node->getAttributeBOOL("can_resize", resizable); - node->getAttributeBOOL("can_minimize", minimizable); - node->getAttributeBOOL("can_close", close_btn); - node->getAttributeBOOL("can_drag_on_left", drag_on_left); - node->getAttributeS32("min_width", min_width); - node->getAttributeS32("min_height", min_height); - - if (! rect_control.empty()) - { - setRectControl(rect_control); - } - - createRect(node, rect, parent, LLRect()); - - setRect(rect); - setName(name); - - initFloater(title, - resizable, - min_width, - min_height, - drag_on_left, - minimizable, - close_btn); - - setTitle(title); - applyTitle (); - - setShortTitle(short_title); - - BOOL can_tear_off; - if (node->getAttributeBOOL("can_tear_off", can_tear_off)) - { - setCanTearOff(can_tear_off); - } - - initFromXML(node, parent); - - LLMultiFloater* last_host = LLFloater::getFloaterHost(); - if (node->hasName("multi_floater")) - { - LLFloater::setFloaterHost((LLMultiFloater*) this); - } - - initChildrenXML(node, factory); - - if (node->hasName("multi_floater")) - { - LLFloater::setFloaterHost(last_host); - } - - BOOL result = postBuild(); - - if (!result) - { - llerrs << "Failed to construct floater " << name << llendl; - } - - applyRectControl(); - if (open) /* Flawfinder: ignore */ - { - this->open(); /* Flawfinder: ignore */ - } - - moveResizeHandlesToFront(); -} diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 0e3d148b09..f6c783b0bf 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -39,7 +39,6 @@ #include "llpanel.h" #include "lluuid.h" -#include "lltabcontainer.h" #include "llnotifications.h" #include @@ -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 mFloaterHandle; }; - class LLFloater : public LLPanel { friend class LLFloaterView; +friend class LLFloaterReg; +friend class LLMultiFloater; public: + struct KeyCompare + { + static bool compare(const LLSD& a, const LLSD& b); + static bool equate(const LLSD& a, const LLSD& b); + bool operator()(const LLSD& a, const LLSD& b) const + { + return compare(a, b); + } + }; + enum EFloaterButtons { BUTTON_CLOSE, @@ -102,49 +105,63 @@ public: BUTTON_COUNT }; - LLFloater(); - LLFloater(const std::string& name); //simple constructor for data-driven initialization - LLFloater( const std::string& name, const LLRect& rect, const std::string& title, - BOOL resizable = FALSE, - S32 min_width = DEFAULT_MIN_WIDTH, - S32 min_height = DEFAULT_MIN_HEIGHT, - BOOL drag_on_left = FALSE, - BOOL minimizable = TRUE, - BOOL close_btn = TRUE, - BOOL bordered = BORDER_NO); - - LLFloater( const std::string& name, const std::string& rect_control, const std::string& title, - BOOL resizable = FALSE, - S32 min_width = DEFAULT_MIN_WIDTH, - S32 min_height = DEFAULT_MIN_HEIGHT, - BOOL drag_on_left = FALSE, - BOOL minimizable = TRUE, - BOOL close_btn = TRUE, - BOOL bordered = BORDER_NO); + struct Params + : public LLInitParam::Block + { + Optional title, + short_title; + + Optional single_instance, + auto_tile, + can_resize, + can_minimize, + can_close, + can_drag_on_left, + can_tear_off, + save_rect, + save_visibility; + + Params() : + title("title"), + short_title("short_title"), + single_instance("single_instance", false), + auto_tile("auto_tile", false), + can_resize("can_resize", false), + can_minimize("can_minimize", true), + can_close("can_close", true), + can_drag_on_left("can_drag_on_left", false), + can_tear_off("can_tear_off", true), + save_rect("save_rect", false), + save_visibility("save_visibility", false) + { + name = "floater"; + // defaults that differ from LLPanel: + background_visible = true; + visible = false; + } + }; + + LLFloater(const LLSD& key = LLSD(), const LLFloater::Params& params = LLFloater::Params()); virtual ~LLFloater(); - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - void initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open = TRUE); + void initFromParams(const LLFloater::Params& p); + void initFloaterXML(LLXMLNodePtr node, LLView *parent, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL); - /*virtual*/ void userSetShape(const LLRect& new_rect); + /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); /*virtual*/ BOOL canSnapTo(const LLView* other_view); - /*virtual*/ void snappedTo(const LLView* snap_view); + /*virtual*/ void setSnappedTo(const LLView* snap_view); /*virtual*/ void setFocus( BOOL b ); /*virtual*/ void setIsChrome(BOOL is_chrome); + /*virtual*/ void setRect(const LLRect &rect); - // Can be called multiple times to reset floater parameters. - // Deletes all children of the floater. - virtual void initFloater(const std::string& title, BOOL resizable, - S32 min_width, S32 min_height, BOOL drag_on_left, - BOOL minimizable, BOOL close_btn); + void initFloater(); - virtual void open(); /* Flawfinder: ignore */ + void openFloater(const LLSD& key = LLSD()); // If allowed, close the floater cleanly, releasing focus. // app_quitting is passed to onClose() below. - virtual void close(bool app_quitting = false); + void closeFloater(bool app_quitting = false); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); @@ -153,11 +170,8 @@ public: // moves to center of gFloaterView void center(); - // applies rectangle stored in mRectControl, if any - void applyRectControl(); - - LLMultiFloater* getHost() { return (LLMultiFloater*)mHostHandle.get(); } + LLMultiFloater* getHost(); void applyTitle(); const std::string& getCurrentTitle() const; @@ -185,9 +199,8 @@ public: void setResizeLimits( S32 min_width, S32 min_height ); void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } - bool isMinimizeable() const{ return mButtonsEnabled[BUTTON_MINIMIZE]; } - // Does this window have a close button, NOT can we close it right now. - bool isCloseable() const{ return (mButtonsEnabled[BUTTON_CLOSE]); } + bool isMinimizeable() const{ return mCanMinimize; } + bool isCloseable() const{ return mCanClose; } bool isDragOnLeft() const{ return mDragOnLeft; } S32 getMinWidth() const{ return mMinWidth; } S32 getMinHeight() const{ return mMinHeight; } @@ -198,7 +211,7 @@ public: virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual void draw(); - virtual void onOpen() {} + virtual void onOpen(const LLSD& key) {} // Call destroy() to free memory, or setVisible(FALSE) to keep it // If app_quitting, you might not want to save your visibility. @@ -210,8 +223,10 @@ public: virtual BOOL canClose() { return TRUE; } virtual void setVisible(BOOL visible); + virtual void onVisibilityChange ( BOOL curVisibilityIn ); + void setFrontmost(BOOL take_focus = TRUE); - + // Defaults to false. virtual BOOL canSaveAs() const { return FALSE; } @@ -222,6 +237,8 @@ public: LLHandle getSnapTarget() const { return mSnappedTo; } LLHandle getHandle() const { return mHandle; } + const LLSD& getKey() { return mKey; } + BOOL matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); } // Return a closeable floater, if any, given the current focus. static LLFloater* getClosableFloaterFromFocus(); @@ -235,22 +252,30 @@ public: return LLNotification::Params(name).context(mNotificationContext); } - static void onClickClose(void *userdata); - static void onClickMinimize(void *userdata); - static void onClickTearOff(void *userdata); - static void onClickEdit(void *userdata); + static void onClickClose(LLFloater* floater); + static void onClickMinimize(LLFloater* floater); + static void onClickTearOff(LLFloater* floater); + static void onClickEdit(LLFloater* floater); static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; } static void setEditModeEnabled(BOOL enable); static BOOL getEditModeEnabled() { return sEditModeEnabled; } - static LLMultiFloater* getFloaterHost() {return sHostp; } - + static LLMultiFloater* getFloaterHost() {return sHostp; } + protected: + void setRectControl(const std::string& rectname) { mRectControl = rectname; }; + void applyRectControl(); + void storeRectControl(); + void storeVisibilityControl(); + + void setKey(const LLSD& key); + void setInstanceName(const std::string& name); + virtual void bringToFront(S32 x, S32 y); virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE); - void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized + void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized const LLRect& getExpandedRect() const { return mExpandedRect; } void setAutoFocus(BOOL focus) { mAutoFocus = focus; } // whether to automatically take focus when opened @@ -266,31 +291,48 @@ private: void updateButtons(); void buildButtons(); BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons index); - + void addResizeCtrls(); + void addDragHandle(); + +protected: + std::string mRectControl; + std::string mVisibilityControl; + + LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg + +private: LLRect mExpandedRect; LLDragHandle* mDragHandle; LLResizeBar* mResizeBar[4]; LLResizeHandle* mResizeHandle[4]; - LLButton *mMinimizeButton; + + LLUIString mTitle; + LLUIString mShortTitle; + + BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater + std::string mInstanceName; // Store the instance name so we can remove ourselves from the list + BOOL mAutoTile; // TRUE if placement of new instances tiles + BOOL mCanTearOff; + BOOL mCanMinimize; + BOOL mCanClose; + BOOL mDragOnLeft; + BOOL mResizable; + + S32 mMinWidth; + S32 mMinHeight; + BOOL mMinimized; BOOL mForeground; LLHandle 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 > handle_set_t; typedef std::set >::iterator handle_set_iter_t; handle_set_t mDependents; - bool mDragOnLeft; BOOL mButtonsEnabled[BUTTON_COUNT]; LLButton* mButtons[BUTTON_COUNT]; @@ -308,7 +350,9 @@ private: static std::string sButtonPressedImageNames[BUTTON_COUNT]; static std::string sButtonNames[BUTTON_COUNT]; static std::string sButtonToolTips[BUTTON_COUNT]; - typedef void (*click_callback)(void *); + static std::string sButtonToolTipsIndex[BUTTON_COUNT]; + + typedef void(*click_callback)(LLFloater*); static click_callback sButtonCallbacks[BUTTON_COUNT]; typedef std::map, LLFloater*> handle_map_t; @@ -320,7 +364,10 @@ private: BOOL mHasBeenDraggedWhileMinimized; S32 mPreviousMinimizedBottom; S32 mPreviousMinimizedLeft; - + + LLColor4 mBgColorAlpha; + LLColor4 mBgColorOpaque; + LLFloaterNotificationContext* mNotificationContext; LLRootHandle mHandle; }; @@ -331,18 +378,18 @@ private: class LLFloaterView : public LLUICtrl { -public: - LLFloaterView( const std::string& name, const LLRect& rect ); +protected: + LLFloaterView (const Params& p); + friend class LLUICtrlFactory; +public: /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical); /*virtual*/ void draw(); /*virtual*/ LLRect getSnapRect() const; - void refresh(); + /*virtual*/ void refresh(); - void getNewFloaterPosition( S32* left, S32* top ); - void resetStartingFloaterPosition(); LLRect findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ); // Given a child of gFloaterView, make sure this view can fit entirely onscreen. @@ -365,10 +412,10 @@ public: void closeAllChildren(bool app_quitting); BOOL allChildrenClosed(); - LLFloater* getFrontmost(); - LLFloater* getBackmost(); - LLFloater* getParentFloater(LLView* viewp); - LLFloater* getFocusedFloater(); + LLFloater* getFrontmost() const; + LLFloater* getBackmost() const; + LLFloater* getParentFloater(LLView* viewp) const; + LLFloater* getFocusedFloater() const; void syncFloaterTabOrder(); // Returns z order of child provided. 0 is closest, larger numbers @@ -386,99 +433,23 @@ private: S32 mSnapOffsetBottom; }; -// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376 -class LLMultiFloater : public LLFloater -{ -public: - LLMultiFloater(); - LLMultiFloater(LLTabContainer::TabPosition tab_pos); - LLMultiFloater(const std::string& name); - LLMultiFloater(const std::string& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE); - LLMultiFloater(const std::string& name, const std::string& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE); - virtual ~LLMultiFloater() {}; - - virtual BOOL postBuild(); - /*virtual*/ void open(); /* Flawfinder: ignore */ - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void draw(); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - - virtual void setCanResize(BOOL can_resize); - virtual void growToFit(S32 content_width, S32 content_height); - virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); - - virtual void showFloater(LLFloater* floaterp); - virtual void removeFloater(LLFloater* floaterp); - - virtual void tabOpen(LLFloater* opened_floater, bool from_click); - virtual void tabClose(); - - virtual BOOL selectFloater(LLFloater* floaterp); - virtual void selectNextFloater(); - virtual void selectPrevFloater(); - - virtual LLFloater* getActiveFloater(); - virtual BOOL isFloaterFlashing(LLFloater* floaterp); - virtual S32 getFloaterCount(); - - virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing); - virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs - void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } - static void onTabSelected(void* userdata, bool); - - virtual void updateResizeLimits(); - -protected: - struct LLFloaterData - { - S32 mWidth; - S32 mHeight; - BOOL mCanMinimize; - BOOL mCanResize; - }; - - LLTabContainer* mTabContainer; - - typedef std::map, 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 { public: // visibility methods - static bool visible(LLFloater* instance, const LLSD& key) - { - if (instance) - { - return !instance->isMinimized() && instance->isInVisibleChain(); - } - return FALSE; - } + static bool visible(LLFloater* instance, const LLSD& key); - static void show(LLFloater* instance, const LLSD& key) - { - if (instance) - { - instance->open(); - if (instance->getHost()) - { - instance->getHost()->open(); - } - } - } + static void show(LLFloater* instance, const LLSD& key); - static void hide(LLFloater* instance, const LLSD& key) - { - if (instance) instance->close(); - } + static void hide(LLFloater* instance, const LLSD& key); }; @@ -489,6 +460,10 @@ template class LLFloaterSingleton : public LLUISingleton 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 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& exceptions) +{ + // Iterate through alll active instances and hide them + for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) + { + const std::string& name = iter->first; + if (exceptions.find(name) != exceptions.end()) + continue; + instance_list_t& list = iter->second; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* floater = *iter; + floater->pushVisible(FALSE); + } + } +} + +//static +void LLFloaterReg::restoreVisibleInstances() +{ + // Iterate through all active instances and restore visibility + for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) + { + instance_list_t& list = iter->second; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* floater = *iter; + floater->popVisible(); + } + } +} + +//static +std::string LLFloaterReg::getRectControlName(const std::string& name) +{ + std::string res = std::string("floater_rect_") + name; + LLStringUtil::replaceChar( res, ' ', '_' ); + return res; +} + +//static +std::string LLFloaterReg::declareRectControl(const std::string& name) +{ + std::string controlname = getRectControlName(name); + LLUI::sSettingGroups["floater"]->declareRect(controlname, LLRect(), + llformat("Window Position and Size for %s", name.c_str()), + TRUE); + return controlname; +} + +//static +std::string LLFloaterReg::getVisibilityControlName(const std::string& name) +{ + std::string res = std::string("floater_vis_") + name; + LLStringUtil::replaceChar( res, ' ', '_' ); + return res; +} + +//static +std::string LLFloaterReg::declareVisibilityControl(const std::string& name) +{ + std::string controlname = getVisibilityControlName(name); + LLUI::sSettingGroups["floater"]->declareBOOL(controlname, FALSE, + llformat("Window Visibility for %s", name.c_str()), + TRUE); + return controlname; +} + +// Callbacks + +// static +// Call once (i.e use for init callbacks) +void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname) +{ + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the control value to the floater visibility control (Sets the value as well) + ctrl->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); +} + +// callback args may use "floatername.key" format +static void parse_name_key(std::string& name, LLSD& key) +{ + std::string instname = name; + std::size_t dotpos = instname.find("."); + if (dotpos != std::string::npos) + { + name = instname.substr(0, dotpos); + key = LLSD(instname.substr(dotpos+1, std::string::npos)); + } +} + +//static +void LLFloaterReg::showFloaterInstance(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + showInstance(name, key, TRUE); +} +//static +void LLFloaterReg::hideFloaterInstance(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + hideInstance(name, key); +} +//static +void LLFloaterReg::toggleFloaterInstance(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + toggleInstance(name, key); +} + +//static +bool LLFloaterReg::floaterInstanceVisible(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + return instanceVisible(name, key); +} + diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h new file mode 100644 index 0000000000..af1bfc5ec1 --- /dev/null +++ b/indra/llui/llfloaterreg.h @@ -0,0 +1,149 @@ +/** + * @file llfloaterreg.h + * @brief LLFloaterReg Floater Registration Class + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +/// llcommon +#include "llboost.h" +#include "llrect.h" +#include "llstl.h" +#include "llsd.h" + +/// llui +#include "lluictrl.h" + +#include + +//******************************************************* +// +// Floater Class Registry +// + +class LLFloater; + +typedef boost::function 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 instance_list_t; + typedef const instance_list_t const_instance_list_t; + typedef std::map instance_map_t; + + struct BuildData + { + LLFloaterBuildFunc mFunc; + std::string mFile; + }; + typedef std::map build_map_t; + +private: + static instance_list_t sNullInstanceList; + static instance_map_t sInstanceMap; + static build_map_t sBuildMap; + static std::map sGroupMap; + +public: + // Registration + + // usage: LLFloaterClassRegistry::add("foo", (LLFloaterBuildFunc)&LLFloaterClassRegistry::build); + template + 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& exceptions = std::set()); + 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 + static T* findTypedInstance(const std::string& name, const LLSD& key = LLSD()) + { + return dynamic_cast(findInstance(name, key)); + } + + template + static T* getTypedInstance(const std::string& name, const LLSD& key = LLSD()) + { + return dynamic_cast(getInstance(name, key)); + } + + template + static T* showTypedInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE) + { + return dynamic_cast(showInstance(name, key, focus)); + } + +}; + diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp new file mode 100644 index 0000000000..6b7c174726 --- /dev/null +++ b/indra/llui/llflyoutbutton.cpp @@ -0,0 +1,94 @@ +/** + * @file llflyoutbutton.cpp + * @brief LLFlyoutButton base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// file includes +#include "llflyoutbutton.h" + +static LLRegisterWidget 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(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 + { + Optional 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 focus_color_cached ("FocusColor", *(new LLColor4)); + LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt()); // de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem) if (!mAppHasFocus) { diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index 8864f7af15..2c0bcc6012 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -40,7 +40,7 @@ #include #include "llsd.h" -#include "llmemory.h" +#include "llsingleton.h" /** * @class LLFunctorRegistry diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index cb3b2a3a62..d01679cd1c 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -40,65 +40,33 @@ #include "llcontrol.h" #include "llui.h" #include "lluictrlfactory.h" - -const F32 RESOLUTION_BUMP = 1.f; +#include "lluiimage.h" static LLRegisterWidget r("icon"); -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id) -: LLUICtrl(name, - rect, - FALSE, // mouse opaque - NULL, NULL, - FOLLOWS_LEFT | FOLLOWS_TOP), - mColor( LLColor4::white ) -{ - setImage( image_id ); - setTabStop(FALSE); -} - -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name) -: LLUICtrl(name, - rect, - FALSE, // mouse opaque - NULL, NULL, - FOLLOWS_LEFT | FOLLOWS_TOP), - mColor( LLColor4::white ), - mImageName(image_name) -{ - setImage( image_name ); - setTabStop(FALSE); -} - - -LLIconCtrl::~LLIconCtrl() +LLIconCtrl::Params::Params() +: image("image_name"), + color("color"), + scale_image("scale_image") { - mImagep = NULL; + tab_stop = false; + mouse_opaque = false; } - -void LLIconCtrl::setImage(const std::string& image_name) +LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p) +: LLUICtrl(p), + mColor(p.color()), + mImagep(p.image) { - //RN: support UUIDs masquerading as strings - if (LLUUID::validate(image_name)) - { - mImageID = LLUUID(image_name); - - setImage(mImageID); - } - else + if (mImagep.notNull()) { - mImageName = image_name; - mImagep = LLUI::sImageProvider->getUIImage(image_name); - mImageID.setNull(); + LLUICtrl::setValue(mImagep->getName()); } } -void LLIconCtrl::setImage(const LLUUID& image_id) +LLIconCtrl::~LLIconCtrl() { - mImageName.clear(); - mImagep = LLUI::sImageProvider->getUIImageByID(image_id); - mImageID = image_id; + mImagep = NULL; } @@ -106,69 +74,37 @@ void LLIconCtrl::draw() { if( mImagep.notNull() ) { - mImagep->draw(getLocalRect(), mColor ); + mImagep->draw(getLocalRect(), mColor.get() ); } LLUICtrl::draw(); } // virtual +// value might be a string or a UUID void LLIconCtrl::setValue(const LLSD& value ) { - if (value.isUUID()) + LLSD tvalue(value); + if (value.isString() && LLUUID::validate(value.asString())) { - setImage(value.asUUID()); + //RN: support UUIDs masquerading as strings + tvalue = LLSD(LLUUID(value.asString())); } - else + LLUICtrl::setValue(tvalue); + if (tvalue.isUUID()) { - setImage(value.asString()); + mImagep = LLUI::getUIImageByID(tvalue.asUUID()); } -} - -// virtual -LLSD LLIconCtrl::getValue() const -{ - LLSD ret = getImage(); - return ret; -} - -// virtual -LLXMLNodePtr LLIconCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - if (mImageName != "") + else { - node->createChild("image_name", TRUE)->setStringValue(mImageName); + mImagep = LLUI::getUIImage(tvalue.asString()); } - - node->createChild("color", TRUE)->setFloatValue(4, mColor.mV); - - return node; } -LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +std::string LLIconCtrl::getImageName() const { - std::string name("icon"); - node->getAttributeString("name", name); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - std::string image_name; - if (node->hasAttribute("image_name")) - { - node->getAttributeString("image_name", image_name); - } - - LLColor4 color(LLColor4::white); - LLUICtrlFactory::getAttributeColor(node,"color", color); - - LLIconCtrl* icon = new LLIconCtrl(name, rect, image_name); - - icon->setColor(color); - - icon->initFromXML(node, parent); - - return icon; + if (getValue().isString()) + return getValue().asString(); + else + return std::string(); } diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 50778cf226..ad0f6f563f 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -45,35 +45,37 @@ class LLUICtrlFactory; // // Classes // + +// class LLIconCtrl : public LLUICtrl { public: - LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id); - LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name); + struct Params : public LLInitParam::Block + { + Optional image; + Optional color; + Deprecated scale_image; + Params(); + }; +protected: + LLIconCtrl(const Params&); + friend class LLUICtrlFactory; +public: virtual ~LLIconCtrl(); // llview overrides virtual void draw(); - void setImage(const std::string& image_name); - void setImage(const LLUUID& image_name); - const LLUUID &getImage() const { return mImageID; } - std::string getImageName() const { return mImageName; } - - // Takes a UUID, wraps get/setImage + // lluictrl overrides virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; - void setColor(const LLColor4& color) { mColor = color; } + std::string getImageName() const; - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + void setColor(const LLColor4& color) { mColor = color; } private: - LLColor4 mColor; - std::string mImageName; - LLUUID mImageID; + LLUIColor mColor; LLPointer mImagep; }; diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 51ef3dbacf..30796a5ab9 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -223,8 +223,8 @@ LLColor3 LLKeywords::readColor( const std::string& s ) { F32 r, g, b; r = g = b = 0.0f; - S32 read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b ); - if( read != 3 ) /* Flawfinder: ignore */ + S32 values_read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b ); + if( values_read != 3 ) { llinfos << " poorly formed color in keyword file" << llendl; } diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp new file mode 100644 index 0000000000..483c1358ae --- /dev/null +++ b/indra/llui/lllayoutstack.cpp @@ -0,0 +1,718 @@ +/** + * @file lllayoutstack.cpp + * @brief LLLayout class - dynamic stacking of UI elements + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Opaque view with a background and a border. Can contain LLUICtrls. + +#include "linden_common.h" + +#include "lllayoutstack.h" +#include "llresizebar.h" +#include "llcriticaldamp.h" + +// +// LLLayoutStack +// +struct LLLayoutStack::LLEmbeddedPanel +{ + LLEmbeddedPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp), + mMinWidth(min_width), + mMinHeight(min_height), + mAutoResize(auto_resize), + mUserResize(user_resize), + mOrientation(orientation), + mCollapsed(FALSE), + mCollapseAmt(0.f), + mVisibleAmt(1.f), // default to fully visible + mResizeBar(NULL) + { + LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; + LLRect resize_bar_rect = panelp->getRect(); + + S32 min_dim; + if (orientation == HORIZONTAL) + { + min_dim = mMinHeight; + } + else + { + min_dim = mMinWidth; + } + LLResizeBar::Params p; + p.name("resize"); + p.resizing_view(mPanel); + p.min_size(min_dim); + p.side(side); + p.snapping_enabled(false); + mResizeBar = LLUICtrlFactory::create(p); + // panels initialized as hidden should not start out partially visible + if (!mPanel->getVisible()) + { + mVisibleAmt = 0.f; + } + } + + ~LLEmbeddedPanel() + { + // probably not necessary, but... + delete mResizeBar; + mResizeBar = NULL; + } + + F32 getCollapseFactor() + { + if (mOrientation == HORIZONTAL) + { + F32 collapse_amt = + clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth())); + return mVisibleAmt * collapse_amt; + } + else + { + F32 collapse_amt = + clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight()))); + return mVisibleAmt * collapse_amt; + } + } + + LLPanel* mPanel; + S32 mMinWidth; + S32 mMinHeight; + BOOL mAutoResize; + BOOL mUserResize; + BOOL mCollapsed; + LLResizeBar* mResizeBar; + ELayoutOrientation mOrientation; + F32 mVisibleAmt; + F32 mCollapseAmt; +}; + +static LLRegisterWidget r2("layout_stack", &LLLayoutStack::fromXML); + +LLLayoutStack::Params::Params() +: orientation("orientation", std::string("vertical")), + border_size("border_size", LLCachedControl(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)) +{ + name="stack"; +} + +LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) +: LLView(p), + mMinWidth(0), + mMinHeight(0), + mPanelSpacing(p.border_size), + mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL) +{} + +LLLayoutStack::~LLLayoutStack() +{ + e_panel_list_t panels = mPanels; // copy list of panel pointers + mPanels.clear(); // clear so that removeChild() calls don't cause trouble + std::for_each(panels.begin(), panels.end(), DeletePointer()); +} + +void LLLayoutStack::draw() +{ + updateLayout(); + + e_panel_list_t::iterator panel_it; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + // clip to layout rectangle, not bounding rectangle + LLRect clip_rect = (*panel_it)->mPanel->getRect(); + // scale clipping rectangle by visible amount + if (mOrientation == HORIZONTAL) + { + clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor()); + } + else + { + clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor()); + } + + LLPanel* panelp = (*panel_it)->mPanel; + + LLLocalClipRect clip(clip_rect); + // only force drawing invisible children if visible amount is non-zero + drawChild(panelp, 0, 0, !clip_rect.isNull()); + } +} + +void LLLayoutStack::removeChild(LLView* view) +{ + LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast(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()); + LLXUIParser::instance().readXUI(node, p); + setupParams(p, parent); + LLLayoutStack* layout_stackp = LLUICtrlFactory::create(p); + + if (parent && layout_stackp) + { + S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup(); + + parent->addChild(layout_stackp, tab_group); + } + + if (output_node) + { + Params output_params(p); + setupParamsForExport(output_params, parent); + LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams()); + output_node->setName(node->getName()->mString); + LLXUIParser::instance().writeXUI( + output_node, output_params, &default_params); + } + + for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) + { + const S32 DEFAULT_MIN_WIDTH = 0; + const S32 DEFAULT_MIN_HEIGHT = 0; + const BOOL DEFAULT_AUTO_RESIZE = TRUE; + + S32 min_width = DEFAULT_MIN_WIDTH; + S32 min_height = DEFAULT_MIN_HEIGHT; + BOOL auto_resize = DEFAULT_AUTO_RESIZE; + + LLXMLNodePtr output_child; + if (output_node) + { + output_child = output_node->createChild("", FALSE); + } + + // Layout stack allows child nodes to acquire additional attributes, + // such as "min_width" in: " + // which equates to the following nesting: + // button + // param + // nested_param1 + // nested_param2 + // nested_param3 + for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) + { + std::string child_name(childp->getName()->mString); + S32 num_tokens_pushed = 0; + + // for non "dotted" child nodes check to see if child node maps to another widget type + // and if not, treat as a child element of the current node + // e.g. will interpret as "button.rect" + // since there is no widget named "rect" + if (child_name.find(".") == std::string::npos) { - continue; + // skip over children with registered names + if (LLWidgetCreatorRegistry::instance().exists(child_name)) + { + childp = childp->getNextSibling(); + continue; + } + + mNameStack.push_back(std::make_pair(child_name, newParseGeneration())); + num_tokens_pushed++; } - llinfos << "Rebuilding UI panel " << panelp->getName() - << " from " << filename - << llendl; - BOOL visible = panelp->getVisible(); - panelp->setVisible(FALSE); - panelp->setFocus(FALSE); - panelp->deleteAllChildren(); + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + childp = childp->getNextSibling(); + continue; + } - buildPanel(panelp, filename.c_str(), &panelp->getFactoryMap()); - panelp->setVisible(visible); + // check for proper nesting + if(!scope.empty() && *name_token_it != scope) + { + childp = childp->getNextSibling(); + continue; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); + num_tokens_pushed++; + } + } + + // recurse and visit children XML nodes + if(readXUIImpl(childp, mNameStack.empty() ? scope : mNameStack.back().first, block)) + { + // child node successfully parsed, remove from DOM + + values_parsed = true; + LLXMLNodePtr node_to_remove = childp; + childp = childp->getNextSibling(); + + nodep->deleteChild(node_to_remove); + } + else + { + childp = childp->getNextSibling(); + } + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } } + return values_parsed; +} + +bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); - built_floater_t::iterator built_floater_it; - for (built_floater_it = mBuiltFloaters.begin(); - built_floater_it != mBuiltFloaters.end(); - ++built_floater_it) + bool any_parsed = false; + + for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); + attribute_it != nodep->mAttributes.end(); + ++attribute_it) { - LLFloater* floaterp = built_floater_it->first.get(); - if (!floaterp) + S32 num_tokens_pushed = 0; + std::string attribute_name(attribute_it->first->mString); + mCurReadNode = attribute_it->second; + + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) { - continue; + mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); + num_tokens_pushed++; } - std::string filename = built_floater_it->second; - llinfos << "Rebuilding UI floater " << floaterp->getName() - << " from " << filename - << llendl; - BOOL visible = floaterp->getVisible(); - floaterp->setVisible(FALSE); - floaterp->setFocus(FALSE); - floaterp->deleteAllChildren(); - gFloaterView->removeChild(floaterp); - buildFloater(floaterp, filename, &floaterp->getFactoryMap()); - floaterp->setVisible(visible); + any_parsed |= block.submitValue(mNameStack, *this); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } } + + return any_parsed; } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- +bool LLXUIParser::readBoolValue(void* val_ptr) +{ + S32 value; + bool success = mCurReadNode->getBoolValue(1, &value); + *((bool*)val_ptr) = (value != FALSE); + return success; +} -LLView *LLUICtrlFactory::createCtrlWidget(LLPanel *parent, LLXMLNodePtr node) +bool LLXUIParser::writeBoolValue(const void* val_ptr, const name_stack_t& stack) { - std::string ctrl_type = node->getName()->mString; - LLStringUtil::toLower(ctrl_type); - - LLWidgetClassRegistry::factory_func_t func = LLWidgetClassRegistry::getInstance()->getCreatorFunc(ctrl_type); + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setBoolValue(*((bool*)val_ptr)); + return true; + } + return false; +} - if (func == NULL) +bool LLXUIParser::readStringValue(void* val_ptr) +{ + *((std::string*)val_ptr) = mCurReadNode->getSanitizedValue(); + return true; +} + +bool LLXUIParser::writeStringValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - llwarns << "Unknown control type " << ctrl_type << llendl; - return NULL; + node->setStringValue(*((std::string*)val_ptr)); + return true; } + return false; +} - if (parent == NULL) +bool LLXUIParser::readU8Value(void* val_ptr) +{ + return mCurReadNode->getByteValue(1, (U8*)val_ptr); +} + +bool LLXUIParser::writeU8Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - if (mDummyPanel == NULL) - { - mDummyPanel = new LLPanel; - } - parent = mDummyPanel; + node->setUnsignedValue(*((U8*)val_ptr)); + return true; } - LLView *ctrl = func(node, parent, this); + return false; +} - return ctrl; +bool LLXUIParser::readS8Value(void* val_ptr) +{ + S32 value; + if(mCurReadNode->getIntValue(1, &value)) + { + *((S8*)val_ptr) = value; + return true; + } + return false; } -LLView* LLUICtrlFactory::createWidget(LLPanel *parent, LLXMLNodePtr node) +bool LLXUIParser::writeS8Value(const void* val_ptr, const name_stack_t& stack) { - LLView* view = createCtrlWidget(parent, node); + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S8*)val_ptr)); + return true; + } + return false; +} - S32 tab_group = parent->getLastTabGroup(); - node->getAttributeS32("tab_group", tab_group); +bool LLXUIParser::readU16Value(void* val_ptr) +{ + U32 value; + if(mCurReadNode->getUnsignedValue(1, &value)) + { + *((U16*)val_ptr) = value; + return true; + } + return false; +} - if (view) +bool LLXUIParser::writeU16Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - parent->addChild(view, tab_group); + node->setUnsignedValue(*((U16*)val_ptr)); + return true; } + return false; +} - return view; +bool LLXUIParser::readS16Value(void* val_ptr) +{ + S32 value; + if(mCurReadNode->getIntValue(1, &value)) + { + *((S16*)val_ptr) = value; + return true; + } + return false; } -//----------------------------------------------------------------------------- -// createFactoryPanel() -//----------------------------------------------------------------------------- -LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name) +bool LLXUIParser::writeS16Value(const void* val_ptr, const name_stack_t& stack) { - std::deque::iterator itor; - for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor) + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - const LLCallbackMap::map_t* factory_map = *itor; + node->setIntValue(*((S16*)val_ptr)); + return true; + } + return false; +} - // Look up this panel's name in the map. - LLCallbackMap::map_const_iter_t iter = factory_map->find( name ); - if (iter != factory_map->end()) - { - // Use the factory to create the panel, instead of using a default LLPanel. - LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData ); - return ret; - } +bool LLXUIParser::readU32Value(void* val_ptr) +{ + return mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); +} + +bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U32*)val_ptr)); + return true; } - return NULL; + return false; } -//----------------------------------------------------------------------------- +bool LLXUIParser::readS32Value(void* val_ptr) +{ + return mCurReadNode->getIntValue(1, (S32*)val_ptr); +} -//static -BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color) +bool LLXUIParser::writeS32Value(const void* val_ptr, const name_stack_t& stack) { - std::string colorstring; - BOOL res = node->getAttributeString(name.c_str(), colorstring); - if (res && LLUI::sColorsGroup) + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - if (LLUI::sColorsGroup->controlExists(colorstring)) - { - color.setVec(LLUI::sColorsGroup->getColor(colorstring)); - } - else - { - res = FALSE; - } + node->setIntValue(*((S32*)val_ptr)); + return true; } - if (!res) + return false; +} + +bool LLXUIParser::readF32Value(void* val_ptr) +{ + return mCurReadNode->getFloatValue(1, (F32*)val_ptr); +} + +bool LLXUIParser::writeF32Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - res = LLColor4::parseColor(colorstring, &color); - } - if (!res) + node->setFloatValue(*((F32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF64Value(void* val_ptr) +{ + return mCurReadNode->getDoubleValue(1, (F64*)val_ptr); +} + +bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) { - res = node->getAttributeColor(name.c_str(), color); + node->setDoubleValue(*((F64*)val_ptr)); + return true; } - return res; + return false; } +bool LLXUIParser::readColor4Value(void* val_ptr) +{ + LLColor4* colorp = (LLColor4*)val_ptr; + if(mCurReadNode->getFloatValue(4, colorp->mV) >= 3) + { + return true; + } + + return false; +} + +bool LLXUIParser::writeColor4Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + LLColor4 color = *((LLColor4*)val_ptr); + node->setFloatValue(4, color.mV); + return true; + } + return false; +} + +bool LLXUIParser::readUIColorValue(void* val_ptr) +{ + LLUIColor* param = (LLUIColor*)val_ptr; + LLColor4 color; + bool success = mCurReadNode->getFloatValue(4, color.mV) >= 3; + if (success) + { + param->set(color); + return true; + } + return false; +} + +bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + LLUIColor color = *((LLUIColor*)val_ptr); + node->setFloatValue(4, color.get().mV); + return true; + } + return false; +} + +bool LLXUIParser::readUUIDValue(void* val_ptr) +{ + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(mCurReadNode->getSanitizedValue())) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLXUIParser::writeUUIDValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setStringValue(((LLUUID*)val_ptr)->asString()); + return true; + } + return false; +} + +bool LLXUIParser::readSDValue(void* val_ptr) +{ + *((LLSD*)val_ptr) = LLSD(mCurReadNode->getSanitizedValue()); + return true; +} + +bool LLXUIParser::writeSDValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setStringValue(((LLSD*)val_ptr)->asString()); + return true; + } + return false; +} + +/*virtual*/ std::string LLXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +void LLXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studo friendly formatting of output message for easy access to originating xml + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", LLUICtrlFactory::getInstance()->getCurFileName().c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserWarning(message); +#endif +} + +void LLXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", LLUICtrlFactory::getInstance()->getCurFileName().c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserError(message); +#endif +} diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 5e7c24efc0..5b04557368 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -33,68 +33,326 @@ #ifndef LLUICTRLFACTORY_H #define LLUICTRLFACTORY_H +#include "llcallbackmap.h" +#include "llinitparam.h" +#include "llxmlnode.h" + +#include #include #include -#include "llcallbackmap.h" -#include "llfloater.h" - -class LLView; class LLPanel; +class LLFloater; +class LLView; -class LLUICtrlFactory : public LLSingleton +class LLXUIParser : public LLInitParam::Parser, public LLSingleton { +LOG_CLASS(LLXUIParser); + +protected: + LLXUIParser(); + friend class LLSingleton; 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 > token_list_t; + + bool readXUIImpl(LLXMLNodePtr node, const std::string& scope, LLInitParam::BaseBlock& block); + bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + + //reader helper functions + bool readBoolValue(void* val_ptr); + bool readStringValue(void* val_ptr); + bool readU8Value(void* val_ptr); + bool readS8Value(void* val_ptr); + bool readU16Value(void* val_ptr); + bool readS16Value(void* val_ptr); + bool readU32Value(void* val_ptr); + bool readS32Value(void* val_ptr); + bool readF32Value(void* val_ptr); + bool readF64Value(void* val_ptr); + bool readColor4Value(void* val_ptr); + bool readUIColorValue(void* val_ptr); + bool readUUIDValue(void* val_ptr); + bool readSDValue(void* val_ptr); + + //writer helper functions + bool writeBoolValue(const void* val_ptr, const name_stack_t&); + bool writeStringValue(const void* val_ptr, const name_stack_t&); + bool writeU8Value(const void* val_ptr, const name_stack_t&); + bool writeS8Value(const void* val_ptr, const name_stack_t&); + bool writeU16Value(const void* val_ptr, const name_stack_t&); + bool writeS16Value(const void* val_ptr, const name_stack_t&); + bool writeU32Value(const void* val_ptr, const name_stack_t&); + bool writeS32Value(const void* val_ptr, const name_stack_t&); + bool writeF32Value(const void* val_ptr, const name_stack_t&); + bool writeF64Value(const void* val_ptr, const name_stack_t&); + bool writeColor4Value(const void* val_ptr, const name_stack_t&); + bool writeUIColorValue(const void* val_ptr, const name_stack_t&); + bool writeUUIDValue(const void* val_ptr, const name_stack_t&); + bool writeSDValue(const void* val_ptr, const name_stack_t&); + + LLXMLNodePtr getNode(const name_stack_t& stack); + +private: + Parser::name_stack_t mNameStack; + LLXMLNodePtr mCurReadNode; + // Root of the widget XML sub-tree, for example, "line_editor" + LLXMLNodePtr mWriteRootNode; + S32 mLastWriteGeneration; + LLXMLNodePtr mLastWrittenChild; +}; + +// global static instance for registering all widget types +typedef boost::function LLWidgetCreatorFunc; + +class LLWidgetCreatorRegistry : public LLRegistrySingleton +{ +protected: + LLWidgetCreatorRegistry() {} + +private: + friend class LLSingleton; +}; + +struct LLCompareTypeID +{ + bool operator()(const std::type_info* lhs, const std::type_info* rhs) const + { + return lhs->before(*rhs); + } +}; + + +class LLWidgetTemplateRegistry +: public LLRegistrySingleton +{ + +}; + +// local static instance for registering a particular widget +template +class LLRegisterWidget +: public LLWidgetCreatorRegistry::StaticRegistrar +{ +public: + // register with either the provided builder, or the generic templated builder + LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func = NULL); +}; + +class LLUICtrlFactory : public LLSingleton +{ +private: + friend class LLSingleton; LLUICtrlFactory(); - // do not call! needs to be public so run-time can clean up the singleton - virtual ~LLUICtrlFactory(); + ~LLUICtrlFactory(); + + // only partial specialization allowed in inner classes, so use extra dummy parameter + template + class ParamDefaults : public LLSingleton > + { + public: + ParamDefaults() + { + // recursively initialize from base class param block + ((typename T::base_block_t&)mPrototype).fillFrom(ParamDefaults::instance().get()); + // after initializing base classes, look up template file for this param block + std::string* param_block_tag = LLWidgetTemplateRegistry::instance().getValue(&typeid(T)); + if (param_block_tag) + { + LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, mPrototype); + } + } - void setupPaths(); + const T& get() { return mPrototype; } - void buildFloater(LLFloater* floaterp, const std::string &filename, - const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE); - BOOL buildPanel(LLPanel* panelp, const std::string &filename, - const LLCallbackMap::map_t* factory_map = NULL); + private: + T mPrototype; + }; - void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); } - void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); } + // base case for recursion, there are NO base classes of LLInitParam::BaseBlock + template + class ParamDefaults : public LLSingleton > + { + public: + const LLInitParam::BaseBlock& get() { return mBaseBlock; } + private: + LLInitParam::BaseBlock mBaseBlock; + }; - class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp); - class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp); +public: + + template + static const T& getDefaultParams() + { + //#pragma message("Generating ParamDefaults") + return ParamDefaults::instance().get(); + } + + void buildFloater(LLFloater* floaterp, const std::string &filename, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL); + LLFloater* buildFloaterFromXML(const std::string& filename, BOOL open_floater = TRUE); + BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL); // Does what you want for LLFloaters and LLPanels // Returns 0 on success S32 saveToXML(LLView* viewp, const std::string& filename); - // Rebuilds all currently built panels. - void rebuild(); + std::string getCurFileName() { return mFileNames.empty() ? "" : mFileNames.back(); } static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color); LLPanel* createFactoryPanel(const std::string& name); - virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node); - virtual LLView* createWidget(LLPanel *parent, LLXMLNodePtr node); + void pushFactoryFunctions(const LLCallbackMap::map_t* map); + void popFactoryFunctions(); - static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); + template + static T* create(typename T::Params& params, LLView* parent = NULL) + { + //#pragma message("Generating LLUICtrlFactory::create") + params.fillFrom(ParamDefaults::instance().get()); + //S32 foo = "test"; - static const std::vector& getXUIPaths(); + if (!params.validateBlock()) + { + llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; + } + T* widget = new T(params); + widget->initFromParams(params); + if (parent) + widget->setParent(parent); + return widget; + } -private: - bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root); + LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename = LLStringUtil::null, LLXMLNodePtr output_node = NULL); + + template + static T* createFromFile(const std::string &filename, LLView *parent) + { + //#pragma message("Generating LLUICtrlFactory::createFromFile") + T* widget = NULL; + + std::string skinned_filename = findSkinnedFilename(filename); + getInstance()->mFileNames.push_back(skinned_filename); + { + LLXMLNodePtr root_node; + + if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) + { + LLView* view = getInstance()->createFromXML(root_node, parent, filename); + if (view) + { + widget = dynamic_cast(view); + // not of right type, so delete it + if (!widget) + { + delete view; + view = NULL; + } + + } + } + else + { + llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl; + } + } + getInstance()->mFileNames.pop_back(); - typedef std::map, std::string> built_panel_t; - built_panel_t mBuiltPanels; + return widget; + } - typedef std::map, std::string> built_floater_t; - built_floater_t mBuiltFloaters; + template + static T* createDummyWidget(const std::string& name) + { + //#pragma message("Generating LLUICtrlFactory::createDummyWidget") + typename T::Params params; + params.name(name); + + return create(params); + } - std::deque mFactoryStack; + template + static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) + { + //#pragma message("Generating LLUICtrlFactory::defaultBuilder") + PARAM_BLOCK params(getDefaultParams()); - static std::vector sXUIPaths; + LLXUIParser::instance().readXUI(node, params); - LLPanel* mDummyPanel; + if (output_node) + { + // We always want to output top-left coordinates + PARAM_BLOCK output_params(params); + T::setupParamsForExport(output_params, parent); + // Export only the differences between this any default params + PARAM_BLOCK default_params(getDefaultParams()); + output_node->setName(node->getName()->mString); + LLXUIParser::instance().writeXUI( + output_node, output_params, &default_params); + } + + // Apply layout transformations, usually munging rect + T::setupParams(params, parent); + + if (!params.validateBlock()) + { + llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; + } + T* widget = new T(params); + widget->initFromParams(params); + + if (parent) + { + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; + setCtrlParent(widget, parent, tab_group); + } + + widget->addChildren(node, output_node); + + if (!widget->postBuild()) + { + delete widget; + return NULL; + } + + return widget; + } + + static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); + + static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); + +private: + //static void setCtrlValue(LLView* view, LLXMLNodePtr node); + static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); + + // Avoid directly using LLUI and LLDir in the template code + static std::string findSkinnedFilename(const std::string& filename); + + typedef std::deque factory_stack_t; + factory_stack_t mFactoryStack; + + LLPanel* mDummyPanel; + std::vector mFileNames; }; +// this is here to make gcc happy with reference to LLUICtrlFactory +template +LLRegisterWidget::LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func) +: LLWidgetCreatorRegistry::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder : func) +{ + //FIXME: inventory_panel will register itself with LLPanel::Params but it does have its own params...:( + LLWidgetTemplateRegistry::instance().defaultRegistrar().add(&typeid(PARAM_BLOCK), tag); +} + #endif //LLUICTRLFACTORY_H diff --git a/indra/llui/lluifwd.h b/indra/llui/lluifwd.h index 32d5c9b44f..f99bb39fdd 100644 --- a/indra/llui/lluifwd.h +++ b/indra/llui/lluifwd.h @@ -53,7 +53,6 @@ class LLSlider; class LLSliderCtrl; class LLSpinCtrl; class LLTabContainer; -class LLTabContainerVertical; class LLTextBox; class LLTextEditor; class LLTextureCtrl; diff --git a/indra/llui/lluiimage.cpp b/indra/llui/lluiimage.cpp new file mode 100644 index 0000000000..0ed2283742 --- /dev/null +++ b/indra/llui/lluiimage.cpp @@ -0,0 +1,158 @@ +/** + * @file lluiimage.cpp + * @brief UI implementation + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Utilities functions the user interface needs + +//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +// Project includes +#include "lluiimage.h" +#include "llui.h" + +LLUIImage::LLUIImage(const std::string& name, LLPointer image) : + mName(name), + mImage(image), + mScaleRegion(0.f, 1.f, 1.f, 0.f), + mClipRegion(0.f, 1.f, 1.f, 0.f), + mUniformScaling(TRUE), + mNoClip(TRUE) +{ +} + +void LLUIImage::setClipRegion(const LLRectf& region) +{ + mClipRegion = region; + mNoClip = mClipRegion.mLeft == 0.f + && mClipRegion.mRight == 1.f + && mClipRegion.mBottom == 0.f + && mClipRegion.mTop == 1.f; +} + +void LLUIImage::setScaleRegion(const LLRectf& region) +{ + mScaleRegion = region; + mUniformScaling = mScaleRegion.mLeft == 0.f + && mScaleRegion.mRight == 1.f + && mScaleRegion.mBottom == 0.f + && mScaleRegion.mTop == 1.f; +} + +//TODO: move drawing implementation inside class +void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const +{ + gl_draw_image(x, y, mImage, color, mClipRegion); +} + +void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ + if (mUniformScaling) + { + gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion); + } + else + { + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + FALSE, + mClipRegion, + mScaleRegion); + } +} + +void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + TRUE, + mClipRegion, + mScaleRegion); +} + +void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const +{ + LLRect border_rect; + border_rect.setOriginAndSize(x, y, width, height); + border_rect.stretch(border_width, border_width); + drawSolid(border_rect, color); +} + +S32 LLUIImage::getWidth() const +{ + // return clipped dimensions of actual image area + return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth()); +} + +S32 LLUIImage::getHeight() const +{ + // return clipped dimensions of actual image area + return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight()); +} + +S32 LLUIImage::getTextureWidth() const +{ + return mImage->getWidth(0); +} + +S32 LLUIImage::getTextureHeight() const +{ + return mImage->getHeight(0); +} + +namespace LLInitParam +{ + LLUIImage* TypedParam::getValueFromBlock() const + { + LLUIImage* imagep = LLUI::getUIImage(name()); + if (!imagep) + { + // default to current value + imagep = mData.mValue; + } + return imagep; + } + + template<> + bool ParamCompare::equals( + LLUIImage* const &a, + LLUIImage* const &b) + { + // force all LLUIImages for XML UI export to be "non-default" + return false; + } +} diff --git a/indra/llui/lluiimage.h b/indra/llui/lluiimage.h new file mode 100644 index 0000000000..cd660a0954 --- /dev/null +++ b/indra/llui/lluiimage.h @@ -0,0 +1,113 @@ +/** + * @file lluiimage.h + * @brief wrapper for images used in the UI that handles smart scaling, etc. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLUIIMAGE_H +#define LL_LLUIIMAGE_H + +#include "llgl.h" +#include "llimagegl.h" +#include "llrefcount.h" +#include "llrect.h" +#include +#include "llinitparam.h" + +extern const LLColor4 UI_VERTEX_COLOR; + +class LLUIImage : public LLRefCount +{ +public: + LLUIImage(const std::string& name, LLPointer image); + + void setClipRegion(const LLRectf& region); + void setScaleRegion(const LLRectf& region); + + LLPointer getImage() { return mImage; } + const LLPointer& 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 mImage; + BOOL mUniformScaling; + BOOL mNoClip; +}; + +namespace LLInitParam +{ + template<> + class TypedParam, false> + : public BlockValue + { + typedef boost::add_reference::type>::type T_const_ref; + typedef BlockValue super_t; + public: + Optional name; + + TypedParam(BlockDescriptor& descriptor, const std::string& name, super_t::value_assignment_t value, ParamDescriptor::validation_func_t func) + : super_t(descriptor, name, value, func) + { + } + + LLUIImage* getValueFromBlock() const; + }; + + // Need custom comparison function for our test app, which only loads + // LLUIImage* as NULL. + template<> + bool ParamCompare::equals( + LLUIImage* const &a, LLUIImage* const &b); +} + +typedef LLPointer LLUIImagePtr; +#endif diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index 0b76b8e814..ce73990d27 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "lluistring.h" #include "llsd.h" +#include "lltrans.h" const LLStringUtil::format_map_t LLUIString::sNullArgs; @@ -112,6 +113,10 @@ void LLUIString::clear() void LLUIString::format() { mResult = mOrig; - LLStringUtil::format(mResult, mArgs); + + // get the defailt args + local args + LLStringUtil::format_map_t combined_args = LLTrans::getDefaultArgs(); + combined_args.insert(mArgs.begin(), mArgs.end()); + LLStringUtil::format(mResult, combined_args); mWResult = utf8str_to_wstring(mResult); } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 2350ea6050..462fd16b60 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -56,17 +56,18 @@ #include "lltexteditor.h" #include "lltextbox.h" -//HACK: this allows you to instantiate LLView from xml with "" which we don't want -static LLRegisterWidget 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::sPreviewHighlightedElements; +BOOL LLView::sHighlightingDiffs = FALSE; +LLView* LLView::sPreviewClickedElement = NULL; +BOOL LLView::sDrawPreviewHighlights = FALSE; S32 LLView::sLastLeftXML = S32_MIN; S32 LLView::sLastBottomXML = S32_MIN; @@ -74,77 +75,76 @@ S32 LLView::sLastBottomXML = S32_MIN; BOOL LLView::sIsDrawing = FALSE; #endif -LLView::LLView() : - mParentView(NULL), - mReshapeFlags(FOLLOWS_NONE), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(TRUE), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mVisible(TRUE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW) -{ -} - -LLView::LLView(const std::string& name, BOOL mouse_opaque) : +LLView::Params::Params() +: name("name", std::string("unnamed")), + enabled("enabled", true), + visible("visible", true), + mouse_opaque("mouse_opaque", true), + follows("follows"), + hover_cursor("hover_cursor", "UI_CURSOR_ARROW"), + use_bounding_rect("use_bounding_rect", false), + tab_group("tab_group", 0), + default_tab_group("default_tab_group"), + tool_tip("tool_tip"), + sound_flags("sound_flags", MOUSE_UP), + font("font", LLFontGL::getFontSansSerif()), + font_halign("halign"), + font_valign("valign"), + layout("layout"), + rect("rect"), + bottom_delta("bottom_delta", S32_MAX), + left_delta("left_delta", S32_MAX), + top_delta("top_delta"), + right_delta("right_delta"), + center_horiz("center_horiz", false), + center_vert("center_vert", false), + serializable("", false), + user_resize("user_resize"), + auto_resize("auto_resize"), + needs_translate("translate") +{ + addSynonym(rect, ""); +} + +LLView::LLView(const LLView::Params& p) +: mName(p.name), mParentView(NULL), - mName(name), mReshapeFlags(FOLLOWS_NONE), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(mouse_opaque), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), - mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mVisible(TRUE), - mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW) -{ -} - - -LLView::LLView( - const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) : - mParentView(NULL), - mName(name), - mRect(rect), - mBoundingRect(rect), - mReshapeFlags(reshape), - mDefaultTabGroup(0), - mEnabled(TRUE), - mMouseOpaque(mouse_opaque), - mSoundFlags(MOUSE_UP), // default to only make sound on mouse up - mSaveToXML(TRUE), + mSaveToXML(p.serializable), mIsFocusRoot(FALSE), - mLastVisible(TRUE), - mUseBoundingRect(FALSE), - mVisible(TRUE), + mLastVisible(FALSE), mNextInsertionOrdinal(0), - mHoverCursor(UI_CURSOR_ARROW) + mHoverCursor(getCursorFromString(p.hover_cursor)), + mEnabled(p.enabled), + mVisible(p.visible), + mMouseOpaque(p.mouse_opaque), + mSoundFlags(p.sound_flags), + mUseBoundingRect(p.use_bounding_rect), + mDefaultTabGroup(p.default_tab_group), + mLastTabGroup(0), + mToolTipMsg((LLStringExplicit)p.tool_tip()) { + // create rect first, as this will supply initial follows flags + setShape(p.rect); + parseFollowsFlags(p); } - LLView::~LLView() { //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl; // llassert(LLView::sIsDrawing == FALSE); + +// llassert_always(sDepth == 0); // avoid deleting views while drawing! It can subtly break list iterators + if( gFocusMgr.getKeyboardFocus() == this ) { - llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; + //llwarns << "View holding keyboard focus deleted: " << getName() << ". Keyboard focus removed." << llendl; gFocusMgr.removeKeyboardFocusWithoutCallback( this ); } if( hasMouseCapture() ) { - llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; + //llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; gFocusMgr.removeMouseCaptureWithoutCallback( this ); } @@ -155,14 +155,6 @@ LLView::~LLView() mParentView->removeChild(this); } - dispatch_list_t::iterator itor; - for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor) - { - (*itor).second->clearDispatchers(); - } - - std::for_each(mFloaterControls.begin(), mFloaterControls.end(), - DeletePairedPointer()); std::for_each(mDummyWidgets.begin(), mDummyWidgets.end(), DeletePairedPointer()); } @@ -185,7 +177,6 @@ BOOL LLView::isPanel() const return FALSE; } -// virtual void LLView::setToolTip(const LLStringExplicit& msg) { mToolTipMsg = msg; @@ -232,19 +223,31 @@ const std::string& LLView::getName() const void LLView::sendChildToFront(LLView* child) { +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child && child->getParent() == this) { - mChildList.remove( child ); - mChildList.push_front(child); + // minor optimization, but more importantly, + // won't temporarily create an empty list + if (child != mChildList.front()) + { + mChildList.remove( child ); + mChildList.push_front(child); + } } } void LLView::sendChildToBack(LLView* child) { +// llassert_always(sDepth == 0); // Avoid re-ordering while drawing; it can cause subtle iterator bugs if (child && child->getParent() == this) { - mChildList.remove( child ); - mChildList.push_back(child); + // minor optimization, but more importantly, + // won't temporarily create an empty list + if (child != mChildList.back()) + { + mChildList.remove( child ); + mChildList.push_back(child); + } } } @@ -264,12 +267,46 @@ void LLView::moveChildToBackOfTabGroup(LLUICtrl* child) } } -void LLView::addChild(LLView* child, S32 tab_group) +void LLView::addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node) +{ + if (node.isNull()) return; + + for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) + { + LLXMLNodePtr outputChild; + if (output_node) + { + outputChild = output_node->createChild("", FALSE); + } + + if (!LLUICtrlFactory::getInstance()->createFromXML(child_node, this, LLStringUtil::null, outputChild)) + { + std::string child_name = std::string(child_node->getName()->mString); + if (child_name.find(".") == std::string::npos) + { + llwarns << "Could not create widget named " << child_node->getName()->mString << llendl; + } + } + + if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty()) + { + output_node->deleteChild(outputChild); + } + } +} + +// virtual +bool LLView::addChild(LLView* child, S32 tab_group) { + if (!child) + { + return false; + } if (mParentView == child) { llerrs << "Adding view " << child->getName() << " as child of itself" << llendl; } + // remove from current parent if (child->mParentView) { @@ -282,55 +319,46 @@ void LLView::addChild(LLView* child, S32 tab_group) // add to ctrl list if is LLUICtrl if (child->isCtrl()) { - // controls are stored in reverse order from render order - addCtrlAtEnd((LLUICtrl*) child, tab_group); + LLUICtrl* ctrl = static_cast(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(child)); + if(found != mCtrlOrder.end()) + { + mCtrlOrder.erase(found); + } } } else @@ -340,28 +368,6 @@ void LLView::removeChild(LLView* child, BOOL deleteIt) updateBoundingRect(); } -void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group) -{ - mCtrlOrder.insert(tab_order_pair_t(ctrl, - tab_order_t(tab_group, mNextInsertionOrdinal++))); -} - -void LLView::addCtrl( LLUICtrl* ctrl, S32 tab_group) -{ - // add to front of list by using negative ordinal, which monotonically increases - mCtrlOrder.insert(tab_order_pair_t(ctrl, - tab_order_t(tab_group, -1 * mNextInsertionOrdinal++))); -} - -void LLView::removeCtrl(LLUICtrl* ctrl) -{ - child_tab_order_t::iterator found = mCtrlOrder.find(ctrl); - if(found != mCtrlOrder.end()) - { - mCtrlOrder.erase(found); - } -} - LLView::ctrl_list_t LLView::getCtrlList() const { ctrl_list_t controls; @@ -651,7 +657,7 @@ BOOL LLView::canSnapTo(const LLView* other_view) } // virtual -void LLView::snappedTo(const LLView* snap_view) +void LLView::setSnappedTo(const LLView* snap_view) { } @@ -669,6 +675,17 @@ BOOL LLView::handleHover(S32 x, S32 y, MASK mask) return handled; } +void LLView::onMouseEnter(S32 x, S32 y, MASK mask) +{ + //llinfos << "Mouse entered " << getName() << llendl; +} + +void LLView::onMouseLeave(S32 x, S32 y, MASK mask) +{ + //llinfos << "Mouse left " << getName() << llendl; +} + + std::string LLView::getShowNamesToolTip() { LLView* view = getParent(); @@ -729,23 +746,14 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s // get our own tooltip tool_tip = mToolTipMsg.getString(); - if ( - LLUI::sShowXUINames + + if (LLUI::sShowXUINames && (tool_tip.find(".xml", 0) == std::string::npos) && (mName.find("Drag", 0) == std::string::npos)) { tool_tip = getShowNamesToolTip(); } - BOOL show_names_text_box = LLUI::sShowXUINames && dynamic_cast(this) != NULL; - - // don't allow any siblings to handle this event - // even if we don't have a tooltip - if (getMouseOpaque() || show_names_text_box) - { - handled = TRUE; - } - if(!tool_tip.empty()) { msg = tool_tip; @@ -757,7 +765,13 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s localPointToScreen( mRect.getWidth(), mRect.getHeight(), &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); - + } + // don't allow any siblings to handle this event + // even if we don't have a tooltip + if (getMouseOpaque() || + (!tool_tip.empty() && + (!LLUI::sShowXUINames || dynamic_cast(this)))) + { handled = TRUE; } @@ -923,22 +937,22 @@ BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask) handled_view = this; } - // HACK If we're editing UI, select the leaf view that ate the click. - if (sEditingUI && handled_view) - { - // need to find leaf views, big hack - LLButton* buttonp = dynamic_cast(handled_view); - LLLineEditor* line_editorp = dynamic_cast(handled_view); - LLTextEditor* text_editorp = dynamic_cast(handled_view); - LLTextBox* text_boxp = dynamic_cast(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(handled_view); + // LLLineEditor* line_editorp = dynamic_cast(handled_view); + // LLTextEditor* text_editorp = dynamic_cast(handled_view); + // LLTextBox* text_boxp = dynamic_cast(handled_view); + // if (buttonp + // || line_editorp + // || text_editorp + // || text_boxp) + // { + // sEditingUIView = handled_view; + // } + //} return handled; } @@ -1164,6 +1178,7 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask) { sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage; } + handled_view = viewp; break; } @@ -1326,55 +1341,58 @@ void LLView::draw() } } - LLRect rootRect = getRootView()->getRect(); - LLRect screenRect; - - // draw focused control on top of everything else - LLView* focus_view = gFocusMgr.getKeyboardFocus(); - if (focus_view && focus_view->getParent() != this) + if (!mChildList.empty()) { - focus_view = NULL; - } + LLRect rootRect = getRootView()->getRect(); + LLRect screenRect; - ++sDepth; - for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) - { - LLView *viewp = *child_iter; + // draw focused control on top of everything else + LLView* focus_view = gFocusMgr.getKeyboardFocus(); + if (focus_view && focus_view->getParent() != this) + { + focus_view = NULL; + } + + ++sDepth; - if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) + for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) { - // Only draw views that are within the root view - localRectToScreen(viewp->getRect(),&screenRect); - if ( rootRect.rectInRect(&screenRect) ) + child_list_reverse_iter_t child = child_iter++; + LLView *viewp = *child; + + if (viewp->getVisible() && viewp != focus_view && viewp->getRect().isValid()) { - glMatrixMode(GL_MODELVIEW); - LLUI::pushMatrix(); + // Only draw views that are within the root view + localRectToScreen(viewp->getRect(),&screenRect); + if ( rootRect.rectInRect(&screenRect) ) { - LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); - viewp->draw(); + glMatrixMode(GL_MODELVIEW); + LLUI::pushMatrix(); + { + LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); + viewp->draw(); + } + LLUI::popMatrix(); } - LLUI::popMatrix(); } - } - } - --sDepth; + } + --sDepth; - if (focus_view && focus_view->getVisible()) - { - drawChild(focus_view); + if (focus_view && focus_view->getVisible()) + { + drawChild(focus_view); + } } - // HACK - if (sEditingUI && this == sEditingUIView) - { - drawDebugRect(); - } + gGL.getTexUnit(0)->disable(); } //Draw a box for debugging. void LLView::drawDebugRect() { + std::set::iterator preview_iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); // figure out if it's a previewed element + LLUI::pushMatrix(); { // drawing solids requires texturing be disabled @@ -1389,9 +1407,21 @@ void LLView::drawDebugRect() // draw red rectangle for the border LLColor4 border_color(0.f, 0.f, 0.f, 1.f); - if (sEditingUI) + //if (sEditingUI) + //{ + // border_color.mV[0] = 1.f; + //} + if(preview_iter != sPreviewHighlightedElements.end()) { - border_color.mV[0] = 1.f; + if(LLView::sPreviewClickedElement && this == sPreviewClickedElement) + { + border_color = LLColor4::red; + } + else + { + static LLUICachedControl scroll_highlighted_color ("ScrollHighlightedColor", *(new LLColor4)); + border_color = scroll_highlighted_color; + } } else { @@ -1414,8 +1444,8 @@ void LLView::drawDebugRect() gGL.vertex2i(0, debug_rect.getHeight() - 1); gGL.end(); - // Draw the name if it's not a leaf node - if (mChildList.size() && !sEditingUI) + // Draw the name if it's not a leaf node or not in editing or preview mode + if (mChildList.size() && preview_iter == sPreviewHighlightedElements.end()) { //char temp[256]; S32 x, y; @@ -1425,7 +1455,7 @@ void LLView::drawDebugRect() std::string debug_text = llformat("%s (%d x %d)", getName().c_str(), debug_rect.getWidth(), debug_rect.getHeight()); LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color, - LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, + LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); } } @@ -1581,15 +1611,28 @@ void LLView::updateBoundingRect() } } -LLRect LLView::getScreenRect() const +LLRect LLView::calcScreenRect() const { - // *FIX: check for one-off error LLRect screen_rect; localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom); localPointToScreen(getRect().getWidth(), getRect().getHeight(), &screen_rect.mRight, &screen_rect.mTop); return screen_rect; } +LLRect LLView::calcScreenBoundingRect() const +{ + LLRect screen_rect; + // get bounding rect, if used + LLRect bounding_rect = mUseBoundingRect ? mBoundingRect : mRect; + + // convert to local coordinates, as defined by mRect + bounding_rect.translate(-mRect.mLeft, -mRect.mBottom); + + localPointToScreen(bounding_rect.mLeft, bounding_rect.mBottom, &screen_rect.mLeft, &screen_rect.mBottom); + localPointToScreen(bounding_rect.mRight, bounding_rect.mTop, &screen_rect.mRight, &screen_rect.mTop); + return screen_rect; +} + LLRect LLView::getLocalBoundingRect() const { LLRect local_bounding_rect = getBoundingRect(); @@ -1688,7 +1731,12 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ if (create_if_missing) { - return createDummyWidget(name); + LLView* view = getDummyWidget(name); + if (!view) + { + view = LLUICtrlFactory::createDummyWidget(name); + } + return view; } return NULL; } @@ -1777,12 +1825,32 @@ LLView* LLView::getRootView() return view; } -BOOL LLView::deleteViewByHandle(LLHandle 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 handle) { LLView* viewp = handle.get(); delete viewp; - return viewp != NULL; } @@ -1943,132 +2011,6 @@ BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* o return FALSE; } -// virtual -LLXMLNodePtr LLView::getXML(bool save_children) const -{ - //FIXME: need to provide actual derived type tag, probably outside this method - LLXMLNodePtr node = new LLXMLNode("view", FALSE); - - node->createChild("name", TRUE)->setStringValue(getName()); - node->createChild("width", TRUE)->setIntValue(getRect().getWidth()); - node->createChild("height", TRUE)->setIntValue(getRect().getHeight()); - - LLView* parent = getParent(); - S32 left = getRect().mLeft; - S32 bottom = getRect().mBottom; - if (parent) bottom -= parent->getRect().getHeight(); - - node->createChild("left", TRUE)->setIntValue(left); - node->createChild("bottom", TRUE)->setIntValue(bottom); - - U32 follows_flags = getFollows(); - if (follows_flags) - { - std::stringstream buffer; - bool pipe = false; - if (followsLeft()) - { - buffer << "left"; - pipe = true; - } - if (followsTop()) - { - if (pipe) buffer << "|"; - buffer << "top"; - pipe = true; - } - if (followsRight()) - { - if (pipe) buffer << "|"; - buffer << "right"; - pipe = true; - } - if (followsBottom()) - { - if (pipe) buffer << "|"; - buffer << "bottom"; - } - node->createChild("follows", TRUE)->setStringValue(buffer.str()); - } - // Export all widgets as enabled and visible - code must disable. - node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque ); - if (!mToolTipMsg.getString().empty()) - { - node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg.getString()); - } - if (mSoundFlags != MOUSE_UP) - { - node->createChild("sound_flags", TRUE)->setIntValue((S32)mSoundFlags); - } - - node->createChild("enabled", TRUE)->setBoolValue(getEnabled()); - - if (!mControlName.empty()) - { - node->createChild("control_name", TRUE)->setStringValue(mControlName); - } - return node; -} - -//static -LLView* LLView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - LLView* viewp = new LLView(); - viewp->initFromXML(node, parent); - return viewp; -} - -// static -void LLView::addColorXML(LLXMLNodePtr node, const LLColor4& color, - const char* xml_name, const char* control_name) -{ - if (color != LLUI::sColorsGroup->getColor(ll_safe_string(control_name))) - { - node->createChild(xml_name, TRUE)->setFloatValue(4, color.mV); - } -} - -//static -std::string LLView::escapeXML(const std::string& xml, std::string& indent) -{ - std::string ret = indent + "\"" + LLXMLNode::escapeXML(xml); - - //replace every newline with a close quote, new line, indent, open quote - size_t index = ret.size()-1; - size_t fnd; - - while ((fnd = ret.rfind("\n", index)) != std::string::npos) - { - ret.replace(fnd, 1, "\"\n" + indent + "\""); - index = fnd-1; - } - - //append close quote - ret.append("\""); - - return ret; -} - -// static -LLWString LLView::escapeXML(const LLWString& xml) -{ - LLWString out; - for (LLWString::size_type i = 0; i < xml.size(); ++i) - { - llwchar c = xml[i]; - switch(c) - { - case '"': out.append(utf8string_to_wstring(""")); break; - case '\'': out.append(utf8string_to_wstring("'")); break; - case '&': out.append(utf8string_to_wstring("&")); break; - case '<': out.append(utf8string_to_wstring("<")); break; - case '>': out.append(utf8string_to_wstring(">")); break; - default: out.push_back(c); break; - } - } - return out; -} - // static const LLCtrlQuery & LLView::getTabOrderQuery() { @@ -2105,7 +2047,12 @@ const LLCtrlQuery & LLView::getFocusRootsQuery() } -void LLView::userSetShape(const LLRect& new_rect) +void LLView::setShape(const LLRect& new_rect, bool by_user) +{ + handleReshape(new_rect, by_user); +} + +void LLView::handleReshape(const LLRect& new_rect, bool by_user) { reshape(new_rect.getWidth(), new_rect.getHeight()); translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom); @@ -2353,306 +2300,52 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna // Listener dispatch functions //----------------------------------------------------------------------------- -void LLView::registerEventListener(std::string name, LLSimpleListener* function) -{ - mDispatchList.insert(std::pair(name, function)); -} - -void LLView::deregisterEventListener(std::string name) -{ - dispatch_list_t::iterator itor = mDispatchList.find(name); - if (itor != mDispatchList.end()) - { - mDispatchList.erase(itor); - } -} - -std::string LLView::findEventListener(LLSimpleListener *listener) const -{ - dispatch_list_t::const_iterator itor; - for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor) - { - if (itor->second == listener) - { - return itor->first; - } - } - if (mParentView) - { - return mParentView->findEventListener(listener); - } - return LLStringUtil::null; -} - -LLSimpleListener* LLView::getListenerByName(const std::string& callback_name) -{ - LLSimpleListener* callback = NULL; - dispatch_list_t::iterator itor = mDispatchList.find(callback_name); - if (itor != mDispatchList.end()) - { - callback = itor->second; - } - else if (mParentView) - { - callback = mParentView->getListenerByName(callback_name); - } - return callback; -} LLControlVariable *LLView::findControl(const std::string& name) { - control_map_t::iterator itor = mFloaterControls.find(name); - if (itor != mFloaterControls.end()) + LLControlVariable* control; + control = LLUI::sSettingGroups["color"]->getControl(name); + if (control) { - return itor->second; + return control; } - if (mParentView) - { - return mParentView->findControl(name); - } - return LLUI::sConfigGroup->getControl(name); + + return LLUI::sSettingGroups["config"]->getControl(name); } const S32 FLOATER_H_MARGIN = 15; const S32 MIN_WIDGET_HEIGHT = 10; const S32 VPAD = 4; -// static -U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect) -{ - U32 follows = 0; - S32 x = rect.mLeft; - S32 y = rect.mBottom; - S32 w = rect.getWidth(); - S32 h = rect.getHeight(); - - U32 last_x = 0; - U32 last_y = 0; - if (parent_view) - { - last_y = parent_view->getRect().getHeight(); - child_list_t::const_iterator itor = parent_view->getChildList()->begin(); - if (itor != parent_view->getChildList()->end()) - { - LLView *last_view = (*itor); - if (last_view->getSaveToXML()) - { - last_x = last_view->getRect().mLeft; - last_y = last_view->getRect().mBottom; - } - } - } - - std::string rect_control; - node->getAttributeString("rect_control", rect_control); - if (! rect_control.empty()) - { - LLRect rect = LLUI::sConfigGroup->getRect(rect_control); - x = rect.mLeft; - y = rect.mBottom; - w = rect.getWidth(); - h = rect.getHeight(); - } - - if (node->hasAttribute("left")) - { - node->getAttributeS32("left", x); - } - if (node->hasAttribute("bottom")) - { - node->getAttributeS32("bottom", y); - } - - // Make your width the width of the containing - // view if you don't specify a width. - if (parent_view) - { - if(w == 0) - { - w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x); - } - - if(h == 0) - { - h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight()); - } - } - - if (node->hasAttribute("width")) - { - node->getAttributeS32("width", w); - } - if (node->hasAttribute("height")) - { - node->getAttributeS32("height", h); - } - - if (parent_view) - { - if (node->hasAttribute("left_delta")) - { - S32 left_delta = 0; - node->getAttributeS32("left_delta", left_delta); - x = last_x + left_delta; - } - else if (node->hasAttribute("left") && node->hasAttribute("right")) - { - // compute width based on left and right - S32 right = 0; - node->getAttributeS32("right", right); - if (right < 0) - { - right = parent_view->getRect().getWidth() + right; - } - w = right - x; - } - else if (node->hasAttribute("left")) - { - if (x < 0) - { - x = parent_view->getRect().getWidth() + x; - follows |= FOLLOWS_RIGHT; - } - else - { - follows |= FOLLOWS_LEFT; - } - } - else if (node->hasAttribute("width") && node->hasAttribute("right")) - { - S32 right = 0; - node->getAttributeS32("right", right); - if (right < 0) - { - right = parent_view->getRect().getWidth() + right; - } - x = right - w; - } - else - { - // left not specified, same as last - x = last_x; - } - - if (node->hasAttribute("bottom_delta")) - { - S32 bottom_delta = 0; - node->getAttributeS32("bottom_delta", bottom_delta); - y = last_y + bottom_delta; - } - else if (node->hasAttribute("top")) - { - // compute height based on top - S32 top = 0; - node->getAttributeS32("top", top); - if (top < 0) - { - top = parent_view->getRect().getHeight() + top; - } - h = top - y; - } - else if (node->hasAttribute("bottom")) - { - if (y < 0) - { - y = parent_view->getRect().getHeight() + y; - follows |= FOLLOWS_TOP; - } - else - { - follows |= FOLLOWS_BOTTOM; - } - } - else - { - // if bottom not specified, generate automatically - if (last_y == 0) - { - // treat first child as "bottom" - y = parent_view->getRect().getHeight() - (h + VPAD); - follows |= FOLLOWS_TOP; - } - else - { - // treat subsequent children as "bottom_delta" - y = last_y - (h + VPAD); - } - } - } - else - { - x = llmax(x, 0); - y = llmax(y, 0); - follows = FOLLOWS_LEFT | FOLLOWS_TOP; - } - rect.setOriginAndSize(x, y, w, h); - - return follows; -} - -void LLView::initFromXML(LLXMLNodePtr node, LLView* parent) +void LLView::initFromParams(const LLView::Params& params) { - // create rect first, as this will supply initial follows flags - LLRect view_rect; - U32 follows_flags = createRect(node, view_rect, parent, getRequiredRect()); - // call reshape in case there are any child elements that need to be layed out - reshape(view_rect.getWidth(), view_rect.getHeight()); - setRect(view_rect); - setFollows(follows_flags); - - parseFollowsFlags(node); + LLRect required_rect = getRequiredRect(); - if (node->hasAttribute("control_name")) - { - std::string control_name; - node->getAttributeString("control_name", control_name); - setControlName(control_name, NULL); - } + S32 width = llmax(getRect().getWidth(), required_rect.getWidth()); + S32 height = llmax(getRect().getHeight(), required_rect.getHeight()); - if (node->hasAttribute("tool_tip")) - { - std::string tool_tip_msg; - node->getAttributeString("tool_tip", tool_tip_msg); - setToolTip(tool_tip_msg); - } + reshape(width, height); - if (node->hasAttribute("enabled")) - { - BOOL enabled; - node->getAttributeBOOL("enabled", enabled); - setEnabled(enabled); - } - - if (node->hasAttribute("visible")) - { - BOOL visible; - node->getAttributeBOOL("visible", visible); - setVisible(visible); - } + // call virtual methods with most recent data + // use getters because these values might not come through parameter block + setEnabled(getEnabled()); + setVisible(getVisible()); - if (node->hasAttribute("hover_cursor")) + if (!params.name().empty()) { - std::string cursor_string; - node->getAttributeString("hover_cursor", cursor_string); - mHoverCursor = getCursorFromString(cursor_string); + setName(params.name()); } - - node->getAttributeBOOL("use_bounding_rect", mUseBoundingRect); - node->getAttributeBOOL("mouse_opaque", mMouseOpaque); - node->getAttributeS32("default_tab_group", mDefaultTabGroup); - - reshape(view_rect.getWidth(), view_rect.getHeight()); + mLayout = params.layout(); } -void LLView::parseFollowsFlags(LLXMLNodePtr node) +void LLView::parseFollowsFlags(const LLView::Params& params) { - if (node->hasAttribute("follows")) + if (params.follows.string.isProvided()) { - setFollowsNone(); + setFollows(FOLLOWS_NONE); - std::string follows; - node->getAttributeString("follows", follows); + std::string follows = params.follows.string; typedef boost::tokenizer > tokenizer; boost::char_separator sep("|"); @@ -2685,45 +2378,13 @@ void LLView::parseFollowsFlags(LLXMLNodePtr node) ++token_iter; } } -} - -// static -LLFontGL* LLView::selectFont(LLXMLNodePtr node) -{ - std::string font_name, font_size, font_style; - U8 style = 0; - - if (node->hasAttribute("font")) - { - node->getAttributeString("font", font_name); - } - - if (node->hasAttribute("font_size")) - { - node->getAttributeString("font_size", font_size); - } - - if (node->hasAttribute("font_style")) - { - node->getAttributeString("font_style", font_style); - style = LLFontGL::getStyleFromString(font_style); - } - - if (node->hasAttribute("font-style")) + else if (params.follows.flags.isProvided()) { - node->getAttributeString("font-style", font_style); - style = LLFontGL::getStyleFromString(font_style); + setFollows(params.follows.flags); } - - if (font_name.empty()) - return NULL; - - LLFontDescriptor desc(font_name, font_size, style); - LLFontGL* gl_font = LLFontGL::getFont(desc); - - return gl_font; } + // static LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) { @@ -2738,175 +2399,216 @@ LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node) return gl_hfont_align; } -// static -LLFontGL::VAlign LLView::selectFontVAlign(LLXMLNodePtr node) +//static +void LLView::setupParams(LLView::Params& p, LLView* parent) { - LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE; + const S32 VPAD = 4; + const S32 MIN_WIDGET_HEIGHT = 10; + + p.serializable(true); + + // *NOTE: Do not inherit layout from parent until we re-export + // all nodes and make topleft the default. JC + //if (p.layout().empty() && parent) + // p.layout = parent->getLayout(); - if (node->hasAttribute("valign")) + if (parent) { - std::string vert_align_name; - node->getAttributeString("valign", vert_align_name); - gl_vfont_align = LLFontGL::vAlignFromName(vert_align_name); - } - return gl_vfont_align; -} + LLRect parent_rect = parent->getLocalRect(); + // overwrite uninitialized rect params, using context + LLRect last_rect = parent->getLocalRect(); -// static -LLFontGL::StyleFlags LLView::selectFontStyle(LLXMLNodePtr node) -{ - LLFontGL::StyleFlags gl_font_style = LLFontGL::NORMAL; + bool layout_topleft = (p.layout() == "topleft"); + if (layout_topleft) + { + //invert top to bottom + if (p.rect.top.isProvided()) p.rect.top = parent_rect.getHeight() - p.rect.top; + if (p.rect.bottom.isProvided()) p.rect.bottom = parent_rect.getHeight() - p.rect.bottom; + } - if (node->hasAttribute("style")) - { - std::string style_flags_name; - node->getAttributeString("style", style_flags_name); + // convert negative or centered coordinates to parent relative values + // Note: some of this logic matches the logic in TypedParam::getValueFromBlock() - if (style_flags_name == "normal") + if (p.center_horiz) { - gl_font_style = LLFontGL::NORMAL; + if (p.rect.left.isProvided() && p.rect.right.isProvided()) + { + S32 width = p.rect.right - p.rect.left; + width = llmax(width, 0); + S32 offset = parent_rect.getWidth()/2 - width/2; + p.rect.left = p.rect.left + offset; + p.rect.right = p.rect.right + offset; + } + else + { + p.rect.left = p.rect.left + parent_rect.getWidth()/2 - p.rect.width/2; + } } - else if (style_flags_name == "bold") + else { - gl_font_style = LLFontGL::BOLD; + if (p.rect.left < 0) p.rect.left = p.rect.left + parent_rect.getWidth(); + if (p.rect.right < 0) p.rect.right = p.rect.right + parent_rect.getWidth(); } - else if (style_flags_name == "italic") + if (p.center_vert) { - gl_font_style = LLFontGL::ITALIC; + if (p.rect.bottom.isProvided() && p.rect.top.isProvided()) + { + S32 height = p.rect.top - p.rect.bottom; + height = llmax(height, 0); + S32 offset = parent_rect.getHeight()/2 - height/2; + p.rect.bottom = p.rect.bottom + offset; + p.rect.top = p.rect.top + offset; + } + else + { + p.rect.bottom = p.rect.bottom + parent_rect.getHeight()/2 - p.rect.height/2; + } } - else if (style_flags_name == "underline") + else { - gl_font_style = LLFontGL::UNDERLINE; + if (p.rect.bottom < 0) p.rect.bottom = p.rect.bottom + parent_rect.getHeight(); + if (p.rect.top < 0) p.rect.top = p.rect.top + parent_rect.getHeight(); } - //else leave left - } - return gl_font_style; -} - -bool LLView::setControlValue(const LLSD& value) -{ - std::string ctrlname = getControlName(); - if (!ctrlname.empty()) - { - LLUI::sConfigGroup->setValue(ctrlname, value); - return true; - } - return false; -} -//virtual -void LLView::setControlName(const std::string& control_name, LLView *context) -{ - if (context == NULL) - { - context = this; - } - if (!mControlName.empty()) - { - llwarns << "setControlName called twice on same control!" << llendl; - mControlConnection.disconnect(); // disconnect current signal - mControlName.clear(); - } - - // Register new listener - if (!control_name.empty()) - { - LLControlVariable *control = context->findControl(control_name); - if (control) + // DEPRECATE: automatically fall back to height of MIN_WIDGET_HEIGHT pixels + if (!p.rect.height.isProvided() && !p.rect.top.isProvided()) { - mControlName = control_name; - mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _1, getHandle(), std::string("value"))); - setValue(control->getValue()); + p.rect.height = MIN_WIDGET_HEIGHT; } - } -} -// static -bool LLView::controlListener(const LLSD& newvalue, LLHandle handle, std::string type) -{ - LLView* view = handle.get(); - if (view) - { - if (type == "value") + last_rect.translate(0, last_rect.getHeight()); + + LLView::child_list_t::const_iterator itor = parent->getChildList()->begin(); + for (;itor != parent->getChildList()->end(); ++itor) { - view->setValue(newvalue); - return true; + LLView *last_view = (*itor); + if (last_view->getSaveToXML()) + { + last_rect = last_view->getRect(); + break; + } } - else if (type == "enabled") + + if (layout_topleft) { - view->setEnabled(newvalue.asBoolean()); - return true; + S32 left_delta = 0; + p.bottom_delta.setIfNotProvided(0, false); + + // Invert the sense of bottom_delta for topleft layout + if (p.bottom_delta.isProvided()) + { + p.bottom_delta = -p.bottom_delta; + } + else if (p.top_delta.isProvided()) + { + p.bottom_delta = -(p.rect.height + p.top_delta); + } + else if (!p.left_delta.isProvided() && !p.right_delta.isProvided() && !p.top_delta.isProvided()) + { + // set default position is just below last rect + p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false); + } + + // *TODO: Add left_pad for padding off the last widget's right edge + // if (p.left_pad.isProvided()) + //{ + // left_delta = p.left_pad + last_rect.getWidth(); + //} + //else if ... + if (p.left_delta.isProvided()) + { + left_delta = p.left_delta; + } + else if (p.right_delta.isProvided()) + { + left_delta = -(p.right_delta + p.rect.width); + } + + last_rect.translate(left_delta, p.bottom_delta); } - else if (type == "visible") - { - view->setVisible(newvalue.asBoolean()); - return true; + else + { + // set default position is just below last rect + p.bottom_delta.setIfNotProvided(-(p.rect.height + VPAD), false); + p.left_delta.setIfNotProvided(0, false); + last_rect.translate(p.left_delta, p.bottom_delta); } - } - return false; -} -void LLView::addBoolControl(const std::string& name, bool initial_value) -{ - mFloaterControls[name] = new LLControlVariable(name, TYPE_BOOLEAN, initial_value, std::string("Internal floater control")); -} + // this handles case where *both* x and x_delta are provided + // ignore x in favor of default x + x_delta + if (p.bottom_delta.isProvided()) p.rect.bottom.set(0, false); + if (p.left_delta.isProvided()) p.rect.left.set(0, false); -LLControlVariable *LLView::getControl(const std::string& name) -{ - control_map_t::iterator itor = mFloaterControls.find(name); - if (itor != mFloaterControls.end()) - { - return itor->second; + // selectively apply rectangle defaults, making sure that + // params are not flagged as having been "provided" + // as rect params are overconstrained and rely on provided flags + p.rect.left.setIfNotProvided(last_rect.mLeft, false); + p.rect.bottom.setIfNotProvided(last_rect.mBottom, false); + p.rect.top.setIfNotProvided(last_rect.mTop, false); + p.rect.right.setIfNotProvided(last_rect.mRight, false); + p.rect.width.setIfNotProvided(last_rect.getWidth(), false); + p.rect.height.setIfNotProvided(last_rect.getHeight(), false); } - return NULL; -} - -//virtual -void LLView::setValue(const LLSD& value) -{ } -//virtual -LLSD LLView::getValue() const +static S32 invert_vertical(S32 y, LLView* parent) { - return LLSD(); + if (y < 0) + { + // already based on top-left, just invert + return -y; + } + else if (parent) + { + // use parent to flip coordinate + S32 parent_height = parent->getRect().getHeight(); + return parent_height - y; + } + else + { + llwarns << "Attempting to convert layout to top-left with no parent" << llendl; + return y; + } } -LLView* LLView::createWidget(LLXMLNodePtr xml_node) const +//static +void LLView::setupParamsForExport(Params& p, LLView* parent) { - // forward requests to ui ctrl factory - return LLUICtrlFactory::getInstance()->createCtrlWidget(NULL, xml_node); -} - -// -// LLWidgetClassRegistry -// - -LLWidgetClassRegistry::LLWidgetClassRegistry() -{ -} + // Don't convert if already top-left based + if (p.layout() == "topleft") + { + return; + } -void LLWidgetClassRegistry::registerCtrl(const std::string& tag, LLWidgetClassRegistry::factory_func_t function) -{ - std::string lower_case_tag = tag; - LLStringUtil::toLower(lower_case_tag); - - mCreatorFunctions[lower_case_tag] = function; + if (p.rect.top.isProvided()) + { + p.rect.top = invert_vertical(p.rect.top, parent); + } + if (p.top_delta.isProvided()) + { + p.top_delta = -p.top_delta; + } + if (p.rect.bottom.isProvided()) + { + p.rect.bottom = invert_vertical(p.rect.bottom, parent); + } + if (p.bottom_delta.isProvided()) + { + p.bottom_delta = -p.bottom_delta; + } + p.layout = "topleft"; } -BOOL LLWidgetClassRegistry::isTagRegistered(const std::string &tag) +LLView::tree_iterator_t LLView::beginTree() { - return mCreatorFunctions.find(tag) != mCreatorFunctions.end(); + return tree_iterator_t(this, + boost::bind(boost::mem_fn(&LLView::beginChild), _1), + boost::bind(boost::mem_fn(&LLView::endChild), _1)); } -LLWidgetClassRegistry::factory_func_t LLWidgetClassRegistry::getCreatorFunc(const std::string& ctrl_type) +LLView::tree_iterator_t LLView::endTree() { - factory_map_t::const_iterator found_it = mCreatorFunctions.find(ctrl_type); - if (found_it == mCreatorFunctions.end()) - { - return NULL; - } - return found_it->second; + // an empty iterator is an "end" iterator + return tree_iterator_t(); } - diff --git a/indra/llui/llview.h b/indra/llui/llview.h index e0e0f6ba47..69ae7dd993 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -47,12 +47,15 @@ #include "llrect.h" #include "llui.h" #include "lluistring.h" -#include "lluixmltags.h" #include "llviewquery.h" #include "llxmlnode.h" #include "stdenums.h" #include "lluistring.h" #include "llcursortypes.h" +#include "lluictrlfactory.h" +#include "lltreeiterators.h" + +#include const U32 FOLLOWS_NONE = 0x00; const U32 FOLLOWS_LEFT = 0x01; @@ -75,9 +78,6 @@ virtual BOOL isPanel(); LLPanel virtual void setRect(const LLRect &rect); LLLineEditor -virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group); -virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); -virtual void removeCtrl( LLUICtrl* ctrl); LLPanel virtual BOOL canFocusChildren() const { return TRUE; } LLFolderView @@ -103,7 +103,7 @@ virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); LLUICtrl, et. al. virtual void translate( S32 x, S32 y ); LLMenuGL -virtual void userSetShape(const LLRect& new_rect); +virtual void setShape(const LLRect& new_rect, bool by_user); LLFloater, LLScrollLIstVtrl virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0); virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0); @@ -121,10 +121,6 @@ virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,EDragAndDropTy virtual void draw(); * - * -virtual LLXMLNodePtr getXML(bool save_children = true) const; - * -virtual void initFromXML(LLXMLNodePtr node, LLView* parent); * virtual void onFocusLost() {} LLUICtrl, LLScrollListCtrl, LLMenuGL, LLLineEditor, LLComboBox @@ -132,14 +128,8 @@ virtual void onFocusReceived() {} LLUICtrl, LLTextEditor, LLScrollListVtrl, LLMenuGL, LLLineEditor virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; LLTabContainer, LLPanel, LLMenuGL -virtual void setControlName(const std::string& control, LLView *context); - LLSliderCtrl, LLCheckBoxCtrl -virtual std::string getControlName() const { return mControlName; } - LLSliderCtrl, LLCheckBoxCtrl virtual bool handleEvent(LLPointer event, const LLSD& userdata); LLMenuItem -virtual void setValue(const LLSD& value); - * protected: virtual BOOL handleKeyHere(KEY key, MASK mask); @@ -148,67 +138,65 @@ virtual BOOL handleUnicodeCharHere(llwchar uni_char); * */ -class LLUICtrlFactory; - -// maps xml strings to widget classes -class LLWidgetClassRegistry : public LLSingleton +class LLView : public LLMouseHandler, public LLMortician { - friend class LLSingleton; public: - typedef LLView* (*factory_func_t)(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - typedef std::map 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 std::string getTag() + struct Follows : public LLInitParam::Choice { - 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 ctrl_name_set_t; - ctrl_name_set_t mUICtrlNames; + Option string; + Option flags; - // map of xml tags to widget creator functions - factory_map_t mCreatorFunctions; -}; + Follows() + : string(""), + flags("flags", FOLLOWS_LEFT | FOLLOWS_TOP) + {} + }; -template -class LLRegisterWidget -{ -public: - LLRegisterWidget(const std::string& tag) + struct Params : public LLInitParam::Block { - LLWidgetClassRegistry* registry = LLWidgetClassRegistry::getInstance(); - if (registry->isTagRegistered(tag)) - { - //error! - llerrs << "Widget named " << tag << " already registered!" << llendl; - } - else - { - registry->registerCtrl(tag, T::fromXML); - } - } -}; + Mandatory name; + + Optional enabled, + visible; + Optional mouse_opaque; + Optional use_bounding_rect; + Optional tab_group, + default_tab_group; + Optional tool_tip; + + Optional sound_flags; + Optional serializable; + Optional follows; + Optional hover_cursor; + + // font params + Optional font; + Optional font_halign; + Optional font_valign; + + Optional layout; + Optional rect; + Optional top_delta, + bottom_delta, + right_delta, + left_delta; + + Optional center_horiz, + center_vert; + + // these are nested attributes for LLLayoutPanel + //FIXME: get parent context involved in parsing traversal + Deprecated user_resize, + auto_resize, + needs_translate; + + Params(); + }; + void initFromParams(const LLView::Params&); -class LLView : public LLMouseHandler, public LLMortician -{ +protected: + LLView(const LLView::Params&); + friend class LLUICtrlFactory; public: #if LL_DEBUG @@ -253,10 +241,6 @@ public: typedef child_tab_order_t::reverse_iterator child_tab_order_reverse_iter_t; typedef child_tab_order_t::const_reverse_iterator child_tab_order_const_reverse_iter_t; - LLView(); - LLView(const std::string& name, BOOL mouse_opaque); - LLView(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows=FOLLOWS_NONE); - virtual ~LLView(); // Hack to support LLFocusMgr (from LLMouseHandler) @@ -300,15 +284,21 @@ public: void sendChildToBack(LLView* child); void moveChildToFrontOfTabGroup(LLUICtrl* child); void moveChildToBackOfTabGroup(LLUICtrl* child); + + void addChildren(LLXMLNodePtr node, LLXMLNodePtr output_node = NULL); + + virtual bool addChild(LLView* view, S32 tab_group = 0); + + // implemented in terms of addChild() + bool addChildInBack(LLView* view, S32 tab_group = 0); - void addChild(LLView* view, S32 tab_group = 0); - void addChildAtEnd(LLView* view, S32 tab_group = 0); // remove the specified child from the view, and set it's parent to NULL. - void removeChild(LLView* view, BOOL deleteIt = FALSE); + virtual void removeChild(LLView* view); + + // helper function for lluictrlfactory.h create<> template + void setParent(LLView* parent) { if (parent) parent->addChild(this); } - virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group); - virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); - virtual void removeCtrl( LLUICtrl* ctrl); + virtual BOOL postBuild() { return TRUE; } child_tab_order_t getCtrlOrder() const { return mCtrlOrder; } ctrl_list_t getCtrlList() const; @@ -316,6 +306,7 @@ public: void setDefaultTabGroup(S32 d) { mDefaultTabGroup = d; } S32 getDefaultTabGroup() const { return mDefaultTabGroup; } + S32 getLastTabGroup() { return mLastTabGroup; } BOOL isInVisibleChain() const; BOOL isInEnabledChain() const; @@ -347,7 +338,7 @@ public: virtual void onVisibilityChange ( BOOL curVisibilityIn ); void pushVisible(BOOL visible) { mLastVisible = mVisible; setVisible(visible); } - void popVisible() { setVisible(mLastVisible); mLastVisible = TRUE; } + void popVisible() { setVisible(mLastVisible); } LLHandle getHandle() { mHandle.bind(this); return mHandle; } @@ -361,11 +352,14 @@ public: const LLRect& getRect() const { return mRect; } const LLRect& getBoundingRect() const { return mBoundingRect; } LLRect getLocalBoundingRect() const; - LLRect getScreenRect() const; + LLRect calcScreenRect() const; + LLRect calcScreenBoundingRect() const; LLRect getLocalRect() const; virtual LLRect getSnapRect() const; LLRect getLocalSnapRect() const; + std::string getLayout() { return mLayout; } + // Override and return required size for this object. 0 for width/height means don't care. virtual LLRect getRequiredRect(); void updateBoundingRect(); @@ -373,12 +367,17 @@ public: LLView* getRootView(); LLView* getParent() const { return mParentView; } LLView* getFirstChild() const { return (mChildList.empty()) ? NULL : *(mChildList.begin()); } + LLView* findPrevSibling(LLView* child); + LLView* findNextSibling(LLView* child); S32 getChildCount() const { return (S32)mChildList.size(); } template 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 tree_iterator_t; + tree_iterator_t beginTree(); + tree_iterator_t endTree(); // // UTILITIES @@ -391,13 +390,11 @@ public: BOOL translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside ); void centerWithin(const LLRect& bounds); - virtual void userSetShape(const LLRect& new_rect); + void setShape(const LLRect& new_rect, bool by_user = false); virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0); virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0); - virtual BOOL canSnapTo(const LLView* other_view); - - virtual void snappedTo(const LLView* snap_view); + virtual void setSnappedTo(const LLView* snap_view); virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); @@ -407,15 +404,11 @@ public: EAcceptance* accept, std::string& tooltip_msg); - std::string getShowNamesToolTip(); + virtual std::string getShowNamesToolTip(); virtual void draw(); - virtual LLXMLNodePtr getXML(bool save_children = true) const; - //FIXME: make LLView non-instantiable from XML - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory); - virtual void initFromXML(LLXMLNodePtr node, LLView* parent); - void parseFollowsFlags(LLXMLNodePtr node); + void parseFollowsFlags(const LLView::Params& params); // Some widgets, like close box buttons, don't need to be saved BOOL getSaveToXML() const { return mSaveToXML; } @@ -440,25 +433,16 @@ public: void screenRectToLocal( const LLRect& screen, LLRect* local ) const; void localRectToScreen( const LLRect& local, LLRect* screen ) const; - // Listener dispatching functions (Dispatcher deletes pointers to listeners on deregistration or destruction) - LLSimpleListener* getListenerByName(const std::string& callback_name); - void registerEventListener(std::string name, LLSimpleListener* function); - void deregisterEventListener(std::string name); - std::string findEventListener(LLSimpleListener *listener) const; - void addListenerToControl(LLEventDispatcher *observer, const std::string& name, LLSD filter, LLSD userdata); - - void addBoolControl(const std::string& name, bool initial_value); - LLControlVariable *getControl(const std::string& name); LLControlVariable *findControl(const std::string& name); - bool setControlValue(const LLSD& value); - virtual void setControlName(const std::string& control, LLView *context); - virtual std::string getControlName() const { return mControlName; } + // Moved setValue(), getValue(), setControlValue(), setControlName(), + // controlListener() to LLUICtrl because an LLView is NOT assumed to + // contain a value. If that's what you want, use LLUICtrl instead. // virtual bool handleEvent(LLPointer event, const LLSD& userdata); - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; const child_list_t* getChildList() const { return &mChildList; } + const child_list_const_iter_t beginChild() { return mChildList.begin(); } + const child_list_const_iter_t endChild() { return mChildList.end(); } // LLMouseHandler functions // Default behavior is to pass events to children @@ -479,26 +463,20 @@ public: /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const; /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; - template 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 T* findChild(const std::string& name, BOOL recurse = TRUE) const { LLView* child = getChildView(name, recurse, FALSE); T* result = dynamic_cast(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(name); - } - } return result; } + template T* getChild(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; + template T& getChildRef(const std::string& name, BOOL recurse = TRUE) const { return *getChild(name, recurse, TRUE); @@ -506,39 +484,6 @@ public: virtual LLView* getChildView(const std::string& name, BOOL recurse = TRUE, BOOL create_if_missing = TRUE) const; - template T* createDummyWidget(const std::string& name) const - { - T* widget = getDummyWidget(name); - if (!widget) - { - // get xml tag name corresponding to requested widget type (e.g. "button") - std::string xml_tag = LLWidgetClassRegistry::getInstance()->getTag(); - if (xml_tag.empty()) - { - llwarns << "No xml tag registered for this class " << llendl; - return NULL; - } - // create dummy xml node (