summaryrefslogtreecommitdiff
path: root/indra/llui/llfloater.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/llui/llfloater.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/llui/llfloater.cpp')
-rw-r--r--indra/llui/llfloater.cpp7470
1 files changed, 3735 insertions, 3735 deletions
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 48693c6267..aa8f2ad04b 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1,3735 +1,3735 @@
-/**
- * @file llfloater.cpp
- * @brief LLFloater base class
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-// Floating "windows" within the GL display, like the inventory floater,
-// mini-map floater, etc.
-
-#include "linden_common.h"
-#include "llviewereventrecorder.h"
-#include "llfloater.h"
-
-#include "llfocusmgr.h"
-
-#include "lluictrlfactory.h"
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "llcriticaldamp.h" // LLSmoothInterpolation
-#include "lldir.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"
-#include "llwindow.h"
-#include "llstl.h"
-#include "llcontrol.h"
-#include "lltabcontainer.h"
-#include "v2math.h"
-#include "lltrans.h"
-#include "llhelp.h"
-#include "llmultifloater.h"
-#include "llsdutil.h"
-#include "lluiusage.h"
-
-
-// use this to control "jumping" behavior when Ctrl-Tabbing
-const S32 TABBED_FLOATER_OFFSET = 0;
-
-const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f;
-const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f;
-const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f;
-
-namespace LLInitParam
-{
- void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()
- {
- declare("relative", LLFloaterEnums::POSITIONING_RELATIVE);
- declare("cascading", LLFloaterEnums::POSITIONING_CASCADING);
- declare("centered", LLFloaterEnums::POSITIONING_CENTERED);
- declare("specified", LLFloaterEnums::POSITIONING_SPECIFIED);
- }
-}
-
-std::string LLFloater::sButtonNames[BUTTON_COUNT] =
-{
- "llfloater_close_btn", //BUTTON_CLOSE
- "llfloater_restore_btn", //BUTTON_RESTORE
- "llfloater_minimize_btn", //BUTTON_MINIMIZE
- "llfloater_tear_off_btn", //BUTTON_TEAR_OFF
- "llfloater_dock_btn", //BUTTON_DOCK
- "llfloater_help_btn" //BUTTON_HELP
-};
-
-std::string LLFloater::sButtonToolTips[BUTTON_COUNT];
-
-std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]=
-{
-#ifdef LL_DARWIN
- "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE
-#else
- "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE
-#endif
- "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE
- "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE
- "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF
- "BUTTON_DOCK",
- "BUTTON_HELP"
-};
-
-LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
-{
- LLFloater::onClickClose, //BUTTON_CLOSE
- LLFloater::onClickMinimize, //BUTTON_RESTORE
- LLFloater::onClickMinimize, //BUTTON_MINIMIZE
- LLFloater::onClickTearOff, //BUTTON_TEAR_OFF
- LLFloater::onClickDock, //BUTTON_DOCK
- LLFloater::onClickHelp //BUTTON_HELP
-};
-
-LLMultiFloater* LLFloater::sHostp = NULL;
-bool LLFloater::sQuitting = false; // Flag to prevent storing visibility controls while quitting
-
-LLFloaterView* gFloaterView = NULL;
-
-/*==========================================================================*|
-// DEV-38598: The fundamental problem with this operation is that it can only
-// support a subset of LLSD values. While it's plausible to compare two arrays
-// lexicographically, what strict ordering can you impose on maps?
-// (LLFloaterTOS's current key is an LLSD map.)
-
-// Of course something like this is necessary if you want to build a std::set
-// or std::map with LLSD keys. Fortunately we're getting by with other
-// container types for now.
-
-//static
-bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
-{
- if (a.type() != b.type())
- {
- //LL_ERRS() << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << LL_ENDL;
- 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)
-{
- return llsd_equals(a, b);
-}
-
-//************************************
-
-LLFloater::Params::Params()
-: title("title"),
- short_title("short_title"),
- single_instance("single_instance", false),
- reuse_instance("reuse_instance", 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_dock_state("save_dock_state", false),
- save_rect("save_rect", false),
- save_visibility("save_visibility", false),
- can_dock("can_dock", false),
- show_title("show_title", true),
- auto_close("auto_close", false),
- positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE),
- header_height("header_height", 0),
- legacy_header_height("legacy_header_height", 0),
- close_image("close_image"),
- restore_image("restore_image"),
- minimize_image("minimize_image"),
- tear_off_image("tear_off_image"),
- dock_image("dock_image"),
- help_image("help_image"),
- close_pressed_image("close_pressed_image"),
- restore_pressed_image("restore_pressed_image"),
- minimize_pressed_image("minimize_pressed_image"),
- tear_off_pressed_image("tear_off_pressed_image"),
- dock_pressed_image("dock_pressed_image"),
- help_pressed_image("help_pressed_image"),
- open_callback("open_callback"),
- close_callback("close_callback"),
- follows("follows"),
- rel_x("rel_x", 0),
- rel_y("rel_y", 0)
-{
- changeDefault(visible, false);
-}
-
-
-//static
-const LLFloater::Params& LLFloater::getDefaultParams()
-{
- return LLUICtrlFactory::getDefaultParams<LLFloater>();
-}
-
-//static
-void LLFloater::initClass()
-{
- // translate tooltips for floater buttons
- for (S32 i = 0; i < BUTTON_COUNT; i++)
- {
- sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
- }
-
- LLControlVariable* ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
- if (ctrl)
- {
- ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
- updateActiveFloaterTransparency();
- }
-
- ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
- if (ctrl)
- {
- ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
- updateInactiveFloaterTransparency();
- }
-
-}
-
-// defaults for floater param block pulled from widgets/floater.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater");
-
-LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
-: LLPanel(), // intentionally do not pass params here, see initFromParams
- mDragHandle(NULL),
- mTitle(p.title),
- mShortTitle(p.short_title),
- mSingleInstance(p.single_instance),
- mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default
- mKey(key),
- mCanTearOff(p.can_tear_off),
- mCanMinimize(p.can_minimize),
- mCanClose(p.can_close),
- mDragOnLeft(p.can_drag_on_left),
- mResizable(p.can_resize),
- mAutoClose(p.auto_close),
- mPositioning(p.positioning),
- mMinWidth(p.min_width),
- mMinHeight(p.min_height),
- mHeaderHeight(p.header_height),
- mLegacyHeaderHeight(p.legacy_header_height),
- mDefaultRectForGroup(true),
- mMinimized(false),
- mForeground(false),
- mFirstLook(true),
- mButtonScale(1.0f),
- mAutoFocus(true), // automatically take focus when opened
- mCanDock(false),
- mDocked(false),
- mTornOff(false),
- mHasBeenDraggedWhileMinimized(false),
- mPreviousMinimizedBottom(0),
- mPreviousMinimizedLeft(0),
- mDefaultRelativeX(p.rel_x),
- mDefaultRelativeY(p.rel_y),
- mMinimizeSignal(NULL)
-// mNotificationContext(NULL)
-{
- mPosition.setFloater(*this);
-// mNotificationContext = new LLFloaterNotificationContext(getHandle());
-
- // Clicks stop here.
- setMouseOpaque(true);
-
- // Floaters always draw their background, unlike every other panel.
- setBackgroundVisible(true);
-
- // Floaters start not minimized. When minimized, they save their
- // prior rectangle to be used on restore.
- mExpandedRect.set(0,0,0,0);
-
- memset(mButtonsEnabled, 0, BUTTON_COUNT * sizeof(bool));
- memset(mButtons, 0, BUTTON_COUNT * sizeof(LLButton*));
-
- addDragHandle();
- addResizeCtrls();
-
- initFromParams(p);
-
- initFloater(p);
-}
-
-// Note: Floaters constructed from XML call init() twice!
-void LLFloater::initFloater(const Params& p)
-{
- // Close button.
- if (mCanClose)
- {
- mButtonsEnabled[BUTTON_CLOSE] = true;
- }
-
- // Help button: '?'
- //SL-14050 Disable all Help question marks
- mButtonsEnabled[BUTTON_HELP] = false;
-
- // Minimize button only for top draggers
- if ( !mDragOnLeft && mCanMinimize )
- {
- mButtonsEnabled[BUTTON_MINIMIZE] = true;
- }
-
- if(mCanDock)
- {
- mButtonsEnabled[BUTTON_DOCK] = true;
- }
-
- buildButtons(p);
-
- // Floaters are created in the invisible state
- setVisible(false);
-
- if (!getParent())
- {
- gFloaterView->addChild(this);
- }
-}
-
-void LLFloater::addDragHandle()
-{
- if (!mDragHandle)
- {
- if (mDragOnLeft)
- {
- LLDragHandleLeft::Params p;
- p.name("drag");
- p.follows.flags(FOLLOWS_ALL);
- p.label(mTitle);
- mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p);
- }
- else // drag on top
- {
- LLDragHandleTop::Params p;
- p.name("Drag Handle");
- p.follows.flags(FOLLOWS_ALL);
- p.label(mTitle);
- mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p);
- }
- addChild(mDragHandle);
- }
- layoutDragHandle();
- applyTitle();
-}
-
-void LLFloater::layoutDragHandle()
-{
- static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
- S32 close_box_size = mCanClose ? floater_close_box_size : 0;
-
- LLRect rect;
- if (mDragOnLeft)
- {
- rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
- }
- else // drag on top
- {
- rect = getLocalRect();
- }
- mDragHandle->setShape(rect);
- updateTitleButtons();
-}
-
-// static
-void LLFloater::updateActiveFloaterTransparency()
-{
- static LLCachedControl<F32> active_transparency(*LLUI::getInstance()->mSettingGroups["config"], "ActiveFloaterTransparency", 1.f);
- sActiveControlTransparency = active_transparency;
-}
-
-// static
-void LLFloater::updateInactiveFloaterTransparency()
-{
- static LLCachedControl<F32> inactive_transparency(*LLUI::getInstance()->mSettingGroups["config"], "InactiveFloaterTransparency", 0.95f);
- sInactiveControlTransparency = inactive_transparency;
-}
-
-void LLFloater::addResizeCtrls()
-{
- // Resize bars (sides)
- LLResizeBar::Params p;
- p.name("resizebar_left");
- p.resizing_view(this);
- p.min_size(mMinWidth);
- p.side(LLResizeBar::LEFT);
- mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p);
- addChild( mResizeBar[LLResizeBar::LEFT] );
-
- p.name("resizebar_top");
- p.min_size(mMinHeight);
- p.side(LLResizeBar::TOP);
-
- mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create<LLResizeBar>(p);
- addChild( mResizeBar[LLResizeBar::TOP] );
-
- p.name("resizebar_right");
- p.min_size(mMinWidth);
- p.side(LLResizeBar::RIGHT);
- mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p);
- addChild( mResizeBar[LLResizeBar::RIGHT] );
-
- p.name("resizebar_bottom");
- p.min_size(mMinHeight);
- p.side(LLResizeBar::BOTTOM);
- mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p);
- addChild( mResizeBar[LLResizeBar::BOTTOM] );
-
- // Resize handles (corners)
- LLResizeHandle::Params handle_p;
- // handles must not be mouse-opaque, otherwise they block hover events
- // to other buttons like the close box. JC
- handle_p.mouse_opaque(false);
- handle_p.min_width(mMinWidth);
- handle_p.min_height(mMinHeight);
- handle_p.corner(LLResizeHandle::RIGHT_BOTTOM);
- mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
- addChild(mResizeHandle[0]);
-
- handle_p.corner(LLResizeHandle::RIGHT_TOP);
- mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
- addChild(mResizeHandle[1]);
-
- handle_p.corner(LLResizeHandle::LEFT_BOTTOM);
- mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
- addChild(mResizeHandle[2]);
-
- handle_p.corner(LLResizeHandle::LEFT_TOP);
- mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
- addChild(mResizeHandle[3]);
-
- layoutResizeCtrls();
-}
-
-void LLFloater::layoutResizeCtrls()
-{
- LLRect rect;
-
- // Resize bars (sides)
- const S32 RESIZE_BAR_THICKNESS = 3;
- rect = LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0);
- mResizeBar[LLResizeBar::LEFT]->setRect(rect);
-
- rect = LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS);
- mResizeBar[LLResizeBar::TOP]->setRect(rect);
-
- rect = LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0);
- mResizeBar[LLResizeBar::RIGHT]->setRect(rect);
-
- rect = LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0);
- mResizeBar[LLResizeBar::BOTTOM]->setRect(rect);
-
- // Resize handles (corners)
- rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0);
- mResizeHandle[0]->setRect(rect);
-
- rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT);
- mResizeHandle[1]->setRect(rect);
-
- rect = LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 );
- mResizeHandle[2]->setRect(rect);
-
- rect = LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT );
- mResizeHandle[3]->setRect(rect);
-}
-
-void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)
-{
- mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width);
- mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width);
-
- mResizeBar[LLResizeBar::TOP]->setVisible(enable && height);
- mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height);
-
- mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width);
- mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width);
-
- mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height);
- mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height);
-
- for (S32 i = 0; i < 4; ++i)
- {
- mResizeHandle[i]->setVisible(enable && width && height);
- mResizeHandle[i]->setEnabled(enable && width && height);
- }
-}
-
-void LLFloater::destroy()
-{
- // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before
- // it was deleted via LLMortician::updateClass(). See EXT-8458.
- LLFloaterReg::removeInstance(mInstanceName, mKey);
- die();
-}
-
-// virtual
-LLFloater::~LLFloater()
-{
- if (!isDead())
- {
- // If it's dead, instance is supposed to be already removed, and
- // in case of single instance we can remove new one by accident
- LLFloaterReg::removeInstance(mInstanceName, mKey);
- }
-
- if( gFocusMgr.childHasKeyboardFocus(this))
- {
- // Just in case we might still have focus here, release it.
- releaseFocus();
- }
-
- // This is important so that floaters with persistent rects (i.e., those
- // created with rect control rather than an LLRect) are restored in their
- // correct, non-minimized positions.
- setMinimized( false );
-
- delete mDragHandle;
- for (S32 i = 0; i < 4; i++)
- {
- delete mResizeBar[i];
- delete mResizeHandle[i];
- }
-
- setVisible(false); // We're not visible if we're destroyed
- storeVisibilityControl();
- storeDockStateControl();
- delete mMinimizeSignal;
-}
-
-void LLFloater::storeRectControl()
-{
- if (!mRectControl.empty())
- {
- getControlGroup()->setRect( mRectControl, getRect() );
- }
- if (!mPosXControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE)
- {
- getControlGroup()->setF32( mPosXControl, mPosition.mX );
- }
- if (!mPosYControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE)
- {
- getControlGroup()->setF32( mPosYControl, mPosition.mY );
- }
-}
-
-void LLFloater::storeVisibilityControl()
-{
- if( !sQuitting && mVisibilityControl.size() > 1 )
- {
- getControlGroup()->setBOOL( mVisibilityControl, getVisible() );
- }
-}
-
-void LLFloater::storeDockStateControl()
-{
- if( !sQuitting && mDocStateControl.size() > 1 )
- {
- getControlGroup()->setBOOL( mDocStateControl, isDocked() );
- }
-}
-
-// static
-std::string LLFloater::getControlName(const std::string& name, const LLSD& key)
-{
- std::string ctrl_name = name;
-
- // Add the key to the control name if appropriate.
- if (key.isString() && !key.asString().empty())
- {
- ctrl_name += "_" + key.asString();
- }
-
- return ctrl_name;
-}
-
-// static
-LLControlGroup* LLFloater::getControlGroup()
-{
- // Floater size, position, visibility, etc are saved in per-account settings.
- return LLUI::getInstance()->mSettingGroups["account"];
-}
-
-void LLFloater::setVisible( bool visible )
-{
- LLPanel::setVisible(visible); // calls onVisibilityChange()
- if( visible && mFirstLook )
- {
- mFirstLook = false;
- }
-
- if( !visible )
- {
- LLUI::getInstance()->removePopup(this);
-
- if( gFocusMgr.childHasMouseCapture( this ) )
- {
- gFocusMgr.setMouseCapture(NULL);
- }
- }
-
- for(handle_set_iter_t dependent_it = mDependents.begin();
- dependent_it != mDependents.end(); )
- {
- LLFloater* floaterp = dependent_it->get();
-
- if (floaterp)
- {
- floaterp->setVisible(visible);
- }
- ++dependent_it;
- }
-
- storeVisibilityControl();
-}
-
-
-void LLFloater::setIsSingleInstance(bool is_single_instance)
-{
- mSingleInstance = is_single_instance;
- if (!mIsReuseInitialized)
- {
- mReuseInstance = is_single_instance; // reuse single-instance floaters by default
- }
-}
-
-
-// virtual
-void LLFloater::onVisibilityChange ( bool new_visibility )
-{
- if (new_visibility)
- {
- if (getHost())
- getHost()->setFloaterFlashing(this, false);
- }
- LLPanel::onVisibilityChange ( new_visibility );
-}
-
-void LLFloater::openFloater(const LLSD& key)
-{
- LL_INFOS() << "Opening floater " << getName() << " full path: " << getPathname() << LL_ENDL;
-
- LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), true,"floater"); // Last param is event subtype or empty string
-
- mKey = key; // in case we need to open ourselves again
-
- if (getSoundFlags() != SILENT
- // don't play open sound for hosted (tabbed) windows
- && !getHost()
- && !getFloaterHost()
- && (!getVisible() || isMinimized()))
- {
- make_ui_sound("UISndWindowOpen");
- }
-
- //RN: for now, we don't allow rehosting from one multifloater to another
- // just need to fix the bugs
- if (getFloaterHost() != NULL && getHost() == NULL)
- {
- // needs a host
- // only select tabs if window they are hosted in is visible
- getFloaterHost()->addFloater(this, getFloaterHost()->getVisible());
- }
-
- if (getHost() != NULL)
- {
- getHost()->setMinimized(false);
- getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
- getHost()->showFloater(this);
- }
- else
- {
- LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
- if (!floater_to_stack)
- {
- floater_to_stack = LLFloaterReg::getLastFloaterCascading();
- }
- applyControlsAndPosition(floater_to_stack);
- setMinimized(false);
- setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
- }
-
- mOpenSignal(this, key);
- onOpen(key);
-
- dirtyRect();
-}
-
-void LLFloater::closeFloater(bool app_quitting)
-{
- LL_INFOS() << "Closing floater " << getName() << LL_ENDL;
- LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string
- if (app_quitting)
- {
- LLFloater::sQuitting = true;
- }
-
- // Always unminimize before trying to close.
- // Most of the time the user will never see this state.
- setMinimized(false);
-
- if (canClose())
- {
- if (getHost())
- {
- ((LLMultiFloater*)getHost())->removeFloater(this);
- gFloaterView->addChild(this);
- }
-
- if (getSoundFlags() != SILENT
- && getVisible()
- && !getHost()
- && !app_quitting)
- {
- make_ui_sound("UISndWindowClose");
- }
-
- gFocusMgr.clearLastFocusForGroup(this);
-
- if (hasFocus())
- {
- // Do this early, so UI controls will commit before the
- // window is taken down.
- releaseFocus();
-
- // give focus to dependee floater if it exists, and we had focus first
- if (isDependent())
- {
- LLFloater* dependee = mDependeeHandle.get();
- if (dependee && !dependee->isDead())
- {
- dependee->setFocus(true);
- }
- }
- }
-
-
- //If floater is a dependent, remove it from parent (dependee)
- LLFloater* dependee = mDependeeHandle.get();
- if (dependee)
- {
- dependee->removeDependentFloater(this);
- }
-
- // now close dependent floater
- while(mDependents.size() > 0)
- {
- handle_set_iter_t dependent_it = mDependents.begin();
- LLFloater* floaterp = dependent_it->get();
- // normally removeDependentFloater will do this, but in
- // case floaterp is somehow invalid or orphaned, erase now
- mDependents.erase(dependent_it);
- if (floaterp)
- {
- floaterp->mDependeeHandle = LLHandle<LLFloater>();
- floaterp->closeFloater(app_quitting);
- }
- }
-
- cleanupHandles();
-
- dirtyRect();
-
- // Close callbacks
- onClose(app_quitting);
- mCloseSignal(this, LLSD(app_quitting));
-
- // Hide or Destroy
- if (mSingleInstance)
- {
- // Hide the instance
- if (getHost())
- {
- getHost()->setVisible(false);
- }
- else
- {
- setVisible(false);
- if (!mReuseInstance)
- {
- destroy();
- }
- }
- }
- else
- {
- setVisible(false); // hide before destroying (so onVisibilityChange() gets called)
- if (!mReuseInstance)
- {
- destroy();
- }
- }
- }
-}
-
-/*virtual*/
-void LLFloater::closeHostedFloater()
-{
- // When toggling *visibility*, close the host instead of the floater when hosted
- if (getHost())
- {
- getHost()->closeFloater();
- }
- else
- {
- closeFloater();
- }
-}
-
-/*virtual*/
-void LLFloater::reshape(S32 width, S32 height, bool called_from_parent)
-{
- LLPanel::reshape(width, height, called_from_parent);
-}
-
-// virtual
-void LLFloater::translate(S32 x, S32 y)
-{
- LLView::translate(x, y);
-
- if (!mTranslateWithDependents || mDependents.empty())
- return;
-
- for (const LLHandle<LLFloater>& handle : mDependents)
- {
- LLFloater* floater = handle.get();
- if (floater && floater->getSnapTarget() == getHandle())
- {
- floater->LLView::translate(x, y);
- }
- }
-}
-
-void LLFloater::releaseFocus()
-{
- LLUI::getInstance()->removePopup(this);
-
- setFocus(false);
-
- if( gFocusMgr.childHasMouseCapture( this ) )
- {
- gFocusMgr.setMouseCapture(NULL);
- }
-}
-
-
-void LLFloater::setResizeLimits( S32 min_width, S32 min_height )
-{
- mMinWidth = min_width;
- mMinHeight = min_height;
-
- for( S32 i = 0; i < 4; i++ )
- {
- if( mResizeBar[i] )
- {
- if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
- {
- mResizeBar[i]->setResizeLimits( min_width, S32_MAX );
- }
- else
- {
- mResizeBar[i]->setResizeLimits( min_height, S32_MAX );
- }
- }
- if( mResizeHandle[i] )
- {
- mResizeHandle[i]->setResizeLimits( min_width, min_height );
- }
- }
-}
-
-
-void LLFloater::center()
-{
- if(getHost())
- {
- // hosted floaters can't move
- return;
- }
- centerWithin(gFloaterView->getRect());
-}
-
-LLMultiFloater* LLFloater::getHost()
-{
- return (LLMultiFloater*)mHostHandle.get();
-}
-
-void LLFloater::applyControlsAndPosition(LLFloater* other)
-{
- if (!applyDockState())
- {
- if (!applyRectControl())
- {
- applyPositioning(other, true);
- }
- }
-}
-
-bool LLFloater::applyRectControl()
-{
- bool saved_rect = false;
-
- LLRect screen_rect = calcScreenRect();
- mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
-
- LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
- if (last_in_group && last_in_group != this)
- {
- // other floaters in our group, position ourselves relative to them and don't save the rect
- if (mDefaultRectForGroup)
- {
- mRectControl.clear();
- }
- mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;
- }
- else
- {
- bool rect_specified = false;
- if (!mRectControl.empty())
- {
- // If we have a saved rect, use it
- const LLRect& rect = getControlGroup()->getRect(mRectControl);
- if (rect.notEmpty()) saved_rect = true;
- if (saved_rect)
- {
- setOrigin(rect.mLeft, rect.mBottom);
-
- if (mResizable)
- {
- reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
- }
- mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
- LLRect screen_rect = calcScreenRect();
- mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
- rect_specified = true;
- }
- }
-
- LLControlVariablePtr x_control = getControlGroup()->getControl(mPosXControl);
- LLControlVariablePtr y_control = getControlGroup()->getControl(mPosYControl);
- if (x_control.notNull()
- && y_control.notNull()
- && !x_control->isDefault()
- && !y_control->isDefault())
- {
- mPosition.mX = x_control->getValue().asReal();
- mPosition.mY = y_control->getValue().asReal();
- mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
- applyRelativePosition();
-
- saved_rect = true;
- }
- else if ((mDefaultRelativeX != 0) && (mDefaultRelativeY != 0))
- {
- mPosition.mX = mDefaultRelativeX;
- mPosition.mY = mDefaultRelativeY;
- mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
- applyRelativePosition();
-
- saved_rect = true;
- }
-
- // remember updated position
- if (rect_specified)
- {
- storeRectControl();
- }
- }
-
- if (saved_rect)
- {
- // propagate any derived positioning data back to settings file
- storeRectControl();
- }
-
-
- return saved_rect;
-}
-
-bool LLFloater::applyDockState()
-{
- bool docked = false;
-
- if (mDocStateControl.size() > 1)
- {
- docked = getControlGroup()->getBOOL(mDocStateControl);
- setDocked(docked);
- }
-
- return docked;
-}
-
-void LLFloater::applyPositioning(LLFloater* other, bool on_open)
-{
- // Otherwise position according to the positioning code
- switch (mPositioning)
- {
- case LLFloaterEnums::POSITIONING_CENTERED:
- center();
- break;
-
- case LLFloaterEnums::POSITIONING_SPECIFIED:
- break;
-
- case LLFloaterEnums::POSITIONING_CASCADING:
- if (!on_open)
- {
- applyRelativePosition();
- }
- // fall through
- case LLFloaterEnums::POSITIONING_CASCADE_GROUP:
- if (on_open)
- {
- if (other != NULL && other != this)
- {
- stackWith(*other);
- }
- else
- {
- static const U32 CASCADING_FLOATER_HOFFSET = 0;
- static const U32 CASCADING_FLOATER_VOFFSET = 0;
-
- const LLRect& snap_rect = gFloaterView->getSnapRect();
-
- const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET;
- const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET;
-
- S32 rect_height = getRect().getHeight();
- setOrigin(horizontal_offset, vertical_offset - rect_height);
-
- translate(snap_rect.mLeft, snap_rect.mBottom);
- }
- setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
- }
- break;
-
- case LLFloaterEnums::POSITIONING_RELATIVE:
- {
- applyRelativePosition();
-
- break;
- }
- default:
- // Do nothing
- break;
- }
-}
-
-void LLFloater::applyTitle()
-{
- if (!mDragHandle)
- {
- return;
- }
-
- if (isMinimized() && !mShortTitle.empty())
- {
- mDragHandle->setTitle( mShortTitle );
- }
- else
- {
- mDragHandle->setTitle ( mTitle );
- }
-
- if (getHost())
- {
- getHost()->updateFloaterTitle(this);
- }
-}
-
-std::string LLFloater::getCurrentTitle() const
-{
- return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
-}
-
-void LLFloater::setTitle( const std::string& title )
-{
- mTitle = title;
- applyTitle();
-}
-
-std::string LLFloater::getTitle() const
-{
- if (mTitle.empty())
- {
- return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
- }
- else
- {
- return mTitle;
- }
-}
-
-void LLFloater::setShortTitle( const std::string& short_title )
-{
- mShortTitle = short_title;
- applyTitle();
-}
-
-std::string LLFloater::getShortTitle() const
-{
- if (mShortTitle.empty())
- {
- return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
- }
- else
- {
- return mShortTitle;
- }
-}
-
-bool LLFloater::canSnapTo(const LLView* other_view)
-{
- if (NULL == other_view)
- {
- LL_WARNS() << "other_view is NULL" << LL_ENDL;
- return false;
- }
-
- if (other_view != getParent())
- {
- const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view);
- if (other_floaterp
- && other_floaterp->getSnapTarget() == getHandle()
- && mDependents.find(other_floaterp->getHandle()) != mDependents.end())
- {
- // this is a dependent that is already snapped to us, so don't snap back to it
- return false;
- }
- }
-
- return LLPanel::canSnapTo(other_view);
-}
-
-void LLFloater::setSnappedTo(const LLView* snap_view)
-{
- if (!snap_view || snap_view == getParent())
- {
- clearSnapTarget();
- }
- else
- {
- //RN: assume it's a floater as it must be a sibling to our parent floater
- const LLFloater* floaterp = dynamic_cast<const LLFloater*>(snap_view);
- if (floaterp)
- {
- setSnapTarget(floaterp->getHandle());
- }
- }
-}
-
-void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
-{
- const LLRect old_rect = getRect();
- LLView::handleReshape(new_rect, by_user);
-
- if (by_user && !getHost())
- {
- LLFloaterView * floaterVp = dynamic_cast<LLFloaterView*>(getParent());
- if (floaterVp)
- {
- floaterVp->adjustToFitScreen(this, !isMinimized());
- }
- }
-
- // if not minimized, adjust all snapped dependents to new shape
- if (!isMinimized())
- {
- if (by_user)
- {
- if (isDocked())
- {
- setDocked( false, false);
- }
- mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
- LLRect screen_rect = calcScreenRect();
- mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
- }
- storeRectControl();
-
- // gather all snapped dependents
- for(handle_set_iter_t dependent_it = mDependents.begin();
- dependent_it != mDependents.end(); ++dependent_it)
- {
- LLFloater* floaterp = dependent_it->get();
- // is a dependent snapped to us?
- if (floaterp && floaterp->getSnapTarget() == getHandle())
- {
- S32 delta_x = 0;
- S32 delta_y = 0;
- // check to see if it snapped to right or top, and move if dependee floater is resizing
- LLRect dependent_rect = floaterp->getRect();
- if (dependent_rect.mLeft - getRect().mLeft >= old_rect.getWidth() || // dependent on my right?
- dependent_rect.mRight == getRect().mLeft + old_rect.getWidth()) // dependent aligned with my right
- {
- // was snapped directly onto right side or aligned with it
- delta_x += new_rect.getWidth() - old_rect.getWidth();
- }
- if (dependent_rect.mBottom - getRect().mBottom >= old_rect.getHeight() ||
- dependent_rect.mTop == getRect().mBottom + old_rect.getHeight())
- {
- // was snapped directly onto top side or aligned with it
- delta_y += new_rect.getHeight() - old_rect.getHeight();
- }
-
- // take translation of dependee floater into account as well
- delta_x += new_rect.mLeft - old_rect.mLeft;
- delta_y += new_rect.mBottom - old_rect.mBottom;
-
- dependent_rect.translate(delta_x, delta_y);
- floaterp->setShape(dependent_rect, by_user);
- }
- }
- }
- else
- {
- // If minimized, and origin has changed, set
- // mHasBeenDraggedWhileMinimized to true
- if ((new_rect.mLeft != old_rect.mLeft) ||
- (new_rect.mBottom != old_rect.mBottom))
- {
- mHasBeenDraggedWhileMinimized = true;
- }
- }
-}
-
-void LLFloater::setMinimized(bool minimize)
-{
- const LLFloater::Params& default_params = LLFloater::getDefaultParams();
- S32 floater_header_size = default_params.header_height;
- static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
-
- if (minimize == mMinimized) return;
-
- if (mMinimizeSignal)
- {
- (*mMinimizeSignal)(this, LLSD(minimize));
- }
-
- if (minimize)
- {
- // minimized flag should be turned on before release focus
- mMinimized = true;
- mExpandedRect = getRect();
-
- // If the floater has been dragged while minimized in the
- // past, then locate it at its previous minimized location.
- // Otherwise, ask the view for a minimize position.
- if (mHasBeenDraggedWhileMinimized)
- {
- setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
- }
- else
- {
- S32 left, bottom;
- gFloaterView->getMinimizePosition(&left, &bottom);
- setOrigin( left, bottom );
- }
-
- if (mButtonsEnabled[BUTTON_MINIMIZE])
- {
- mButtonsEnabled[BUTTON_MINIMIZE] = false;
- mButtonsEnabled[BUTTON_RESTORE] = true;
- }
-
- setBorderVisible(true);
-
- for(handle_set_iter_t dependent_it = mDependents.begin();
- dependent_it != mDependents.end();
- ++dependent_it)
- {
- LLFloater* floaterp = dependent_it->get();
- if (floaterp)
- {
- if (floaterp->isMinimizeable())
- {
- floaterp->setMinimized(true);
- }
- else if (!floaterp->isMinimized())
- {
- floaterp->setVisible(false);
- }
- }
- }
-
- // Lose keyboard focus when minimized
- releaseFocus();
-
- for (S32 i = 0; i < 4; i++)
- {
- if (mResizeBar[i] != NULL)
- {
- mResizeBar[i]->setEnabled(false);
- }
- if (mResizeHandle[i] != NULL)
- {
- mResizeHandle[i]->setEnabled(false);
- }
- }
-
- // Reshape *after* setting mMinimized
- reshape( minimized_width, floater_header_size, true);
- }
- else
- {
- // If this window has been dragged while minimized (at any time),
- // remember its position for the next time it's minimized.
- if (mHasBeenDraggedWhileMinimized)
- {
- const LLRect& currentRect = getRect();
- mPreviousMinimizedLeft = currentRect.mLeft;
- mPreviousMinimizedBottom = currentRect.mBottom;
- }
-
- setOrigin( mExpandedRect.mLeft, mExpandedRect.mBottom );
- if (mButtonsEnabled[BUTTON_RESTORE])
- {
- mButtonsEnabled[BUTTON_MINIMIZE] = true;
- mButtonsEnabled[BUTTON_RESTORE] = false;
- }
-
- // show dependent floater
- for(handle_set_iter_t dependent_it = mDependents.begin();
- dependent_it != mDependents.end();
- ++dependent_it)
- {
- LLFloater* floaterp = dependent_it->get();
- if (floaterp)
- {
- floaterp->setMinimized(false);
- floaterp->setVisible(true);
- }
- }
-
- for (S32 i = 0; i < 4; i++)
- {
- if (mResizeBar[i] != NULL)
- {
- mResizeBar[i]->setEnabled(isResizable());
- }
- if (mResizeHandle[i] != NULL)
- {
- mResizeHandle[i]->setEnabled(isResizable());
- }
- }
-
- mMinimized = false;
- setFrontmost();
- // Reshape *after* setting mMinimized
- reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), true );
- }
-
- make_ui_sound("UISndWindowClose");
- updateTitleButtons();
- applyTitle ();
-}
-
-void LLFloater::setFocus( bool b )
-{
- if (b && getIsChrome())
- {
- return;
- }
- LLView* last_focus = gFocusMgr.getLastFocusForGroup(this);
- // a descendent already has focus
- bool child_had_focus = hasFocus();
-
- // give focus to first valid descendent
- LLPanel::setFocus(b);
-
- if (b)
- {
- // only push focused floaters to front of stack if not in midst of ctrl-tab cycle
- LLFloaterView * parent = dynamic_cast<LLFloaterView *>(getParent());
- if (!getHost() && parent && !parent->getCycleMode())
- {
- if (!isFrontmost())
- {
- setFrontmost();
- }
- }
-
- // when getting focus, delegate to last descendent which had focus
- if (last_focus && !child_had_focus &&
- last_focus->isInEnabledChain() &&
- last_focus->isInVisibleChain())
- {
- // *FIX: should handle case where focus doesn't stick
- last_focus->setFocus(true);
- }
- }
- updateTransparency(b ? TT_ACTIVE : TT_INACTIVE);
-}
-
-// virtual
-void LLFloater::setRect(const LLRect &rect)
-{
- LLPanel::setRect(rect);
- layoutDragHandle();
- layoutResizeCtrls();
-}
-
-// virtual
-void LLFloater::setIsChrome(bool is_chrome)
-{
- // chrome floaters don't take focus at all
- if (is_chrome)
- {
- // remove focus if we're changing to chrome
- setFocus(false);
- // can't Ctrl-Tab to "chrome" floaters
- setFocusRoot(false);
- mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome)));
- }
-
- LLPanel::setIsChrome(is_chrome);
-}
-
-// Change the draw style to account for the foreground state.
-void LLFloater::setForeground(bool front)
-{
- if (front != mForeground)
- {
- mForeground = front;
- if (mDragHandle)
- mDragHandle->setForeground( front );
-
- if (!front)
- {
- releaseFocus();
- }
-
- setBackgroundOpaque( front );
- }
-}
-
-void LLFloater::cleanupHandles()
-{
- // remove handles to non-existent dependents
- for(handle_set_iter_t dependent_it = mDependents.begin();
- dependent_it != mDependents.end(); )
- {
- LLFloater* floaterp = dependent_it->get();
- if (!floaterp)
- {
- dependent_it = mDependents.erase(dependent_it);
- }
- else
- {
- ++dependent_it;
- }
- }
-}
-
-void LLFloater::setHost(LLMultiFloater* host)
-{
- if (mHostHandle.isDead() && host)
- {
- // make buttons smaller for hosted windows to differentiate from parent
- mButtonScale = 0.9f;
-
- // add tear off button
- if (mCanTearOff)
- {
- mButtonsEnabled[BUTTON_TEAR_OFF] = true;
- }
- }
- else if (!mHostHandle.isDead() && !host)
- {
- mButtonScale = 1.f;
- //mButtonsEnabled[BUTTON_TEAR_OFF] = false;
- }
- if (host)
- {
- mHostHandle = host->getHandle();
- mLastHostHandle = host->getHandle();
- }
- else
- {
- mHostHandle.markDead();
- }
-
- updateTitleButtons();
-}
-
-void LLFloater::moveResizeHandlesToFront()
-{
- for( S32 i = 0; i < 4; i++ )
- {
- if( mResizeBar[i] )
- {
- sendChildToFront(mResizeBar[i]);
- }
- }
-
- for( S32 i = 0; i < 4; i++ )
- {
- if( mResizeHandle[i] )
- {
- sendChildToFront(mResizeHandle[i]);
- }
- }
-}
-
-/*virtual*/
-bool LLFloater::isFrontmost()
-{
- LLFloaterView* floater_view = getParentByType<LLFloaterView>();
- return getVisible()
- && (floater_view
- && floater_view->getFrontmost() == this);
-}
-
-void LLFloater::addDependentFloater(LLFloater* floaterp, bool reposition, bool resize)
-{
- mDependents.insert(floaterp->getHandle());
- floaterp->mDependeeHandle = getHandle();
-
- if (reposition)
- {
- LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp);
- if (resize)
- {
- const LLRect& base = getRect();
- if (rect.mTop == base.mTop)
- rect.mBottom = base.mBottom;
- else if (rect.mLeft == base.mLeft)
- rect.mRight = base.mRight;
- floaterp->reshape(rect.getWidth(), rect.getHeight(), false);
- }
- floaterp->setRect(rect);
- floaterp->setSnapTarget(getHandle());
- }
- gFloaterView->adjustToFitScreen(floaterp, false, true);
- if (floaterp->isFrontmost())
- {
- // make sure to bring self and sibling floaters to front
- gFloaterView->bringToFront(floaterp, floaterp->getAutoFocus() && !getIsChrome());
- }
-}
-
-void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, bool reposition, bool resize)
-{
- LLFloater* dependent_floaterp = dependent.get();
- if(dependent_floaterp)
- {
- addDependentFloater(dependent_floaterp, reposition, resize);
- }
-}
-
-void LLFloater::removeDependentFloater(LLFloater* floaterp)
-{
- mDependents.erase(floaterp->getHandle());
- floaterp->mDependeeHandle = LLHandle<LLFloater>();
-}
-
-void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels)
-{
- LLRect total_rect = getRect();
-
- for (const LLHandle<LLFloater>& handle : mDependents)
- {
- LLFloater* floater = handle.get();
- if (floater && floater->getSnapTarget() == getHandle())
- {
- total_rect.unionWith(floater->getRect());
- }
- }
-
- S32 delta_left = left.notEmpty() ? left.mRight - total_rect.mRight : 0;
- S32 delta_bottom = bottom.notEmpty() ? bottom.mTop - total_rect.mTop : 0;
- S32 delta_right = right.notEmpty() ? right.mLeft - total_rect.mLeft : 0;
-
- // move floater with dependings fully onscreen
- mTranslateWithDependents = true;
- if (translateRectIntoRect(total_rect, constraint, min_overlap_pixels))
- {
- clearSnapTarget();
- }
- else if (delta_left > 0 && total_rect.mTop < left.mTop && total_rect.mBottom > left.mBottom)
- {
- translate(delta_left, 0);
- }
- else if (delta_bottom > 0 && total_rect.mLeft > bottom.mLeft && total_rect.mRight < bottom.mRight)
- {
- translate(0, delta_bottom);
- }
- else if (delta_right < 0 && total_rect.mTop < right.mTop && total_rect.mBottom > right.mBottom)
- {
- translate(delta_right, 0);
- }
- mTranslateWithDependents = false;
-}
-
-bool LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index)
-{
- if( mButtonsEnabled[index] )
- {
- LLButton* my_butt = mButtons[index];
- S32 local_x = x - my_butt->getRect().mLeft;
- S32 local_y = y - my_butt->getRect().mBottom;
-
- if (
- my_butt->pointInView(local_x, local_y) &&
- my_butt->handleMouseDown(local_x, local_y, mask))
- {
- // the button handled it
- return true;
- }
- }
- return false;
-}
-
-bool LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
-{
- LLPanel::handleScrollWheel(x,y,clicks);
- return true;//always
-}
-
-// virtual
-bool LLFloater::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- LL_DEBUGS() << "LLFloater::handleMouseUp calling LLPanel (really LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL;
- bool handled = LLPanel::handleMouseUp(x,y,mask); // Not implemented in LLPanel so this actually calls LLView
- if (handled) {
- LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
- }
- return handled;
-}
-
-// virtual
-bool LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- if( mMinimized )
- {
- // Offer the click to titlebar buttons.
- // Note: this block and the offerClickToButton helper method can be removed
- // because the parent container will handle it for us but we'll keep it here
- // for safety until after reworking the panel code to manage hidden children.
- if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return true;
- if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return true;
- if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return true;
- if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return true;
-
- setFrontmost(true, false);
- // Otherwise pass to drag handle for movement
- return mDragHandle->handleMouseDown(x, y, mask);
- }
- else
- {
- bringToFront( x, y );
- bool handled = LLPanel::handleMouseDown( x, y, mask );
- if (handled) {
- LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
- }
- return handled;
- }
-}
-
-// virtual
-bool LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
- bool was_minimized = mMinimized;
- bringToFront( x, y );
- return was_minimized || LLPanel::handleRightMouseDown( x, y, mask );
-}
-
-bool LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
-{
- bringToFront( x, y );
- return LLPanel::handleMiddleMouseDown( x, y, mask );
-}
-
-
-// virtual
-bool LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
-{
- bool was_minimized = mMinimized;
- setMinimized(false);
- return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
-}
-
-// virtual
-void LLFloater::bringToFront( S32 x, S32 y )
-{
- if (getVisible() && pointInView(x, y))
- {
- LLMultiFloater* hostp = getHost();
- if (hostp)
- {
- hostp->showFloater(this);
- }
- else
- {
- LLFloaterView* parent = dynamic_cast<LLFloaterView*>( getParent() );
- if (parent)
- {
- parent->bringToFront(this, !getIsChrome());
- }
- }
- }
-}
-
-// virtual
-void LLFloater::goneFromFront()
-{
- if (mAutoClose)
- {
- closeFloater();
- }
-}
-
-// virtual
-void LLFloater::setVisibleAndFrontmost(bool take_focus,const LLSD& key)
-{
- LLUIUsage::instance().logFloater(getInstanceName());
- LLMultiFloater* hostp = getHost();
- if (hostp)
- {
- hostp->setVisible(true);
- hostp->setFrontmost(take_focus);
- }
- else
- {
- setVisible(true);
- setFrontmost(take_focus);
- }
-}
-
-void LLFloater::setFrontmost(bool take_focus, bool restore)
-{
- LLMultiFloater* hostp = getHost();
- if (hostp)
- {
- // this will bring the host floater to the front and select
- // the appropriate panel
- hostp->showFloater(this);
- }
- else
- {
- // there are more than one floater view
- // so we need to query our parent directly
- LLFloaterView * parent = dynamic_cast<LLFloaterView*>( getParent() );
- if (parent)
- {
- parent->bringToFront(this, take_focus, restore);
- }
-
- // Make sure to set the appropriate transparency type (STORM-732).
- updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE);
- }
-}
-
-void LLFloater::setCanDock(bool b)
-{
- if(b != mCanDock)
- {
- mCanDock = b;
- if(mCanDock)
- {
- mButtonsEnabled[BUTTON_DOCK] = !mDocked;
- }
- else
- {
- mButtonsEnabled[BUTTON_DOCK] = false;
- }
- }
- updateTitleButtons();
-}
-
-void LLFloater::setDocked(bool docked, bool pop_on_undock)
-{
- if(docked != mDocked && mCanDock)
- {
- mDocked = docked;
- mButtonsEnabled[BUTTON_DOCK] = !mDocked;
-
- if (mDocked)
- {
- setMinimized(false);
- mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
- }
-
- updateTitleButtons();
-
- storeDockStateControl();
- }
-
-}
-
-// static
-void LLFloater::onClickMinimize(LLFloater* self)
-{
- if (!self)
- return;
- self->setMinimized( !self->isMinimized() );
-}
-
-void LLFloater::onClickTearOff(LLFloater* self)
-{
- if (!self)
- return;
- S32 floater_header_size = self->mHeaderHeight;
- LLMultiFloater* host_floater = self->getHost();
- if (host_floater) //Tear off
- {
- LLRect new_rect;
- host_floater->removeFloater(self);
- // reparent to floater view
- gFloaterView->addChild(self);
-
- self->openFloater(self->getKey());
- if (self->mSaveRect && !self->mRectControl.empty())
- {
- self->applyRectControl();
- }
- else
- { // only force position for floaters that don't have that data saved
- 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);
- // give focus to new window to keep continuity for the user
- self->setFocus(true);
- self->setTornOff(true);
- }
- else //Attach to parent.
- {
- LLMultiFloater* new_host = (LLMultiFloater*)self->mLastHostHandle.get();
- if (new_host)
- {
- if (self->mSaveRect)
- {
- LLRect screen_rect = self->calcScreenRect();
- self->mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
- self->storeRectControl();
- }
- self->setMinimized(false); // to reenable minimize button if it was minimized
- new_host->showFloater(self);
- // make sure host is visible
- new_host->openFloater(new_host->getKey());
- }
- self->setTornOff(false);
- }
- self->updateTitleButtons();
- self->setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE);
-}
-
-// static
-void LLFloater::onClickDock(LLFloater* self)
-{
- if(self && self->mCanDock)
- {
- self->setDocked(!self->mDocked, true);
- }
-}
-
-// static
-void LLFloater::onClickHelp( LLFloater* self )
-{
- if (self && LLUI::getInstance()->mHelpImpl)
- {
- // find the current help context for this floater
- std::string help_topic;
- if (self->findHelpTopic(help_topic))
- {
- LLUI::getInstance()->mHelpImpl->showTopic(help_topic);
- }
- }
-}
-
-void LLFloater::initRectControl()
-{
- // save_rect and save_visibility only apply to registered floaters
- if (mSaveRect)
- {
- std::string ctrl_name = getControlName(mInstanceName, mKey);
- mRectControl = LLFloaterReg::declareRectControl(ctrl_name);
- mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name);
- mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name);
- }
-}
-
-// static
-void LLFloater::closeFrontmostFloater()
-{
- LLFloater* floater_to_close = gFloaterView->getFrontmostClosableFloater();
- if(floater_to_close)
- {
- floater_to_close->closeFloater();
- }
-
- // if nothing took focus after closing focused floater
- // give it to next floater (to allow closing multiple windows via keyboard in rapid succession)
- if (gFocusMgr.getKeyboardFocus() == NULL)
- {
- // HACK: use gFloaterView directly in case we are using Ctrl-W to close snapshot window
- // which sits in gSnapshotFloaterView, and needs to pass focus on to normal floater view
- gFloaterView->focusFrontFloater();
- }
-}
-
-
-// static
-void LLFloater::onClickClose( LLFloater* self )
-{
- if (!self)
- return;
- self->onClickCloseBtn();
-}
-
-void LLFloater::onClickCloseBtn(bool app_quitting)
-{
- closeFloater(false);
-}
-
-
-// virtual
-void LLFloater::draw()
-{
- const F32 alpha = getCurrentTransparency();
-
- // draw background
- if( isBackgroundVisible() )
- {
- drawShadow(this);
-
- S32 left = LLPANEL_BORDER_WIDTH;
- S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH;
- S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH;
- S32 bottom = LLPANEL_BORDER_WIDTH;
-
- LLUIImage* image = NULL;
- LLColor4 color;
- LLColor4 overlay_color;
- if (isBackgroundOpaque())
- {
- // NOTE: image may not be set
- image = getBackgroundImage();
- color = getBackgroundColor();
- overlay_color = getBackgroundImageOverlay();
- }
- else
- {
- image = getTransparentImage();
- color = getTransparentColor();
- overlay_color = getTransparentImageOverlay();
- }
-
- if (image)
- {
- // We're using images for this floater's backgrounds
- image->draw(getLocalRect(), overlay_color % alpha);
- }
- else
- {
- // We're not using images, use old-school flat colors
- gl_rect_2d( left, top, right, bottom, color % alpha );
-
- // draw highlight on title bar to indicate focus. RDW
- if(hasFocus()
- && !getIsChrome()
- && !getCurrentTitle().empty())
- {
- static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor");
-
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- LLRect r = getRect();
- gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - font->getLineHeight() - 1,
- titlebar_focus_color % alpha, 0, true);
- }
- }
- }
-
- LLPanel::updateDefaultBtn();
-
- if( getDefaultButton() )
- {
- if (hasFocus() && getDefaultButton()->getEnabled())
- {
- LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
- // is this button a direct descendent and not a nested widget (e.g. checkbox)?
- bool focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this;
- // only enable default button when current focus is not a button
- getDefaultButton()->setBorderEnabled(!focus_is_child_button);
- }
- else
- {
- getDefaultButton()->setBorderEnabled(false);
- }
- }
- if (isMinimized())
- {
- for (S32 i = 0; i < BUTTON_COUNT; i++)
- {
- drawChild(mButtons[i]);
- }
- drawChild(mDragHandle, 0, 0, true);
- }
- else
- {
- // don't call LLPanel::draw() since we've implemented custom background rendering
- LLView::draw();
- }
-
- // update tearoff button for torn off floaters
- // when last host goes away
- if (mCanTearOff && !getHost())
- {
- LLFloater* old_host = mLastHostHandle.get();
- if (!old_host)
- {
- setCanTearOff(false);
- }
- }
-}
-
-void LLFloater::drawShadow(LLPanel* panel)
-{
- S32 left = LLPANEL_BORDER_WIDTH;
- S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH;
- S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
- S32 bottom = LLPANEL_BORDER_WIDTH;
-
- static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0);
- static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow");
- LLColor4 shadow_color = shadow_color_cached;
- F32 shadow_offset = (F32)shadow_offset_S32;
-
- if (!panel->isBackgroundOpaque())
- {
- shadow_offset *= 0.2f;
- shadow_color.mV[VALPHA] *= 0.5f;
- }
- gl_drop_shadow(left, top, right, bottom,
- shadow_color % getCurrentTransparency(),
- ll_round(shadow_offset));
-}
-
-void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type)
-{
- if (!view) return;
- child_list_t children = *view->getChildList();
- child_list_t::iterator it = children.begin();
-
- LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view);
- if (ctrl)
- {
- ctrl->setTransparencyType(transparency_type);
- }
-
- for(; it != children.end(); ++it)
- {
- updateTransparency(*it, transparency_type);
- }
-}
-
-void LLFloater::updateTransparency(ETypeTransparency transparency_type)
-{
- updateTransparency(this, transparency_type);
-}
-
-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);
- }
-
- mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized();
- mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized();
-
- updateTitleButtons();
-}
-
-void LLFloater::setCanClose(bool can_close)
-{
- mCanClose = can_close;
- mButtonsEnabled[BUTTON_CLOSE] = can_close;
-
- updateTitleButtons();
-}
-
-void LLFloater::setCanTearOff(bool can_tear_off)
-{
- mCanTearOff = can_tear_off;
- mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead();
-
- updateTitleButtons();
-}
-
-
-void LLFloater::setCanResize(bool can_resize)
-{
- mResizable = can_resize;
- enableResizeCtrls(can_resize);
-}
-
-void LLFloater::setCanDrag(bool can_drag)
-{
- // if we delete drag handle, we no longer have access to the floater's title
- // so just enable/disable it
- if (!can_drag && mDragHandle->getEnabled())
- {
- mDragHandle->setEnabled(false);
- }
- else if (can_drag && !mDragHandle->getEnabled())
- {
- mDragHandle->setEnabled(true);
- }
-}
-
-bool LLFloater::getCanDrag()
-{
- return mDragHandle->getEnabled();
-}
-
-
-void LLFloater::updateTitleButtons()
-{
- static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
- static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
- LLRect buttons_rect;
- S32 button_count = 0;
- for (S32 i = 0; i < BUTTON_COUNT; i++)
- {
- if (!mButtons[i])
- {
- continue;
- }
-
- bool enabled = mButtonsEnabled[i];
- if (i == BUTTON_HELP)
- {
- // don't show the help button if the floater is minimized
- // or if it is a docked tear-off floater
- if (isMinimized() || (mButtonsEnabled[BUTTON_TEAR_OFF] && ! mTornOff))
- {
- enabled = false;
- }
- }
- if (i == BUTTON_CLOSE && mButtonScale != 1.f)
- {
- //*HACK: always render close button for hosted floaters so
- //that users don't accidentally hit the button when
- //closing multiple windows in the chatterbox
- enabled = true;
- }
-
- mButtons[i]->setEnabled(enabled);
-
- if (enabled)
- {
- button_count++;
-
- LLRect btn_rect;
- if (mDragOnLeft)
- {
- btn_rect.setLeftTopAndSize(
- LLPANEL_BORDER_WIDTH,
- getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count,
- ll_round((F32)floater_close_box_size * mButtonScale),
- ll_round((F32)floater_close_box_size * mButtonScale));
- }
- else
- {
- btn_rect.setLeftTopAndSize(
- getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count,
- getRect().getHeight() - close_box_from_top,
- ll_round((F32)floater_close_box_size * mButtonScale),
- ll_round((F32)floater_close_box_size * mButtonScale));
- }
-
- // first time here, init 'buttons_rect'
- if(1 == button_count)
- {
- buttons_rect = btn_rect;
- }
- else
- {
- // if mDragOnLeft=true then buttons are on top-left side vertically aligned
- // title is not displayed in this case, calculating 'buttons_rect' for future use
- mDragOnLeft ? buttons_rect.mBottom -= btn_rect.mBottom :
- buttons_rect.mLeft = btn_rect.mLeft;
- }
- mButtons[i]->setRect(btn_rect);
- mButtons[i]->setVisible(true);
- // the restore button should have a tab stop so that it takes action when you Ctrl-Tab to a minimized floater
- mButtons[i]->setTabStop(i == BUTTON_RESTORE);
- }
- else
- {
- mButtons[i]->setVisible(false);
- }
- }
- if (mDragHandle)
- {
- localRectToOtherView(buttons_rect, &buttons_rect, mDragHandle);
- mDragHandle->setButtonsRect(buttons_rect);
- }
-}
-
-void LLFloater::drawConeToOwner(F32 &context_cone_opacity,
- F32 max_cone_opacity,
- LLView *owner_view,
- F32 fade_time,
- F32 contex_cone_in_alpha,
- F32 contex_cone_out_alpha)
-{
- if (owner_view
- && owner_view->isInVisibleChain()
- && hasFocus()
- && context_cone_opacity > 0.001f
- && gFocusMgr.childHasKeyboardFocus(this))
- {
- // draw cone of context pointing back to owner (e.x. texture swatch)
- LLRect owner_rect;
- owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this);
- LLRect local_rect = getLocalRect();
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLEnable(GL_CULL_FACE);
- gGL.begin(LLRender::QUADS);
- {
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
- gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
- gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
- gGL.vertex2i(local_rect.mRight, local_rect.mTop);
- gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
-
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
- gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
- gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
- gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
- gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
-
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
- gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
- gGL.vertex2i(local_rect.mRight, local_rect.mTop);
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
- gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
- gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
-
-
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
- gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
- gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
- gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
- gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
- gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
- }
- gGL.end();
- }
-
- if (gFocusMgr.childHasMouseCapture(getDragHandle()))
- {
- context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time));
- }
- else
- {
- context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time));
- }
-}
-
-void LLFloater::buildButtons(const Params& floater_params)
-{
- static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
- static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
- for (S32 i = 0; i < BUTTON_COUNT; i++)
- {
- if (mButtons[i])
- {
- removeChild(mButtons[i]);
- delete mButtons[i];
- mButtons[i] = NULL;
- }
-
- LLRect btn_rect;
- if (mDragOnLeft)
- {
- btn_rect.setLeftTopAndSize(
- LLPANEL_BORDER_WIDTH,
- getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * (i + 1),
- ll_round(floater_close_box_size * mButtonScale),
- ll_round(floater_close_box_size * mButtonScale));
- }
- else
- {
- btn_rect.setLeftTopAndSize(
- getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * (i + 1),
- getRect().getHeight() - close_box_from_top,
- ll_round(floater_close_box_size * mButtonScale),
- ll_round(floater_close_box_size * mButtonScale));
- }
-
- LLButton::Params p;
- p.name(sButtonNames[i]);
- p.rect(btn_rect);
- p.image_unselected = getButtonImage(floater_params, (EFloaterButton)i);
- // Selected, no matter if hovered or not, is "pressed"
- LLUIImage* pressed_image = getButtonPressedImage(floater_params, (EFloaterButton)i);
- p.image_selected = pressed_image;
- p.image_hover_selected = pressed_image;
- // Use a glow effect when the user hovers over the button
- // These icons are really small, need glow amount increased
- p.hover_glow_amount( 0.33f );
- p.click_callback.function(boost::bind(sButtonCallbacks[i], this));
- p.tab_stop(false);
- p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT);
- p.tool_tip = getButtonTooltip(floater_params, (EFloaterButton)i, getIsChrome());
- p.scale_image(true);
- p.chrome(true);
-
- LLButton* buttonp = LLUICtrlFactory::create<LLButton>(p);
- addChild(buttonp);
- mButtons[i] = buttonp;
- }
-
- updateTitleButtons();
-}
-
-// static
-LLUIImage* LLFloater::getButtonImage(const Params& p, EFloaterButton e)
-{
- switch(e)
- {
- default:
- case BUTTON_CLOSE:
- return p.close_image;
- case BUTTON_RESTORE:
- return p.restore_image;
- case BUTTON_MINIMIZE:
- return p.minimize_image;
- case BUTTON_TEAR_OFF:
- return p.tear_off_image;
- case BUTTON_DOCK:
- return p.dock_image;
- case BUTTON_HELP:
- return p.help_image;
- }
-}
-
-// static
-LLUIImage* LLFloater::getButtonPressedImage(const Params& p, EFloaterButton e)
-{
- switch(e)
- {
- default:
- case BUTTON_CLOSE:
- return p.close_pressed_image;
- case BUTTON_RESTORE:
- return p.restore_pressed_image;
- case BUTTON_MINIMIZE:
- return p.minimize_pressed_image;
- case BUTTON_TEAR_OFF:
- return p.tear_off_pressed_image;
- case BUTTON_DOCK:
- return p.dock_pressed_image;
- case BUTTON_HELP:
- return p.help_pressed_image;
- }
-}
-
-// static
-std::string LLFloater::getButtonTooltip(const Params& p, EFloaterButton e, bool is_chrome)
-{
- // EXT-4081 (Lag Meter: Ctrl+W does not close floater)
- // If floater is chrome set 'Close' text for close button's tooltip
- if(is_chrome && BUTTON_CLOSE == e)
- {
- static std::string close_tooltip_chrome = LLTrans::getString("BUTTON_CLOSE_CHROME");
- return close_tooltip_chrome;
- }
- // TODO: per-floater localizable tooltips set in XML
- return sButtonToolTips[e];
-}
-
-/////////////////////////////////////////////////////
-// LLFloaterView
-
-static LLDefaultChildRegistry::Register<LLFloaterView> r("floater_view");
-
-LLFloaterView::LLFloaterView (const Params& p)
-: LLUICtrl (p),
- mFocusCycleMode(false),
- mMinimizePositionVOffset(0),
- mSnapOffsetBottom(0),
- mSnapOffsetRight(0)
-{
- mSnapView = getHandle();
-}
-
-// By default, adjust vertical.
-void LLFloaterView::reshape(S32 width, S32 height, bool called_from_parent)
-{
- LLView::reshape(width, height, called_from_parent);
-
- mLastSnapRect = getSnapRect();
-
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLView* viewp = *child_it;
- LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
- if (floaterp->isDependent())
- {
- // dependents are moved with their "dependee"
- continue;
- }
-
- if (!floaterp->isMinimized() && floaterp->getCanDrag())
- {
- LLRect old_rect = floaterp->getRect();
- floaterp->applyPositioning(NULL, false);
- LLRect new_rect = floaterp->getRect();
-
- //LLRect r = floaterp->getRect();
-
- //// Compute absolute distance from each edge of screen
- //S32 left_offset = llabs(r.mLeft - 0);
- //S32 right_offset = llabs(old_right - r.mRight);
-
- //S32 top_offset = llabs(old_top - r.mTop);
- //S32 bottom_offset = llabs(r.mBottom - 0);
-
- S32 translate_x = new_rect.mLeft - old_rect.mLeft;
- S32 translate_y = new_rect.mBottom - old_rect.mBottom;
-
- //if (left_offset > right_offset)
- //{
- // translate_x = new_right - old_right;
- //}
-
- //if (top_offset < bottom_offset)
- //{
- // translate_y = new_top - old_top;
- //}
-
- // don't reposition immovable floaters
- //if (floaterp->getCanDrag())
- //{
- // floaterp->translate(translate_x, translate_y);
- //}
- for (LLHandle<LLFloater> dependent_floater : floaterp->mDependents)
- {
- if (dependent_floater.get())
- {
- dependent_floater.get()->translate(translate_x, translate_y);
- }
- }
- }
- }
-}
-
-
-void LLFloaterView::restoreAll()
-{
- // make sure all subwindows aren't minimized
- for (auto child : *getChildList())
- {
- LLFloater* floaterp = dynamic_cast<LLFloater*>(child);
- if (floaterp)
- {
- floaterp->setMinimized(false);
- }
- }
-
- // *FIX: make sure dependents are restored
-
- // children then deleted by default view constructor
-}
-
-
-LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor )
-{
- LLRect base_rect = reference_floater->getRect();
- LLRect::tCoordType width = neighbor->getRect().getWidth();
- LLRect::tCoordType height = neighbor->getRect().getHeight();
- LLRect new_rect = neighbor->getRect();
-
- LLRect expanded_base_rect = base_rect;
- expanded_base_rect.stretch(10);
- for(LLFloater::handle_set_iter_t dependent_it = reference_floater->mDependents.begin();
- dependent_it != reference_floater->mDependents.end(); ++dependent_it)
- {
- LLFloater* sibling = dependent_it->get();
- // check for dependents within 10 pixels of base floater
- if (sibling &&
- sibling != neighbor &&
- sibling->getVisible() &&
- expanded_base_rect.overlaps(sibling->getRect()))
- {
- base_rect.unionWith(sibling->getRect());
- }
- }
-
- LLRect::tCoordType left_margin = llmax(0, base_rect.mLeft);
- LLRect::tCoordType right_margin = llmax(0, getRect().getWidth() - base_rect.mRight);
- LLRect::tCoordType top_margin = llmax(0, getRect().getHeight() - base_rect.mTop);
- LLRect::tCoordType bottom_margin = llmax(0, base_rect.mBottom);
-
- // find position for floater in following order
- // right->left->bottom->top
- for (S32 i = 0; i < 5; i++)
- {
- if (right_margin > width)
- {
- new_rect.translate(base_rect.mRight - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mTop);
- return new_rect;
- }
- else if (left_margin > width)
- {
- new_rect.translate(base_rect.mLeft - neighbor->getRect().mRight, base_rect.mTop - neighbor->getRect().mTop);
- return new_rect;
- }
- else if (bottom_margin > height)
- {
- new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mBottom - neighbor->getRect().mTop);
- return new_rect;
- }
- else if (top_margin > height)
- {
- new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mBottom);
- return new_rect;
- }
-
- // keep growing margins to find "best" fit
- left_margin += 20;
- right_margin += 20;
- top_margin += 20;
- bottom_margin += 20;
- }
-
- // didn't find anything, return initial rect
- return new_rect;
-}
-
-
-void LLFloaterView::bringToFront(LLFloater* child, bool give_focus, bool restore)
-{
- if (!child)
- return;
-
- LLFloater* front_child = mFrontChildHandle.get();
- if (front_child == child)
- {
- if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))
- {
- child->setFocus(true);
- }
- return;
- }
-
- if (front_child && front_child->getVisible())
- {
- front_child->goneFromFront();
- }
-
- mFrontChildHandle = child->getHandle();
-
- // *TODO: make this respect floater's mAutoFocus value, instead of
- // using parameter
- if (child->getHost())
- {
- // this floater is hosted elsewhere and hence not one of our children, abort
- return;
- }
- std::vector<LLFloater*> floaters_to_move;
- // Look at all floaters...tab
- for (child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it)
- {
- LLFloater* floater = dynamic_cast<LLFloater*>(*child_it);
-
- // ...but if I'm a dependent floater...
- if (floater && child->isDependent())
- {
- // ...look for floaters that have me as a dependent...
- LLFloater::handle_set_iter_t found_dependent = floater->mDependents.find(child->getHandle());
-
- if (found_dependent != floater->mDependents.end())
- {
- // ...and make sure all children of that floater (including me) are brought to front...
- for (LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
- dependent_it != floater->mDependents.end(); ++dependent_it)
- {
- LLFloater* sibling = dependent_it->get();
- if (sibling)
- {
- floaters_to_move.push_back(sibling);
- }
- }
- //...before bringing my parent to the front...
- floaters_to_move.push_back(floater);
- }
- }
- }
-
- std::vector<LLFloater*>::iterator floater_it;
- for(floater_it = floaters_to_move.begin(); floater_it != floaters_to_move.end(); ++floater_it)
- {
- LLFloater* floaterp = *floater_it;
- sendChildToFront(floaterp);
-
- // always unminimize dependee, but allow dependents to stay minimized
- if (!floaterp->isDependent())
- {
- floaterp->setMinimized(false);
- }
- }
- floaters_to_move.clear();
-
- // ...then bringing my own dependents to the front...
- for (LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin();
- dependent_it != child->mDependents.end(); ++dependent_it)
- {
- LLFloater* dependent = dependent_it->get();
- if (dependent)
- {
- sendChildToFront(dependent);
- }
- }
-
- // ...and finally bringing myself to front
- // (do this last, so that I'm left in front at end of this call)
- if (*beginChild() != child)
- {
- sendChildToFront(child);
- }
-
- if(restore)
- {
- child->setMinimized(false);
- }
-
- if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
- {
- child->setFocus(true);
- // floater did not take focus, so relinquish focus to world
- if (!child->hasFocus())
- {
- gFocusMgr.setKeyboardFocus(NULL);
- }
- }
-}
-
-void LLFloaterView::highlightFocusedFloater()
-{
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLFloater *floater = (LLFloater *)(*child_it);
-
- // skip dependent floaters, as we'll handle them in a batch along with their dependee(?)
- if (floater->isDependent())
- {
- continue;
- }
-
- bool floater_or_dependent_has_focus = gFocusMgr.childHasKeyboardFocus(floater);
- for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
- dependent_it != floater->mDependents.end();
- ++dependent_it)
- {
- LLFloater* dependent_floaterp = dependent_it->get();
- if (dependent_floaterp && gFocusMgr.childHasKeyboardFocus(dependent_floaterp))
- {
- floater_or_dependent_has_focus = true;
- }
- }
-
- // now set this floater and all its dependents
- floater->setForeground(floater_or_dependent_has_focus);
-
- for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
- dependent_it != floater->mDependents.end(); )
- {
- LLFloater* dependent_floaterp = dependent_it->get();
- if (dependent_floaterp)
- {
- dependent_floaterp->setForeground(floater_or_dependent_has_focus);
- }
- ++dependent_it;
- }
-
- floater->cleanupHandles();
- }
-}
-
-LLFloater* LLFloaterView::getFrontmostClosableFloater()
-{
- child_list_const_iter_t child_it;
- LLFloater* frontmost_floater = NULL;
-
- for ( child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- frontmost_floater = (LLFloater *)(*child_it);
-
- if (frontmost_floater->isInVisibleChain() && frontmost_floater->isCloseable())
- {
- return frontmost_floater;
- }
- }
-
- return NULL;
-}
-
-void LLFloaterView::unhighlightFocusedFloater()
-{
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLFloater *floater = (LLFloater *)(*child_it);
-
- floater->setForeground(false);
- }
-}
-
-void LLFloaterView::focusFrontFloater()
-{
- LLFloater* floaterp = getFrontmost();
- if (floaterp)
- {
- floaterp->setFocus(true);
- }
-}
-
-void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
-{
- const LLFloater::Params& default_params = LLFloater::getDefaultParams();
- S32 floater_header_size = default_params.header_height;
- static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
- LLRect snap_rect_local = getLocalSnapRect();
- snap_rect_local.mTop += mMinimizePositionVOffset;
- for(S32 col = snap_rect_local.mLeft;
- col < snap_rect_local.getWidth() - minimized_width;
- col += minimized_width)
- {
- for(S32 row = snap_rect_local.mTop - floater_header_size;
- row > floater_header_size;
- row -= floater_header_size ) //loop rows
- {
-
- bool foundGap = true;
- for(child_list_const_iter_t child_it = getChildList()->begin();
- child_it != getChildList()->end();
- ++child_it) //loop floaters
- {
- // Examine minimized children.
- LLFloater* floater = dynamic_cast<LLFloater*>(*child_it);
- if(floater->isMinimized())
- {
- LLRect r = floater->getRect();
- 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
- foundGap = false;
- break;
- }
- }
- } //done floaters
- if(foundGap)
- {
- *left = col;
- *bottom = row;
- return; //done
- }
- } //done this col
- }
-
- // crude - stack'em all at 0,0 when screen is full of minimized
- // floaters.
- *left = snap_rect_local.mLeft;
- *bottom = snap_rect_local.mBottom;
-}
-
-
-void LLFloaterView::destroyAllChildren()
-{
- LLView::deleteAllChildren();
-}
-
-void LLFloaterView::closeAllChildren(bool app_quitting)
-{
- // iterate over a copy of the list, because closing windows will destroy
- // some windows on the list.
- child_list_t child_list = *(getChildList());
-
- for (child_list_const_iter_t it = child_list.begin(); it != child_list.end(); ++it)
- {
- LLView* viewp = *it;
- child_list_const_iter_t exists = std::find(getChildList()->begin(), getChildList()->end(), viewp);
- if (exists == getChildList()->end())
- {
- // this floater has already been removed
- continue;
- }
-
- LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
-
- // Attempt to close floater. This will cause the "do you want to save"
- // dialogs to appear.
- // Skip invisible floaters if we're not quitting (STORM-192).
- if (floaterp->canClose() && !floaterp->isDead() &&
- (app_quitting || floaterp->getVisible()))
- {
- floaterp->closeFloater(app_quitting);
- }
- }
-}
-
-void LLFloaterView::hiddenFloaterClosed(LLFloater* floater)
-{
- for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end();
- it != end_it;
- ++it)
- {
- if (it->first.get() == floater)
- {
- it->second.disconnect();
- mHiddenFloaters.erase(it);
- break;
- }
- }
-}
-
-void LLFloaterView::hideAllFloaters()
-{
- child_list_t child_list = *(getChildList());
-
- for (child_list_iter_t it = child_list.begin(); it != child_list.end(); ++it)
- {
- LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
- if (floaterp && floaterp->getVisible())
- {
- floaterp->setVisible(false);
- boost::signals2::connection connection = floaterp->mCloseSignal.connect(boost::bind(&LLFloaterView::hiddenFloaterClosed, this, floaterp));
- mHiddenFloaters.push_back(std::make_pair(floaterp->getHandle(), connection));
- }
- }
-}
-
-void LLFloaterView::showHiddenFloaters()
-{
- for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end();
- it != end_it;
- ++it)
- {
- LLFloater* floaterp = it->first.get();
- if (floaterp)
- {
- floaterp->setVisible(true);
- }
- it->second.disconnect();
- }
- mHiddenFloaters.clear();
-}
-
-bool LLFloaterView::allChildrenClosed()
-{
- // see if there are any visible floaters (some floaters "close"
- // by setting themselves invisible)
- for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
- {
- LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
-
- if (floaterp->getVisible() && !floaterp->isDead() && floaterp->isCloseable())
- {
- return false;
- }
- }
- return true;
-}
-
-void LLFloaterView::shiftFloaters(S32 x_offset, S32 y_offset)
-{
- for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
- {
- LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
-
- if (floaterp && floaterp->isMinimized())
- {
- floaterp->translate(x_offset, y_offset);
- }
- }
-}
-
-void LLFloaterView::refresh()
-{
- LLRect snap_rect = getSnapRect();
- if (snap_rect != mLastSnapRect)
- {
- reshape(getRect().getWidth(), getRect().getHeight(), true);
- }
-
- // 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 = dynamic_cast<LLFloater*>(*child_it);
- if (floaterp && floaterp->getVisible() )
- {
- // minimized floaters are kept fully onscreen
- adjustToFitScreen(floaterp, !floaterp->isMinimized());
- }
- }
-}
-
-void LLFloaterView::adjustToFitScreen(LLFloater* floater, bool allow_partial_outside, bool snap_in_toolbars/* = false*/)
-{
- if (floater->getParent() != this)
- {
- // floater is hosted elsewhere, so ignore
- return;
- }
-
- if (floater->getDependee() &&
- floater->getDependee() == floater->getSnapTarget().get())
- {
- // floater depends on other and snaps to it, so ignore
- return;
- }
-
- LLRect::tCoordType screen_width = getSnapRect().getWidth();
- LLRect::tCoordType screen_height = getSnapRect().getHeight();
-
- // only automatically resize non-minimized, resizable floaters
- if( floater->isResizable() && !floater->isMinimized() )
- {
- LLRect view_rect = floater->getRect();
- S32 old_width = view_rect.getWidth();
- S32 old_height = view_rect.getHeight();
- S32 min_width;
- S32 min_height;
- floater->getResizeLimits( &min_width, &min_height );
-
- // Make sure floater isn't already smaller than its min height/width?
- S32 new_width = llmax( min_width, old_width );
- S32 new_height = llmax( min_height, old_height);
-
- if((new_width > screen_width) || (new_height > screen_height))
- {
- // We have to make this window able to fit on screen
- new_width = llmin(new_width, screen_width);
- new_height = llmin(new_height, screen_height);
-
- // ...while respecting minimum width/height
- new_width = llmax(new_width, min_width);
- new_height = llmax(new_height, min_height);
-
- LLRect new_rect;
- new_rect.setLeftTopAndSize(view_rect.mLeft,view_rect.mTop,new_width, new_height);
-
- floater->setShape(new_rect);
-
- if (floater->followsRight())
- {
- floater->translate(old_width - new_width, 0);
- }
-
- if (floater->followsTop())
- {
- floater->translate(0, old_height - new_height);
- }
- }
- }
-
- const LLRect& constraint = snap_in_toolbars ? getSnapRect() : gFloaterView->getRect();
- S32 min_overlap_pixels = allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX;
-
- floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels);
-}
-
-void LLFloaterView::draw()
-{
- refresh();
-
- // hide focused floater if in cycle mode, so that it can be drawn on top
- LLFloater* focused_floater = getFocusedFloater();
-
- if (mFocusCycleMode && focused_floater)
- {
- child_list_const_iter_t child_it = getChildList()->begin();
- for (;child_it != getChildList()->end(); ++child_it)
- {
- if ((*child_it) != focused_floater)
- {
- drawChild(*child_it);
- }
- }
-
- drawChild(focused_floater, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET);
- }
- else
- {
- LLView::draw();
- }
-}
-
-LLRect LLFloaterView::getSnapRect() const
-{
- LLRect snap_rect = getLocalRect();
-
- LLView* snap_view = mSnapView.get();
- if (snap_view)
- {
- snap_view->localRectToOtherView(snap_view->getLocalRect(), &snap_rect, this);
- }
-
- return snap_rect;
-}
-
-LLFloater *LLFloaterView::getFocusedFloater() const
-{
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- if ((*child_it)->isCtrl())
- {
- LLFloater* ctrlp = dynamic_cast<LLFloater*>(*child_it);
- if ( ctrlp && ctrlp->hasFocus() )
- {
- return ctrlp;
- }
- }
- }
- return NULL;
-}
-
-LLFloater *LLFloaterView::getFrontmost() const
-{
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLView* viewp = *child_it;
- if ( viewp->getVisible() && !viewp->isDead())
- {
- return (LLFloater *)viewp;
- }
- }
- return NULL;
-}
-
-LLFloater *LLFloaterView::getBackmost() const
-{
- LLFloater* back_most = NULL;
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLView* viewp = *child_it;
- if ( viewp->getVisible() )
- {
- back_most = (LLFloater *)viewp;
- }
- }
- return back_most;
-}
-
-void LLFloaterView::syncFloaterTabOrder()
-{
- LLFloater* front_child = mFrontChildHandle.get();
- if (front_child && front_child->getIsChrome())
- return;
-
- // look for a visible modal dialog, starting from first
- LLModalDialog* modal_dialog = NULL;
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLModalDialog* dialog = dynamic_cast<LLModalDialog*>(*child_it);
- if (dialog && dialog->isModal() && dialog->getVisible())
- {
- modal_dialog = dialog;
- break;
- }
- }
-
- if (modal_dialog)
- {
- // If we have a visible modal dialog, make sure that it has focus
- LLUI::getInstance()->addPopup(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 = dynamic_cast<LLFloater*>(*child_it);
- if (gFocusMgr.childHasKeyboardFocus(floaterp))
- {
- LLFloater* front_child = mFrontChildHandle.get();
- if (front_child != floaterp)
- {
- // Grab a list of the top floaters that want to stay on top of the focused floater
- std::list<LLFloater*> listTop;
- if (front_child && !front_child->canFocusStealFrontmost())
- {
- for (LLView* childp : *getChildList())
- {
- LLFloater* child_floaterp = static_cast<LLFloater*>(childp);
- if (child_floaterp->canFocusStealFrontmost())
- break;
- listTop.push_back(child_floaterp);
- }
- }
-
- bringToFront(floaterp, false);
-
- // Restore top floaters
- if (!listTop.empty())
- {
- for (LLView* childp : listTop)
- {
- sendChildToFront(childp);
- }
- mFrontChildHandle = listTop.back()->getHandle();
- }
- }
-
- break;
- }
- }
- }
-}
-
-LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const
-{
- LLView* parentp = viewp->getParent();
-
- while(parentp && parentp != this)
- {
- viewp = parentp;
- parentp = parentp->getParent();
- }
-
- if (parentp == this)
- {
- return dynamic_cast<LLFloater*>(viewp);
- }
-
- return NULL;
-}
-
-S32 LLFloaterView::getZOrder(LLFloater* child)
-{
- S32 rv = 0;
- for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
- {
- LLView* viewp = *child_it;
- if(viewp == child)
- {
- break;
- }
- ++rv;
- }
- return rv;
-}
-
-void LLFloaterView::pushVisibleAll(bool visible, const skip_list_t& skip_list)
-{
- for (child_list_const_iter_t child_iter = getChildList()->begin();
- child_iter != getChildList()->end(); ++child_iter)
- {
- LLView *view = *child_iter;
- if (skip_list.find(view) == skip_list.end())
- {
- view->pushVisible(visible);
- }
- }
-
- LLFloaterReg::blockShowFloaters(true);
-}
-
-void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
-{
- // make a copy of the list since some floaters change their
- // order in the childList when changing visibility.
- child_list_t child_list_copy = *getChildList();
-
- for (child_list_const_iter_t child_iter = child_list_copy.begin();
- child_iter != child_list_copy.end(); ++child_iter)
- {
- LLView *view = *child_iter;
- if (skip_list.find(view) == skip_list.end())
- {
- view->popVisible();
- }
- }
-
- LLFloaterReg::blockShowFloaters(false);
-}
-
-void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect)
-{
- switch (tb)
- {
- case LLToolBarEnums::TOOLBAR_LEFT:
- mToolbarLeftRect = toolbar_rect;
- break;
- case LLToolBarEnums::TOOLBAR_BOTTOM:
- mToolbarBottomRect = toolbar_rect;
- break;
- case LLToolBarEnums::TOOLBAR_RIGHT:
- mToolbarRightRect = toolbar_rect;
- break;
- default:
- LL_WARNS() << "setToolbarRect() passed odd toolbar number " << (S32) tb << LL_ENDL;
- break;
- }
-}
-
-void LLFloater::setInstanceName(const std::string& name)
-{
- if (name != mInstanceName)
- {
- llassert_always(mInstanceName.empty());
- mInstanceName = name;
- if (!mInstanceName.empty())
- {
- std::string ctrl_name = getControlName(mInstanceName, mKey);
- initRectControl();
- if (!mVisibilityControl.empty())
- {
- mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name);
- }
- if(!mDocStateControl.empty())
- {
- mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name);
- }
- }
-}
-}
-
-void LLFloater::setKey(const LLSD& newkey)
-{
- // Note: We don't have to do anything special with registration when we change keys
- mKey = newkey;
-}
-
-//static
-void LLFloater::setupParamsForExport(Params& p, LLView* parent)
-{
- // Do rectangle munging to topleft layout first
- LLPanel::setupParamsForExport(p, parent);
-
- // Copy the rectangle out to apply layout constraints
- LLRect rect = p.rect;
-
- // Null out other settings
- p.rect.left.setProvided(false);
- p.rect.top.setProvided(false);
- p.rect.right.setProvided(false);
- p.rect.bottom.setProvided(false);
-
- // Explicitly set width/height
- p.rect.width.set( rect.getWidth(), true );
- p.rect.height.set( rect.getHeight(), true );
-
- // If you can't resize this floater, don't export min_height
- // and min_width
- bool can_resize = p.can_resize;
- if (!can_resize)
- {
- p.min_height.setProvided(false);
- p.min_width.setProvided(false);
- }
-}
-
-void LLFloater::initFromParams(const LLFloater::Params& p)
-{
- // *NOTE: We have too many classes derived from LLFloater to retrofit them
- // all to pass in params via constructors. So we use this method.
-
- // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
- LLPanel::initFromParams(p);
-
- // override any follows flags
- if (mPositioning != LLFloaterEnums::POSITIONING_SPECIFIED)
- {
- setFollows(FOLLOWS_NONE);
- }
-
- mTitle = p.title;
- mShortTitle = p.short_title;
- applyTitle();
-
- setCanTearOff(p.can_tear_off);
- setCanMinimize(p.can_minimize);
- setCanClose(p.can_close);
- setCanDock(p.can_dock);
- setCanResize(p.can_resize);
- setResizeLimits(p.min_width, p.min_height);
-
- mDragOnLeft = p.can_drag_on_left;
- mHeaderHeight = p.header_height;
- mLegacyHeaderHeight = p.legacy_header_height;
- mSingleInstance = p.single_instance;
- mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance;
-
- mDefaultRelativeX = p.rel_x;
- mDefaultRelativeY = p.rel_y;
-
- mPositioning = p.positioning;
- mAutoClose = p.auto_close;
-
- mSaveRect = p.save_rect;
- if (p.save_visibility)
- {
- mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
- }
- if(p.save_dock_state)
- {
- mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set
- }
-
- // open callback
- if (p.open_callback.isProvided())
- {
- setOpenCallback(initCommitCallback(p.open_callback));
- }
- // close callback
- if (p.close_callback.isProvided())
- {
- setCloseCallback(initCommitCallback(p.close_callback));
- }
-
- if (mDragHandle)
- {
- mDragHandle->setTitleVisible(p.show_title);
- }
-}
-
-boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mMinimizeSignal) mMinimizeSignal = new commit_signal_t();
- return mMinimizeSignal->connect(cb);
-}
-
-boost::signals2::connection LLFloater::setOpenCallback( const commit_signal_t::slot_type& cb )
-{
- return mOpenSignal.connect(cb);
-}
-
-boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb )
-{
- return mCloseSignal.connect(cb);
-}
-
-bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
-{
- LL_PROFILE_ZONE_SCOPED;
- Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());
- Params params(default_params);
-
- LLXUIParser parser;
- parser.readXUI(node, params, filename); // *TODO: Error checking
-
- std::string xml_filename = params.filename;
-
- if (!xml_filename.empty())
- {
- LLXMLNodePtr referenced_xml;
-
- if (output_node)
- {
- //if we are exporting, we want to export the current xml
- //not the referenced xml
- Params output_params;
- parser.readXUI(node, output_params, LLUICtrlFactory::getInstance()->getCurFileName());
- setupParamsForExport(output_params, parent);
- output_node->setName(node->getName()->mString);
- parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params);
- return true;
- }
-
- LLUICtrlFactory::instance().pushFileName(xml_filename);
-
- if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
- {
- LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL;
-
- return false;
- }
-
- Params referenced_params;
- parser.readXUI(referenced_xml, referenced_params, LLUICtrlFactory::getInstance()->getCurFileName());
- params.fillFrom(referenced_params);
-
- // add children using dimensions from referenced xml for consistent layout
- setShape(params.rect);
- LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance());
-
- LLUICtrlFactory::instance().popFileName();
- }
-
-
- if (output_node)
- {
- Params output_params(params);
- setupParamsForExport(output_params, parent);
- output_node->setName(node->getName()->mString);
- parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params);
- }
-
- // Default floater position to top-left corner of screen
- // However, some legacy floaters have explicit top or bottom
- // coordinates set, so respect their wishes.
- if (!params.rect.top.isProvided() && !params.rect.bottom.isProvided())
- {
- params.rect.top.set(0);
- }
- if (!params.rect.left.isProvided() && !params.rect.right.isProvided())
- {
- params.rect.left.set(0);
- }
- params.from_xui = true;
- applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect());
- initFromParams(params);
-
- initFloater(params);
-
- LLMultiFloater* last_host = LLFloater::getFloaterHost();
- if (node->hasName("multi_floater"))
- {
- LLFloater::setFloaterHost((LLMultiFloater*) this);
- }
-
- LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node);
-
- if (node->hasName("multi_floater"))
- {
- LLFloater::setFloaterHost(last_host);
- }
-
- // HACK: When we changed the header height to 25 pixels in Viewer 2, rather
- // than re-layout all the floaters we use this value in pixels to make the
- // whole floater bigger and change the top-left coordinate for widgets.
- // The goal is to eventually set mLegacyHeaderHeight to zero, which would
- // make the top-left corner for widget layout the same as the top-left
- // corner of the window's content area. James
- S32 header_stretch = (mHeaderHeight - mLegacyHeaderHeight);
- if (header_stretch > 0)
- {
- // Stretch the floater vertically, don't move widgets
- LLRect rect = getRect();
- rect.mTop += header_stretch;
-
- // This will also update drag handle, title bar, close box, etc.
- setRect(rect);
- }
-
- bool result;
- result = postBuild();
-
- if (!result)
- {
- LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL;
- }
-
- applyRectControl(); // If we have a saved rect control, apply it
- gFloaterView->adjustToFitScreen(this, false); // Floaters loaded from XML should all fit on screen
-
- moveResizeHandlesToFront();
-
- applyDockState();
-
- return true; // *TODO: Error checking
-}
-
-bool LLFloater::isShown() const
-{
- return ! isMinimized() && isInVisibleChain();
-}
-
-bool LLFloater::isDetachedAndNotMinimized()
-{
- return !getHost() && !isMinimized();
-}
-
-/* static */
-bool LLFloater::isShown(const LLFloater* floater)
-{
- return floater && floater->isShown();
-}
-
-/* static */
-bool LLFloater::isMinimized(const LLFloater* floater)
-{
- return floater && floater->isMinimized();
-}
-
-/* static */
-bool LLFloater::isVisible(const LLFloater* floater)
-{
- return floater && floater->getVisible();
-}
-
-bool LLFloater::buildFromFile(const std::string& filename)
-{
- LL_PROFILE_ZONE_SCOPED;
- LLXMLNodePtr root;
-
- if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
- {
- LL_WARNS() << "Couldn't find (or parse) floater from: " << filename << LL_ENDL;
- return false;
- }
-
- // root must be called floater
- if( !(root->hasName("floater") || root->hasName("multi_floater")) )
- {
- LL_WARNS() << "Root node should be named floater in: " << filename << LL_ENDL;
- return false;
- }
-
- bool res = true;
-
- LL_DEBUGS() << "Building floater " << filename << LL_ENDL;
- LLUICtrlFactory::instance().pushFileName(filename);
- {
- if (!getFactoryMap().empty())
- {
- LLPanel::sFactoryStack.push_front(&getFactoryMap());
- }
-
- // for local registry callbacks; define in constructor, referenced in XUI or postBuild
- getCommitCallbackRegistrar().pushScope();
- getEnableCallbackRegistrar().pushScope();
-
- res = initFloaterXML(root, getParent(), filename, NULL);
-
- setXMLFilename(filename);
-
- getCommitCallbackRegistrar().popScope();
- getEnableCallbackRegistrar().popScope();
-
- if (!getFactoryMap().empty())
- {
- LLPanel::sFactoryStack.pop_front();
- }
- }
- LLUICtrlFactory::instance().popFileName();
-
- return res;
-}
-
-void LLFloater::stackWith(LLFloater& other)
-{
- static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16);
-
- LLRect next_rect;
- if (other.getHost())
- {
- next_rect = other.getHost()->getRect();
- }
- else
- {
- next_rect = other.getRect();
- }
- next_rect.translate(floater_offset, -floater_offset);
-
- const LLRect& rect = getControlGroup()->getRect(mRectControl);
- if (rect.notEmpty() && !mDefaultRectForGroup && mResizable)
- {
- next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
- }
- else
- {
- next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
- }
- setShape(next_rect);
-
- if (!other.getHost())
- {
- other.mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;
- other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP);
- }
-}
-
-void LLFloater::applyRelativePosition()
-{
- LLRect snap_rect = gFloaterView->getSnapRect();
- LLRect floater_view_screen_rect = gFloaterView->calcScreenRect();
- snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom);
- LLRect floater_screen_rect = calcScreenRect();
-
- LLCoordGL new_center = mPosition.convert();
- LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY());
- translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY);
-}
-
-
-LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater)
-: coord_t((S32)x, (S32)y)
-{
- mFloater = floater.getHandle();
-}
-
-
-LLCoordFloater::LLCoordFloater(const LLCoordCommon& other, LLFloater& floater)
-{
- mFloater = floater.getHandle();
- convertFromCommon(other);
-}
-
-LLCoordFloater& LLCoordFloater::operator=(const LLCoordFloater& other)
-{
- mFloater = other.mFloater;
- coord_t::operator =(other);
- return *this;
-}
-
-void LLCoordFloater::setFloater(LLFloater& floater)
-{
- mFloater = floater.getHandle();
-}
-
-bool LLCoordFloater::operator==(const LLCoordFloater& other) const
-{
- return mX == other.mX && mY == other.mY && mFloater == other.mFloater;
-}
-
-LLCoordCommon LL_COORD_FLOATER::convertToCommon() const
-{
- const LLCoordFloater& self = static_cast<const LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this));
-
- LLRect snap_rect = gFloaterView->getSnapRect();
- LLRect floater_view_screen_rect = gFloaterView->calcScreenRect();
- snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom);
-
- LLFloater* floaterp = mFloater.get();
- S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0;
- S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0;
- LLCoordCommon out;
- if (self.mX < -0.5f)
- {
- out.mX = ll_round(rescale(self.mX, -1.f, -0.5f, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft));
- }
- else if (self.mX > 0.5f)
- {
- out.mX = ll_round(rescale(self.mX, 0.5f, 1.f, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS));
- }
- else
- {
- out.mX = ll_round(rescale(self.mX, -0.5f, 0.5f, snap_rect.mLeft, snap_rect.mRight - floater_width));
- }
-
- if (self.mY < -0.5f)
- {
- out.mY = ll_round(rescale(self.mY, -1.f, -0.5f, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom));
- }
- else if (self.mY > 0.5f)
- {
- out.mY = ll_round(rescale(self.mY, 0.5f, 1.f, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS));
- }
- else
- {
- out.mY = ll_round(rescale(self.mY, -0.5f, 0.5f, snap_rect.mBottom, snap_rect.mTop - floater_height));
- }
-
- // return center point instead of lower left
- out.mX += floater_width / 2;
- out.mY += floater_height / 2;
-
- return out;
-}
-
-void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from)
-{
- LLCoordFloater& self = static_cast<LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this));
- LLRect snap_rect = gFloaterView->getSnapRect();
- LLRect floater_view_screen_rect = gFloaterView->calcScreenRect();
- snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom);
-
-
- LLFloater* floaterp = mFloater.get();
- S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0;
- S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0;
-
- S32 from_x = from.mX - floater_width / 2;
- S32 from_y = from.mY - floater_height / 2;
-
- if (from_x < snap_rect.mLeft)
- {
- self.mX = rescale(from_x, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft, -1.f, -0.5f);
- }
- else if (from_x + floater_width > snap_rect.mRight)
- {
- self.mX = rescale(from_x, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f);
- }
- else
- {
- self.mX = rescale(from_x, snap_rect.mLeft, snap_rect.mRight - floater_width, -0.5f, 0.5f);
- }
-
- if (from_y < snap_rect.mBottom)
- {
- self.mY = rescale(from_y, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom, -1.f, -0.5f);
- }
- else if (from_y + floater_height > snap_rect.mTop)
- {
- self.mY = rescale(from_y, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f);
- }
- else
- {
- self.mY = rescale(from_y, snap_rect.mBottom, snap_rect.mTop - floater_height, -0.5f, 0.5f);
- }
-}
+/**
+ * @file llfloater.cpp
+ * @brief LLFloater base class
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+// Floating "windows" within the GL display, like the inventory floater,
+// mini-map floater, etc.
+
+#include "linden_common.h"
+#include "llviewereventrecorder.h"
+#include "llfloater.h"
+
+#include "llfocusmgr.h"
+
+#include "lluictrlfactory.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llcriticaldamp.h" // LLSmoothInterpolation
+#include "lldir.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"
+#include "llwindow.h"
+#include "llstl.h"
+#include "llcontrol.h"
+#include "lltabcontainer.h"
+#include "v2math.h"
+#include "lltrans.h"
+#include "llhelp.h"
+#include "llmultifloater.h"
+#include "llsdutil.h"
+#include "lluiusage.h"
+
+
+// use this to control "jumping" behavior when Ctrl-Tabbing
+const S32 TABBED_FLOATER_OFFSET = 0;
+
+const F32 LLFloater::CONTEXT_CONE_IN_ALPHA = 0.0f;
+const F32 LLFloater::CONTEXT_CONE_OUT_ALPHA = 1.f;
+const F32 LLFloater::CONTEXT_CONE_FADE_TIME = 0.08f;
+
+namespace LLInitParam
+{
+ void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()
+ {
+ declare("relative", LLFloaterEnums::POSITIONING_RELATIVE);
+ declare("cascading", LLFloaterEnums::POSITIONING_CASCADING);
+ declare("centered", LLFloaterEnums::POSITIONING_CENTERED);
+ declare("specified", LLFloaterEnums::POSITIONING_SPECIFIED);
+ }
+}
+
+std::string LLFloater::sButtonNames[BUTTON_COUNT] =
+{
+ "llfloater_close_btn", //BUTTON_CLOSE
+ "llfloater_restore_btn", //BUTTON_RESTORE
+ "llfloater_minimize_btn", //BUTTON_MINIMIZE
+ "llfloater_tear_off_btn", //BUTTON_TEAR_OFF
+ "llfloater_dock_btn", //BUTTON_DOCK
+ "llfloater_help_btn" //BUTTON_HELP
+};
+
+std::string LLFloater::sButtonToolTips[BUTTON_COUNT];
+
+std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]=
+{
+#ifdef LL_DARWIN
+ "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE
+#else
+ "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE
+#endif
+ "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE
+ "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE
+ "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF
+ "BUTTON_DOCK",
+ "BUTTON_HELP"
+};
+
+LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
+{
+ LLFloater::onClickClose, //BUTTON_CLOSE
+ LLFloater::onClickMinimize, //BUTTON_RESTORE
+ LLFloater::onClickMinimize, //BUTTON_MINIMIZE
+ LLFloater::onClickTearOff, //BUTTON_TEAR_OFF
+ LLFloater::onClickDock, //BUTTON_DOCK
+ LLFloater::onClickHelp //BUTTON_HELP
+};
+
+LLMultiFloater* LLFloater::sHostp = NULL;
+bool LLFloater::sQuitting = false; // Flag to prevent storing visibility controls while quitting
+
+LLFloaterView* gFloaterView = NULL;
+
+/*==========================================================================*|
+// DEV-38598: The fundamental problem with this operation is that it can only
+// support a subset of LLSD values. While it's plausible to compare two arrays
+// lexicographically, what strict ordering can you impose on maps?
+// (LLFloaterTOS's current key is an LLSD map.)
+
+// Of course something like this is necessary if you want to build a std::set
+// or std::map with LLSD keys. Fortunately we're getting by with other
+// container types for now.
+
+//static
+bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b)
+{
+ if (a.type() != b.type())
+ {
+ //LL_ERRS() << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << LL_ENDL;
+ 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)
+{
+ return llsd_equals(a, b);
+}
+
+//************************************
+
+LLFloater::Params::Params()
+: title("title"),
+ short_title("short_title"),
+ single_instance("single_instance", false),
+ reuse_instance("reuse_instance", 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_dock_state("save_dock_state", false),
+ save_rect("save_rect", false),
+ save_visibility("save_visibility", false),
+ can_dock("can_dock", false),
+ show_title("show_title", true),
+ auto_close("auto_close", false),
+ positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE),
+ header_height("header_height", 0),
+ legacy_header_height("legacy_header_height", 0),
+ close_image("close_image"),
+ restore_image("restore_image"),
+ minimize_image("minimize_image"),
+ tear_off_image("tear_off_image"),
+ dock_image("dock_image"),
+ help_image("help_image"),
+ close_pressed_image("close_pressed_image"),
+ restore_pressed_image("restore_pressed_image"),
+ minimize_pressed_image("minimize_pressed_image"),
+ tear_off_pressed_image("tear_off_pressed_image"),
+ dock_pressed_image("dock_pressed_image"),
+ help_pressed_image("help_pressed_image"),
+ open_callback("open_callback"),
+ close_callback("close_callback"),
+ follows("follows"),
+ rel_x("rel_x", 0),
+ rel_y("rel_y", 0)
+{
+ changeDefault(visible, false);
+}
+
+
+//static
+const LLFloater::Params& LLFloater::getDefaultParams()
+{
+ return LLUICtrlFactory::getDefaultParams<LLFloater>();
+}
+
+//static
+void LLFloater::initClass()
+{
+ // translate tooltips for floater buttons
+ for (S32 i = 0; i < BUTTON_COUNT; i++)
+ {
+ sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] );
+ }
+
+ LLControlVariable* ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("ActiveFloaterTransparency").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency));
+ updateActiveFloaterTransparency();
+ }
+
+ ctrl = LLUI::getInstance()->mSettingGroups["config"]->getControl("InactiveFloaterTransparency").get();
+ if (ctrl)
+ {
+ ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency));
+ updateInactiveFloaterTransparency();
+ }
+
+}
+
+// defaults for floater param block pulled from widgets/floater.xml
+static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater");
+
+LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
+: LLPanel(), // intentionally do not pass params here, see initFromParams
+ mDragHandle(NULL),
+ mTitle(p.title),
+ mShortTitle(p.short_title),
+ mSingleInstance(p.single_instance),
+ mReuseInstance(p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance), // reuse single-instance floaters by default
+ mKey(key),
+ mCanTearOff(p.can_tear_off),
+ mCanMinimize(p.can_minimize),
+ mCanClose(p.can_close),
+ mDragOnLeft(p.can_drag_on_left),
+ mResizable(p.can_resize),
+ mAutoClose(p.auto_close),
+ mPositioning(p.positioning),
+ mMinWidth(p.min_width),
+ mMinHeight(p.min_height),
+ mHeaderHeight(p.header_height),
+ mLegacyHeaderHeight(p.legacy_header_height),
+ mDefaultRectForGroup(true),
+ mMinimized(false),
+ mForeground(false),
+ mFirstLook(true),
+ mButtonScale(1.0f),
+ mAutoFocus(true), // automatically take focus when opened
+ mCanDock(false),
+ mDocked(false),
+ mTornOff(false),
+ mHasBeenDraggedWhileMinimized(false),
+ mPreviousMinimizedBottom(0),
+ mPreviousMinimizedLeft(0),
+ mDefaultRelativeX(p.rel_x),
+ mDefaultRelativeY(p.rel_y),
+ mMinimizeSignal(NULL)
+// mNotificationContext(NULL)
+{
+ mPosition.setFloater(*this);
+// mNotificationContext = new LLFloaterNotificationContext(getHandle());
+
+ // Clicks stop here.
+ setMouseOpaque(true);
+
+ // Floaters always draw their background, unlike every other panel.
+ setBackgroundVisible(true);
+
+ // Floaters start not minimized. When minimized, they save their
+ // prior rectangle to be used on restore.
+ mExpandedRect.set(0,0,0,0);
+
+ memset(mButtonsEnabled, 0, BUTTON_COUNT * sizeof(bool));
+ memset(mButtons, 0, BUTTON_COUNT * sizeof(LLButton*));
+
+ addDragHandle();
+ addResizeCtrls();
+
+ initFromParams(p);
+
+ initFloater(p);
+}
+
+// Note: Floaters constructed from XML call init() twice!
+void LLFloater::initFloater(const Params& p)
+{
+ // Close button.
+ if (mCanClose)
+ {
+ mButtonsEnabled[BUTTON_CLOSE] = true;
+ }
+
+ // Help button: '?'
+ //SL-14050 Disable all Help question marks
+ mButtonsEnabled[BUTTON_HELP] = false;
+
+ // Minimize button only for top draggers
+ if ( !mDragOnLeft && mCanMinimize )
+ {
+ mButtonsEnabled[BUTTON_MINIMIZE] = true;
+ }
+
+ if(mCanDock)
+ {
+ mButtonsEnabled[BUTTON_DOCK] = true;
+ }
+
+ buildButtons(p);
+
+ // Floaters are created in the invisible state
+ setVisible(false);
+
+ if (!getParent())
+ {
+ gFloaterView->addChild(this);
+ }
+}
+
+void LLFloater::addDragHandle()
+{
+ if (!mDragHandle)
+ {
+ if (mDragOnLeft)
+ {
+ LLDragHandleLeft::Params p;
+ p.name("drag");
+ p.follows.flags(FOLLOWS_ALL);
+ p.label(mTitle);
+ mDragHandle = LLUICtrlFactory::create<LLDragHandleLeft>(p);
+ }
+ else // drag on top
+ {
+ LLDragHandleTop::Params p;
+ p.name("Drag Handle");
+ p.follows.flags(FOLLOWS_ALL);
+ p.label(mTitle);
+ mDragHandle = LLUICtrlFactory::create<LLDragHandleTop>(p);
+ }
+ addChild(mDragHandle);
+ }
+ layoutDragHandle();
+ applyTitle();
+}
+
+void LLFloater::layoutDragHandle()
+{
+ static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+ S32 close_box_size = mCanClose ? floater_close_box_size : 0;
+
+ LLRect rect;
+ if (mDragOnLeft)
+ {
+ rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
+ }
+ else // drag on top
+ {
+ rect = getLocalRect();
+ }
+ mDragHandle->setShape(rect);
+ updateTitleButtons();
+}
+
+// static
+void LLFloater::updateActiveFloaterTransparency()
+{
+ static LLCachedControl<F32> active_transparency(*LLUI::getInstance()->mSettingGroups["config"], "ActiveFloaterTransparency", 1.f);
+ sActiveControlTransparency = active_transparency;
+}
+
+// static
+void LLFloater::updateInactiveFloaterTransparency()
+{
+ static LLCachedControl<F32> inactive_transparency(*LLUI::getInstance()->mSettingGroups["config"], "InactiveFloaterTransparency", 0.95f);
+ sInactiveControlTransparency = inactive_transparency;
+}
+
+void LLFloater::addResizeCtrls()
+{
+ // Resize bars (sides)
+ LLResizeBar::Params p;
+ p.name("resizebar_left");
+ p.resizing_view(this);
+ p.min_size(mMinWidth);
+ p.side(LLResizeBar::LEFT);
+ mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create<LLResizeBar>(p);
+ addChild( mResizeBar[LLResizeBar::LEFT] );
+
+ p.name("resizebar_top");
+ p.min_size(mMinHeight);
+ p.side(LLResizeBar::TOP);
+
+ mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create<LLResizeBar>(p);
+ addChild( mResizeBar[LLResizeBar::TOP] );
+
+ p.name("resizebar_right");
+ p.min_size(mMinWidth);
+ p.side(LLResizeBar::RIGHT);
+ mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create<LLResizeBar>(p);
+ addChild( mResizeBar[LLResizeBar::RIGHT] );
+
+ p.name("resizebar_bottom");
+ p.min_size(mMinHeight);
+ p.side(LLResizeBar::BOTTOM);
+ mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create<LLResizeBar>(p);
+ addChild( mResizeBar[LLResizeBar::BOTTOM] );
+
+ // Resize handles (corners)
+ LLResizeHandle::Params handle_p;
+ // handles must not be mouse-opaque, otherwise they block hover events
+ // to other buttons like the close box. JC
+ handle_p.mouse_opaque(false);
+ handle_p.min_width(mMinWidth);
+ handle_p.min_height(mMinHeight);
+ handle_p.corner(LLResizeHandle::RIGHT_BOTTOM);
+ mResizeHandle[0] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+ addChild(mResizeHandle[0]);
+
+ handle_p.corner(LLResizeHandle::RIGHT_TOP);
+ mResizeHandle[1] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+ addChild(mResizeHandle[1]);
+
+ handle_p.corner(LLResizeHandle::LEFT_BOTTOM);
+ mResizeHandle[2] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+ addChild(mResizeHandle[2]);
+
+ handle_p.corner(LLResizeHandle::LEFT_TOP);
+ mResizeHandle[3] = LLUICtrlFactory::create<LLResizeHandle>(handle_p);
+ addChild(mResizeHandle[3]);
+
+ layoutResizeCtrls();
+}
+
+void LLFloater::layoutResizeCtrls()
+{
+ LLRect rect;
+
+ // Resize bars (sides)
+ const S32 RESIZE_BAR_THICKNESS = 3;
+ rect = LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0);
+ mResizeBar[LLResizeBar::LEFT]->setRect(rect);
+
+ rect = LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS);
+ mResizeBar[LLResizeBar::TOP]->setRect(rect);
+
+ rect = LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0);
+ mResizeBar[LLResizeBar::RIGHT]->setRect(rect);
+
+ rect = LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0);
+ mResizeBar[LLResizeBar::BOTTOM]->setRect(rect);
+
+ // Resize handles (corners)
+ rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0);
+ mResizeHandle[0]->setRect(rect);
+
+ rect = LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT);
+ mResizeHandle[1]->setRect(rect);
+
+ rect = LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 );
+ mResizeHandle[2]->setRect(rect);
+
+ rect = LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT );
+ mResizeHandle[3]->setRect(rect);
+}
+
+void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)
+{
+ mResizeBar[LLResizeBar::LEFT]->setVisible(enable && width);
+ mResizeBar[LLResizeBar::LEFT]->setEnabled(enable && width);
+
+ mResizeBar[LLResizeBar::TOP]->setVisible(enable && height);
+ mResizeBar[LLResizeBar::TOP]->setEnabled(enable && height);
+
+ mResizeBar[LLResizeBar::RIGHT]->setVisible(enable && width);
+ mResizeBar[LLResizeBar::RIGHT]->setEnabled(enable && width);
+
+ mResizeBar[LLResizeBar::BOTTOM]->setVisible(enable && height);
+ mResizeBar[LLResizeBar::BOTTOM]->setEnabled(enable && height);
+
+ for (S32 i = 0; i < 4; ++i)
+ {
+ mResizeHandle[i]->setVisible(enable && width && height);
+ mResizeHandle[i]->setEnabled(enable && width && height);
+ }
+}
+
+void LLFloater::destroy()
+{
+ // LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before
+ // it was deleted via LLMortician::updateClass(). See EXT-8458.
+ LLFloaterReg::removeInstance(mInstanceName, mKey);
+ die();
+}
+
+// virtual
+LLFloater::~LLFloater()
+{
+ if (!isDead())
+ {
+ // If it's dead, instance is supposed to be already removed, and
+ // in case of single instance we can remove new one by accident
+ LLFloaterReg::removeInstance(mInstanceName, mKey);
+ }
+
+ if( gFocusMgr.childHasKeyboardFocus(this))
+ {
+ // Just in case we might still have focus here, release it.
+ releaseFocus();
+ }
+
+ // This is important so that floaters with persistent rects (i.e., those
+ // created with rect control rather than an LLRect) are restored in their
+ // correct, non-minimized positions.
+ setMinimized( false );
+
+ delete mDragHandle;
+ for (S32 i = 0; i < 4; i++)
+ {
+ delete mResizeBar[i];
+ delete mResizeHandle[i];
+ }
+
+ setVisible(false); // We're not visible if we're destroyed
+ storeVisibilityControl();
+ storeDockStateControl();
+ delete mMinimizeSignal;
+}
+
+void LLFloater::storeRectControl()
+{
+ if (!mRectControl.empty())
+ {
+ getControlGroup()->setRect( mRectControl, getRect() );
+ }
+ if (!mPosXControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE)
+ {
+ getControlGroup()->setF32( mPosXControl, mPosition.mX );
+ }
+ if (!mPosYControl.empty() && mPositioning == LLFloaterEnums::POSITIONING_RELATIVE)
+ {
+ getControlGroup()->setF32( mPosYControl, mPosition.mY );
+ }
+}
+
+void LLFloater::storeVisibilityControl()
+{
+ if( !sQuitting && mVisibilityControl.size() > 1 )
+ {
+ getControlGroup()->setBOOL( mVisibilityControl, getVisible() );
+ }
+}
+
+void LLFloater::storeDockStateControl()
+{
+ if( !sQuitting && mDocStateControl.size() > 1 )
+ {
+ getControlGroup()->setBOOL( mDocStateControl, isDocked() );
+ }
+}
+
+// static
+std::string LLFloater::getControlName(const std::string& name, const LLSD& key)
+{
+ std::string ctrl_name = name;
+
+ // Add the key to the control name if appropriate.
+ if (key.isString() && !key.asString().empty())
+ {
+ ctrl_name += "_" + key.asString();
+ }
+
+ return ctrl_name;
+}
+
+// static
+LLControlGroup* LLFloater::getControlGroup()
+{
+ // Floater size, position, visibility, etc are saved in per-account settings.
+ return LLUI::getInstance()->mSettingGroups["account"];
+}
+
+void LLFloater::setVisible( bool visible )
+{
+ LLPanel::setVisible(visible); // calls onVisibilityChange()
+ if( visible && mFirstLook )
+ {
+ mFirstLook = false;
+ }
+
+ if( !visible )
+ {
+ LLUI::getInstance()->removePopup(this);
+
+ if( gFocusMgr.childHasMouseCapture( this ) )
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ }
+ }
+
+ for(handle_set_iter_t dependent_it = mDependents.begin();
+ dependent_it != mDependents.end(); )
+ {
+ LLFloater* floaterp = dependent_it->get();
+
+ if (floaterp)
+ {
+ floaterp->setVisible(visible);
+ }
+ ++dependent_it;
+ }
+
+ storeVisibilityControl();
+}
+
+
+void LLFloater::setIsSingleInstance(bool is_single_instance)
+{
+ mSingleInstance = is_single_instance;
+ if (!mIsReuseInitialized)
+ {
+ mReuseInstance = is_single_instance; // reuse single-instance floaters by default
+ }
+}
+
+
+// virtual
+void LLFloater::onVisibilityChange ( bool new_visibility )
+{
+ if (new_visibility)
+ {
+ if (getHost())
+ getHost()->setFloaterFlashing(this, false);
+ }
+ LLPanel::onVisibilityChange ( new_visibility );
+}
+
+void LLFloater::openFloater(const LLSD& key)
+{
+ LL_INFOS() << "Opening floater " << getName() << " full path: " << getPathname() << LL_ENDL;
+
+ LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), true,"floater"); // Last param is event subtype or empty string
+
+ mKey = key; // in case we need to open ourselves again
+
+ if (getSoundFlags() != SILENT
+ // don't play open sound for hosted (tabbed) windows
+ && !getHost()
+ && !getFloaterHost()
+ && (!getVisible() || isMinimized()))
+ {
+ make_ui_sound("UISndWindowOpen");
+ }
+
+ //RN: for now, we don't allow rehosting from one multifloater to another
+ // just need to fix the bugs
+ if (getFloaterHost() != NULL && getHost() == NULL)
+ {
+ // needs a host
+ // only select tabs if window they are hosted in is visible
+ getFloaterHost()->addFloater(this, getFloaterHost()->getVisible());
+ }
+
+ if (getHost() != NULL)
+ {
+ getHost()->setMinimized(false);
+ getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
+ getHost()->showFloater(this);
+ }
+ else
+ {
+ LLFloater* floater_to_stack = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
+ if (!floater_to_stack)
+ {
+ floater_to_stack = LLFloaterReg::getLastFloaterCascading();
+ }
+ applyControlsAndPosition(floater_to_stack);
+ setMinimized(false);
+ setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
+ }
+
+ mOpenSignal(this, key);
+ onOpen(key);
+
+ dirtyRect();
+}
+
+void LLFloater::closeFloater(bool app_quitting)
+{
+ LL_INFOS() << "Closing floater " << getName() << LL_ENDL;
+ LLViewerEventRecorder::instance().logVisibilityChange( getPathname(), getName(), false,"floater"); // Last param is event subtype or empty string
+ if (app_quitting)
+ {
+ LLFloater::sQuitting = true;
+ }
+
+ // Always unminimize before trying to close.
+ // Most of the time the user will never see this state.
+ setMinimized(false);
+
+ if (canClose())
+ {
+ if (getHost())
+ {
+ ((LLMultiFloater*)getHost())->removeFloater(this);
+ gFloaterView->addChild(this);
+ }
+
+ if (getSoundFlags() != SILENT
+ && getVisible()
+ && !getHost()
+ && !app_quitting)
+ {
+ make_ui_sound("UISndWindowClose");
+ }
+
+ gFocusMgr.clearLastFocusForGroup(this);
+
+ if (hasFocus())
+ {
+ // Do this early, so UI controls will commit before the
+ // window is taken down.
+ releaseFocus();
+
+ // give focus to dependee floater if it exists, and we had focus first
+ if (isDependent())
+ {
+ LLFloater* dependee = mDependeeHandle.get();
+ if (dependee && !dependee->isDead())
+ {
+ dependee->setFocus(true);
+ }
+ }
+ }
+
+
+ //If floater is a dependent, remove it from parent (dependee)
+ LLFloater* dependee = mDependeeHandle.get();
+ if (dependee)
+ {
+ dependee->removeDependentFloater(this);
+ }
+
+ // now close dependent floater
+ while(mDependents.size() > 0)
+ {
+ handle_set_iter_t dependent_it = mDependents.begin();
+ LLFloater* floaterp = dependent_it->get();
+ // normally removeDependentFloater will do this, but in
+ // case floaterp is somehow invalid or orphaned, erase now
+ mDependents.erase(dependent_it);
+ if (floaterp)
+ {
+ floaterp->mDependeeHandle = LLHandle<LLFloater>();
+ floaterp->closeFloater(app_quitting);
+ }
+ }
+
+ cleanupHandles();
+
+ dirtyRect();
+
+ // Close callbacks
+ onClose(app_quitting);
+ mCloseSignal(this, LLSD(app_quitting));
+
+ // Hide or Destroy
+ if (mSingleInstance)
+ {
+ // Hide the instance
+ if (getHost())
+ {
+ getHost()->setVisible(false);
+ }
+ else
+ {
+ setVisible(false);
+ if (!mReuseInstance)
+ {
+ destroy();
+ }
+ }
+ }
+ else
+ {
+ setVisible(false); // hide before destroying (so onVisibilityChange() gets called)
+ if (!mReuseInstance)
+ {
+ destroy();
+ }
+ }
+ }
+}
+
+/*virtual*/
+void LLFloater::closeHostedFloater()
+{
+ // When toggling *visibility*, close the host instead of the floater when hosted
+ if (getHost())
+ {
+ getHost()->closeFloater();
+ }
+ else
+ {
+ closeFloater();
+ }
+}
+
+/*virtual*/
+void LLFloater::reshape(S32 width, S32 height, bool called_from_parent)
+{
+ LLPanel::reshape(width, height, called_from_parent);
+}
+
+// virtual
+void LLFloater::translate(S32 x, S32 y)
+{
+ LLView::translate(x, y);
+
+ if (!mTranslateWithDependents || mDependents.empty())
+ return;
+
+ for (const LLHandle<LLFloater>& handle : mDependents)
+ {
+ LLFloater* floater = handle.get();
+ if (floater && floater->getSnapTarget() == getHandle())
+ {
+ floater->LLView::translate(x, y);
+ }
+ }
+}
+
+void LLFloater::releaseFocus()
+{
+ LLUI::getInstance()->removePopup(this);
+
+ setFocus(false);
+
+ if( gFocusMgr.childHasMouseCapture( this ) )
+ {
+ gFocusMgr.setMouseCapture(NULL);
+ }
+}
+
+
+void LLFloater::setResizeLimits( S32 min_width, S32 min_height )
+{
+ mMinWidth = min_width;
+ mMinHeight = min_height;
+
+ for( S32 i = 0; i < 4; i++ )
+ {
+ if( mResizeBar[i] )
+ {
+ if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
+ {
+ mResizeBar[i]->setResizeLimits( min_width, S32_MAX );
+ }
+ else
+ {
+ mResizeBar[i]->setResizeLimits( min_height, S32_MAX );
+ }
+ }
+ if( mResizeHandle[i] )
+ {
+ mResizeHandle[i]->setResizeLimits( min_width, min_height );
+ }
+ }
+}
+
+
+void LLFloater::center()
+{
+ if(getHost())
+ {
+ // hosted floaters can't move
+ return;
+ }
+ centerWithin(gFloaterView->getRect());
+}
+
+LLMultiFloater* LLFloater::getHost()
+{
+ return (LLMultiFloater*)mHostHandle.get();
+}
+
+void LLFloater::applyControlsAndPosition(LLFloater* other)
+{
+ if (!applyDockState())
+ {
+ if (!applyRectControl())
+ {
+ applyPositioning(other, true);
+ }
+ }
+}
+
+bool LLFloater::applyRectControl()
+{
+ bool saved_rect = false;
+
+ LLRect screen_rect = calcScreenRect();
+ mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
+
+ LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName);
+ if (last_in_group && last_in_group != this)
+ {
+ // other floaters in our group, position ourselves relative to them and don't save the rect
+ if (mDefaultRectForGroup)
+ {
+ mRectControl.clear();
+ }
+ mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;
+ }
+ else
+ {
+ bool rect_specified = false;
+ if (!mRectControl.empty())
+ {
+ // If we have a saved rect, use it
+ const LLRect& rect = getControlGroup()->getRect(mRectControl);
+ if (rect.notEmpty()) saved_rect = true;
+ if (saved_rect)
+ {
+ setOrigin(rect.mLeft, rect.mBottom);
+
+ if (mResizable)
+ {
+ reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
+ }
+ mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
+ LLRect screen_rect = calcScreenRect();
+ mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
+ rect_specified = true;
+ }
+ }
+
+ LLControlVariablePtr x_control = getControlGroup()->getControl(mPosXControl);
+ LLControlVariablePtr y_control = getControlGroup()->getControl(mPosYControl);
+ if (x_control.notNull()
+ && y_control.notNull()
+ && !x_control->isDefault()
+ && !y_control->isDefault())
+ {
+ mPosition.mX = x_control->getValue().asReal();
+ mPosition.mY = y_control->getValue().asReal();
+ mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
+ applyRelativePosition();
+
+ saved_rect = true;
+ }
+ else if ((mDefaultRelativeX != 0) && (mDefaultRelativeY != 0))
+ {
+ mPosition.mX = mDefaultRelativeX;
+ mPosition.mY = mDefaultRelativeY;
+ mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
+ applyRelativePosition();
+
+ saved_rect = true;
+ }
+
+ // remember updated position
+ if (rect_specified)
+ {
+ storeRectControl();
+ }
+ }
+
+ if (saved_rect)
+ {
+ // propagate any derived positioning data back to settings file
+ storeRectControl();
+ }
+
+
+ return saved_rect;
+}
+
+bool LLFloater::applyDockState()
+{
+ bool docked = false;
+
+ if (mDocStateControl.size() > 1)
+ {
+ docked = getControlGroup()->getBOOL(mDocStateControl);
+ setDocked(docked);
+ }
+
+ return docked;
+}
+
+void LLFloater::applyPositioning(LLFloater* other, bool on_open)
+{
+ // Otherwise position according to the positioning code
+ switch (mPositioning)
+ {
+ case LLFloaterEnums::POSITIONING_CENTERED:
+ center();
+ break;
+
+ case LLFloaterEnums::POSITIONING_SPECIFIED:
+ break;
+
+ case LLFloaterEnums::POSITIONING_CASCADING:
+ if (!on_open)
+ {
+ applyRelativePosition();
+ }
+ // fall through
+ case LLFloaterEnums::POSITIONING_CASCADE_GROUP:
+ if (on_open)
+ {
+ if (other != NULL && other != this)
+ {
+ stackWith(*other);
+ }
+ else
+ {
+ static const U32 CASCADING_FLOATER_HOFFSET = 0;
+ static const U32 CASCADING_FLOATER_VOFFSET = 0;
+
+ const LLRect& snap_rect = gFloaterView->getSnapRect();
+
+ const S32 horizontal_offset = CASCADING_FLOATER_HOFFSET;
+ const S32 vertical_offset = snap_rect.getHeight() - CASCADING_FLOATER_VOFFSET;
+
+ S32 rect_height = getRect().getHeight();
+ setOrigin(horizontal_offset, vertical_offset - rect_height);
+
+ translate(snap_rect.mLeft, snap_rect.mBottom);
+ }
+ setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
+ }
+ break;
+
+ case LLFloaterEnums::POSITIONING_RELATIVE:
+ {
+ applyRelativePosition();
+
+ break;
+ }
+ default:
+ // Do nothing
+ break;
+ }
+}
+
+void LLFloater::applyTitle()
+{
+ if (!mDragHandle)
+ {
+ return;
+ }
+
+ if (isMinimized() && !mShortTitle.empty())
+ {
+ mDragHandle->setTitle( mShortTitle );
+ }
+ else
+ {
+ mDragHandle->setTitle ( mTitle );
+ }
+
+ if (getHost())
+ {
+ getHost()->updateFloaterTitle(this);
+ }
+}
+
+std::string LLFloater::getCurrentTitle() const
+{
+ return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
+}
+
+void LLFloater::setTitle( const std::string& title )
+{
+ mTitle = title;
+ applyTitle();
+}
+
+std::string LLFloater::getTitle() const
+{
+ if (mTitle.empty())
+ {
+ return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
+ }
+ else
+ {
+ return mTitle;
+ }
+}
+
+void LLFloater::setShortTitle( const std::string& short_title )
+{
+ mShortTitle = short_title;
+ applyTitle();
+}
+
+std::string LLFloater::getShortTitle() const
+{
+ if (mShortTitle.empty())
+ {
+ return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
+ }
+ else
+ {
+ return mShortTitle;
+ }
+}
+
+bool LLFloater::canSnapTo(const LLView* other_view)
+{
+ if (NULL == other_view)
+ {
+ LL_WARNS() << "other_view is NULL" << LL_ENDL;
+ return false;
+ }
+
+ if (other_view != getParent())
+ {
+ const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view);
+ if (other_floaterp
+ && other_floaterp->getSnapTarget() == getHandle()
+ && mDependents.find(other_floaterp->getHandle()) != mDependents.end())
+ {
+ // this is a dependent that is already snapped to us, so don't snap back to it
+ return false;
+ }
+ }
+
+ return LLPanel::canSnapTo(other_view);
+}
+
+void LLFloater::setSnappedTo(const LLView* snap_view)
+{
+ if (!snap_view || snap_view == getParent())
+ {
+ clearSnapTarget();
+ }
+ else
+ {
+ //RN: assume it's a floater as it must be a sibling to our parent floater
+ const LLFloater* floaterp = dynamic_cast<const LLFloater*>(snap_view);
+ if (floaterp)
+ {
+ setSnapTarget(floaterp->getHandle());
+ }
+ }
+}
+
+void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
+{
+ const LLRect old_rect = getRect();
+ LLView::handleReshape(new_rect, by_user);
+
+ if (by_user && !getHost())
+ {
+ LLFloaterView * floaterVp = dynamic_cast<LLFloaterView*>(getParent());
+ if (floaterVp)
+ {
+ floaterVp->adjustToFitScreen(this, !isMinimized());
+ }
+ }
+
+ // if not minimized, adjust all snapped dependents to new shape
+ if (!isMinimized())
+ {
+ if (by_user)
+ {
+ if (isDocked())
+ {
+ setDocked( false, false);
+ }
+ mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
+ LLRect screen_rect = calcScreenRect();
+ mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
+ }
+ storeRectControl();
+
+ // gather all snapped dependents
+ for(handle_set_iter_t dependent_it = mDependents.begin();
+ dependent_it != mDependents.end(); ++dependent_it)
+ {
+ LLFloater* floaterp = dependent_it->get();
+ // is a dependent snapped to us?
+ if (floaterp && floaterp->getSnapTarget() == getHandle())
+ {
+ S32 delta_x = 0;
+ S32 delta_y = 0;
+ // check to see if it snapped to right or top, and move if dependee floater is resizing
+ LLRect dependent_rect = floaterp->getRect();
+ if (dependent_rect.mLeft - getRect().mLeft >= old_rect.getWidth() || // dependent on my right?
+ dependent_rect.mRight == getRect().mLeft + old_rect.getWidth()) // dependent aligned with my right
+ {
+ // was snapped directly onto right side or aligned with it
+ delta_x += new_rect.getWidth() - old_rect.getWidth();
+ }
+ if (dependent_rect.mBottom - getRect().mBottom >= old_rect.getHeight() ||
+ dependent_rect.mTop == getRect().mBottom + old_rect.getHeight())
+ {
+ // was snapped directly onto top side or aligned with it
+ delta_y += new_rect.getHeight() - old_rect.getHeight();
+ }
+
+ // take translation of dependee floater into account as well
+ delta_x += new_rect.mLeft - old_rect.mLeft;
+ delta_y += new_rect.mBottom - old_rect.mBottom;
+
+ dependent_rect.translate(delta_x, delta_y);
+ floaterp->setShape(dependent_rect, by_user);
+ }
+ }
+ }
+ else
+ {
+ // If minimized, and origin has changed, set
+ // mHasBeenDraggedWhileMinimized to true
+ if ((new_rect.mLeft != old_rect.mLeft) ||
+ (new_rect.mBottom != old_rect.mBottom))
+ {
+ mHasBeenDraggedWhileMinimized = true;
+ }
+ }
+}
+
+void LLFloater::setMinimized(bool minimize)
+{
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
+ static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
+
+ if (minimize == mMinimized) return;
+
+ if (mMinimizeSignal)
+ {
+ (*mMinimizeSignal)(this, LLSD(minimize));
+ }
+
+ if (minimize)
+ {
+ // minimized flag should be turned on before release focus
+ mMinimized = true;
+ mExpandedRect = getRect();
+
+ // If the floater has been dragged while minimized in the
+ // past, then locate it at its previous minimized location.
+ // Otherwise, ask the view for a minimize position.
+ if (mHasBeenDraggedWhileMinimized)
+ {
+ setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
+ }
+ else
+ {
+ S32 left, bottom;
+ gFloaterView->getMinimizePosition(&left, &bottom);
+ setOrigin( left, bottom );
+ }
+
+ if (mButtonsEnabled[BUTTON_MINIMIZE])
+ {
+ mButtonsEnabled[BUTTON_MINIMIZE] = false;
+ mButtonsEnabled[BUTTON_RESTORE] = true;
+ }
+
+ setBorderVisible(true);
+
+ for(handle_set_iter_t dependent_it = mDependents.begin();
+ dependent_it != mDependents.end();
+ ++dependent_it)
+ {
+ LLFloater* floaterp = dependent_it->get();
+ if (floaterp)
+ {
+ if (floaterp->isMinimizeable())
+ {
+ floaterp->setMinimized(true);
+ }
+ else if (!floaterp->isMinimized())
+ {
+ floaterp->setVisible(false);
+ }
+ }
+ }
+
+ // Lose keyboard focus when minimized
+ releaseFocus();
+
+ for (S32 i = 0; i < 4; i++)
+ {
+ if (mResizeBar[i] != NULL)
+ {
+ mResizeBar[i]->setEnabled(false);
+ }
+ if (mResizeHandle[i] != NULL)
+ {
+ mResizeHandle[i]->setEnabled(false);
+ }
+ }
+
+ // Reshape *after* setting mMinimized
+ reshape( minimized_width, floater_header_size, true);
+ }
+ else
+ {
+ // If this window has been dragged while minimized (at any time),
+ // remember its position for the next time it's minimized.
+ if (mHasBeenDraggedWhileMinimized)
+ {
+ const LLRect& currentRect = getRect();
+ mPreviousMinimizedLeft = currentRect.mLeft;
+ mPreviousMinimizedBottom = currentRect.mBottom;
+ }
+
+ setOrigin( mExpandedRect.mLeft, mExpandedRect.mBottom );
+ if (mButtonsEnabled[BUTTON_RESTORE])
+ {
+ mButtonsEnabled[BUTTON_MINIMIZE] = true;
+ mButtonsEnabled[BUTTON_RESTORE] = false;
+ }
+
+ // show dependent floater
+ for(handle_set_iter_t dependent_it = mDependents.begin();
+ dependent_it != mDependents.end();
+ ++dependent_it)
+ {
+ LLFloater* floaterp = dependent_it->get();
+ if (floaterp)
+ {
+ floaterp->setMinimized(false);
+ floaterp->setVisible(true);
+ }
+ }
+
+ for (S32 i = 0; i < 4; i++)
+ {
+ if (mResizeBar[i] != NULL)
+ {
+ mResizeBar[i]->setEnabled(isResizable());
+ }
+ if (mResizeHandle[i] != NULL)
+ {
+ mResizeHandle[i]->setEnabled(isResizable());
+ }
+ }
+
+ mMinimized = false;
+ setFrontmost();
+ // Reshape *after* setting mMinimized
+ reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), true );
+ }
+
+ make_ui_sound("UISndWindowClose");
+ updateTitleButtons();
+ applyTitle ();
+}
+
+void LLFloater::setFocus( bool b )
+{
+ if (b && getIsChrome())
+ {
+ return;
+ }
+ LLView* last_focus = gFocusMgr.getLastFocusForGroup(this);
+ // a descendent already has focus
+ bool child_had_focus = hasFocus();
+
+ // give focus to first valid descendent
+ LLPanel::setFocus(b);
+
+ if (b)
+ {
+ // only push focused floaters to front of stack if not in midst of ctrl-tab cycle
+ LLFloaterView * parent = dynamic_cast<LLFloaterView *>(getParent());
+ if (!getHost() && parent && !parent->getCycleMode())
+ {
+ if (!isFrontmost())
+ {
+ setFrontmost();
+ }
+ }
+
+ // when getting focus, delegate to last descendent which had focus
+ if (last_focus && !child_had_focus &&
+ last_focus->isInEnabledChain() &&
+ last_focus->isInVisibleChain())
+ {
+ // *FIX: should handle case where focus doesn't stick
+ last_focus->setFocus(true);
+ }
+ }
+ updateTransparency(b ? TT_ACTIVE : TT_INACTIVE);
+}
+
+// virtual
+void LLFloater::setRect(const LLRect &rect)
+{
+ LLPanel::setRect(rect);
+ layoutDragHandle();
+ layoutResizeCtrls();
+}
+
+// virtual
+void LLFloater::setIsChrome(bool is_chrome)
+{
+ // chrome floaters don't take focus at all
+ if (is_chrome)
+ {
+ // remove focus if we're changing to chrome
+ setFocus(false);
+ // can't Ctrl-Tab to "chrome" floaters
+ setFocusRoot(false);
+ mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome)));
+ }
+
+ LLPanel::setIsChrome(is_chrome);
+}
+
+// Change the draw style to account for the foreground state.
+void LLFloater::setForeground(bool front)
+{
+ if (front != mForeground)
+ {
+ mForeground = front;
+ if (mDragHandle)
+ mDragHandle->setForeground( front );
+
+ if (!front)
+ {
+ releaseFocus();
+ }
+
+ setBackgroundOpaque( front );
+ }
+}
+
+void LLFloater::cleanupHandles()
+{
+ // remove handles to non-existent dependents
+ for(handle_set_iter_t dependent_it = mDependents.begin();
+ dependent_it != mDependents.end(); )
+ {
+ LLFloater* floaterp = dependent_it->get();
+ if (!floaterp)
+ {
+ dependent_it = mDependents.erase(dependent_it);
+ }
+ else
+ {
+ ++dependent_it;
+ }
+ }
+}
+
+void LLFloater::setHost(LLMultiFloater* host)
+{
+ if (mHostHandle.isDead() && host)
+ {
+ // make buttons smaller for hosted windows to differentiate from parent
+ mButtonScale = 0.9f;
+
+ // add tear off button
+ if (mCanTearOff)
+ {
+ mButtonsEnabled[BUTTON_TEAR_OFF] = true;
+ }
+ }
+ else if (!mHostHandle.isDead() && !host)
+ {
+ mButtonScale = 1.f;
+ //mButtonsEnabled[BUTTON_TEAR_OFF] = false;
+ }
+ if (host)
+ {
+ mHostHandle = host->getHandle();
+ mLastHostHandle = host->getHandle();
+ }
+ else
+ {
+ mHostHandle.markDead();
+ }
+
+ updateTitleButtons();
+}
+
+void LLFloater::moveResizeHandlesToFront()
+{
+ for( S32 i = 0; i < 4; i++ )
+ {
+ if( mResizeBar[i] )
+ {
+ sendChildToFront(mResizeBar[i]);
+ }
+ }
+
+ for( S32 i = 0; i < 4; i++ )
+ {
+ if( mResizeHandle[i] )
+ {
+ sendChildToFront(mResizeHandle[i]);
+ }
+ }
+}
+
+/*virtual*/
+bool LLFloater::isFrontmost()
+{
+ LLFloaterView* floater_view = getParentByType<LLFloaterView>();
+ return getVisible()
+ && (floater_view
+ && floater_view->getFrontmost() == this);
+}
+
+void LLFloater::addDependentFloater(LLFloater* floaterp, bool reposition, bool resize)
+{
+ mDependents.insert(floaterp->getHandle());
+ floaterp->mDependeeHandle = getHandle();
+
+ if (reposition)
+ {
+ LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp);
+ if (resize)
+ {
+ const LLRect& base = getRect();
+ if (rect.mTop == base.mTop)
+ rect.mBottom = base.mBottom;
+ else if (rect.mLeft == base.mLeft)
+ rect.mRight = base.mRight;
+ floaterp->reshape(rect.getWidth(), rect.getHeight(), false);
+ }
+ floaterp->setRect(rect);
+ floaterp->setSnapTarget(getHandle());
+ }
+ gFloaterView->adjustToFitScreen(floaterp, false, true);
+ if (floaterp->isFrontmost())
+ {
+ // make sure to bring self and sibling floaters to front
+ gFloaterView->bringToFront(floaterp, floaterp->getAutoFocus() && !getIsChrome());
+ }
+}
+
+void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, bool reposition, bool resize)
+{
+ LLFloater* dependent_floaterp = dependent.get();
+ if(dependent_floaterp)
+ {
+ addDependentFloater(dependent_floaterp, reposition, resize);
+ }
+}
+
+void LLFloater::removeDependentFloater(LLFloater* floaterp)
+{
+ mDependents.erase(floaterp->getHandle());
+ floaterp->mDependeeHandle = LLHandle<LLFloater>();
+}
+
+void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels)
+{
+ LLRect total_rect = getRect();
+
+ for (const LLHandle<LLFloater>& handle : mDependents)
+ {
+ LLFloater* floater = handle.get();
+ if (floater && floater->getSnapTarget() == getHandle())
+ {
+ total_rect.unionWith(floater->getRect());
+ }
+ }
+
+ S32 delta_left = left.notEmpty() ? left.mRight - total_rect.mRight : 0;
+ S32 delta_bottom = bottom.notEmpty() ? bottom.mTop - total_rect.mTop : 0;
+ S32 delta_right = right.notEmpty() ? right.mLeft - total_rect.mLeft : 0;
+
+ // move floater with dependings fully onscreen
+ mTranslateWithDependents = true;
+ if (translateRectIntoRect(total_rect, constraint, min_overlap_pixels))
+ {
+ clearSnapTarget();
+ }
+ else if (delta_left > 0 && total_rect.mTop < left.mTop && total_rect.mBottom > left.mBottom)
+ {
+ translate(delta_left, 0);
+ }
+ else if (delta_bottom > 0 && total_rect.mLeft > bottom.mLeft && total_rect.mRight < bottom.mRight)
+ {
+ translate(0, delta_bottom);
+ }
+ else if (delta_right < 0 && total_rect.mTop < right.mTop && total_rect.mBottom > right.mBottom)
+ {
+ translate(delta_right, 0);
+ }
+ mTranslateWithDependents = false;
+}
+
+bool LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index)
+{
+ if( mButtonsEnabled[index] )
+ {
+ LLButton* my_butt = mButtons[index];
+ S32 local_x = x - my_butt->getRect().mLeft;
+ S32 local_y = y - my_butt->getRect().mBottom;
+
+ if (
+ my_butt->pointInView(local_x, local_y) &&
+ my_butt->handleMouseDown(local_x, local_y, mask))
+ {
+ // the button handled it
+ return true;
+ }
+ }
+ return false;
+}
+
+bool LLFloater::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ LLPanel::handleScrollWheel(x,y,clicks);
+ return true;//always
+}
+
+// virtual
+bool LLFloater::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ LL_DEBUGS() << "LLFloater::handleMouseUp calling LLPanel (really LLView)'s handleMouseUp (first initialized xui to: " << getPathname() << " )" << LL_ENDL;
+ bool handled = LLPanel::handleMouseUp(x,y,mask); // Not implemented in LLPanel so this actually calls LLView
+ if (handled) {
+ LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
+ }
+ return handled;
+}
+
+// virtual
+bool LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if( mMinimized )
+ {
+ // Offer the click to titlebar buttons.
+ // Note: this block and the offerClickToButton helper method can be removed
+ // because the parent container will handle it for us but we'll keep it here
+ // for safety until after reworking the panel code to manage hidden children.
+ if(offerClickToButton(x, y, mask, BUTTON_CLOSE)) return true;
+ if(offerClickToButton(x, y, mask, BUTTON_RESTORE)) return true;
+ if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return true;
+ if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return true;
+
+ setFrontmost(true, false);
+ // Otherwise pass to drag handle for movement
+ return mDragHandle->handleMouseDown(x, y, mask);
+ }
+ else
+ {
+ bringToFront( x, y );
+ bool handled = LLPanel::handleMouseDown( x, y, mask );
+ if (handled) {
+ LLViewerEventRecorder::instance().updateMouseEventInfo(x,y,-55,-55,getPathname());
+ }
+ return handled;
+ }
+}
+
+// virtual
+bool LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+ bool was_minimized = mMinimized;
+ bringToFront( x, y );
+ return was_minimized || LLPanel::handleRightMouseDown( x, y, mask );
+}
+
+bool LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
+{
+ bringToFront( x, y );
+ return LLPanel::handleMiddleMouseDown( x, y, mask );
+}
+
+
+// virtual
+bool LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+ bool was_minimized = mMinimized;
+ setMinimized(false);
+ return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
+}
+
+// virtual
+void LLFloater::bringToFront( S32 x, S32 y )
+{
+ if (getVisible() && pointInView(x, y))
+ {
+ LLMultiFloater* hostp = getHost();
+ if (hostp)
+ {
+ hostp->showFloater(this);
+ }
+ else
+ {
+ LLFloaterView* parent = dynamic_cast<LLFloaterView*>( getParent() );
+ if (parent)
+ {
+ parent->bringToFront(this, !getIsChrome());
+ }
+ }
+ }
+}
+
+// virtual
+void LLFloater::goneFromFront()
+{
+ if (mAutoClose)
+ {
+ closeFloater();
+ }
+}
+
+// virtual
+void LLFloater::setVisibleAndFrontmost(bool take_focus,const LLSD& key)
+{
+ LLUIUsage::instance().logFloater(getInstanceName());
+ LLMultiFloater* hostp = getHost();
+ if (hostp)
+ {
+ hostp->setVisible(true);
+ hostp->setFrontmost(take_focus);
+ }
+ else
+ {
+ setVisible(true);
+ setFrontmost(take_focus);
+ }
+}
+
+void LLFloater::setFrontmost(bool take_focus, bool restore)
+{
+ LLMultiFloater* hostp = getHost();
+ if (hostp)
+ {
+ // this will bring the host floater to the front and select
+ // the appropriate panel
+ hostp->showFloater(this);
+ }
+ else
+ {
+ // there are more than one floater view
+ // so we need to query our parent directly
+ LLFloaterView * parent = dynamic_cast<LLFloaterView*>( getParent() );
+ if (parent)
+ {
+ parent->bringToFront(this, take_focus, restore);
+ }
+
+ // Make sure to set the appropriate transparency type (STORM-732).
+ updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE);
+ }
+}
+
+void LLFloater::setCanDock(bool b)
+{
+ if(b != mCanDock)
+ {
+ mCanDock = b;
+ if(mCanDock)
+ {
+ mButtonsEnabled[BUTTON_DOCK] = !mDocked;
+ }
+ else
+ {
+ mButtonsEnabled[BUTTON_DOCK] = false;
+ }
+ }
+ updateTitleButtons();
+}
+
+void LLFloater::setDocked(bool docked, bool pop_on_undock)
+{
+ if(docked != mDocked && mCanDock)
+ {
+ mDocked = docked;
+ mButtonsEnabled[BUTTON_DOCK] = !mDocked;
+
+ if (mDocked)
+ {
+ setMinimized(false);
+ mPositioning = LLFloaterEnums::POSITIONING_RELATIVE;
+ }
+
+ updateTitleButtons();
+
+ storeDockStateControl();
+ }
+
+}
+
+// static
+void LLFloater::onClickMinimize(LLFloater* self)
+{
+ if (!self)
+ return;
+ self->setMinimized( !self->isMinimized() );
+}
+
+void LLFloater::onClickTearOff(LLFloater* self)
+{
+ if (!self)
+ return;
+ S32 floater_header_size = self->mHeaderHeight;
+ LLMultiFloater* host_floater = self->getHost();
+ if (host_floater) //Tear off
+ {
+ LLRect new_rect;
+ host_floater->removeFloater(self);
+ // reparent to floater view
+ gFloaterView->addChild(self);
+
+ self->openFloater(self->getKey());
+ if (self->mSaveRect && !self->mRectControl.empty())
+ {
+ self->applyRectControl();
+ }
+ else
+ { // only force position for floaters that don't have that data saved
+ 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);
+ // give focus to new window to keep continuity for the user
+ self->setFocus(true);
+ self->setTornOff(true);
+ }
+ else //Attach to parent.
+ {
+ LLMultiFloater* new_host = (LLMultiFloater*)self->mLastHostHandle.get();
+ if (new_host)
+ {
+ if (self->mSaveRect)
+ {
+ LLRect screen_rect = self->calcScreenRect();
+ self->mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert();
+ self->storeRectControl();
+ }
+ self->setMinimized(false); // to reenable minimize button if it was minimized
+ new_host->showFloater(self);
+ // make sure host is visible
+ new_host->openFloater(new_host->getKey());
+ }
+ self->setTornOff(false);
+ }
+ self->updateTitleButtons();
+ self->setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE);
+}
+
+// static
+void LLFloater::onClickDock(LLFloater* self)
+{
+ if(self && self->mCanDock)
+ {
+ self->setDocked(!self->mDocked, true);
+ }
+}
+
+// static
+void LLFloater::onClickHelp( LLFloater* self )
+{
+ if (self && LLUI::getInstance()->mHelpImpl)
+ {
+ // find the current help context for this floater
+ std::string help_topic;
+ if (self->findHelpTopic(help_topic))
+ {
+ LLUI::getInstance()->mHelpImpl->showTopic(help_topic);
+ }
+ }
+}
+
+void LLFloater::initRectControl()
+{
+ // save_rect and save_visibility only apply to registered floaters
+ if (mSaveRect)
+ {
+ std::string ctrl_name = getControlName(mInstanceName, mKey);
+ mRectControl = LLFloaterReg::declareRectControl(ctrl_name);
+ mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name);
+ mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name);
+ }
+}
+
+// static
+void LLFloater::closeFrontmostFloater()
+{
+ LLFloater* floater_to_close = gFloaterView->getFrontmostClosableFloater();
+ if(floater_to_close)
+ {
+ floater_to_close->closeFloater();
+ }
+
+ // if nothing took focus after closing focused floater
+ // give it to next floater (to allow closing multiple windows via keyboard in rapid succession)
+ if (gFocusMgr.getKeyboardFocus() == NULL)
+ {
+ // HACK: use gFloaterView directly in case we are using Ctrl-W to close snapshot window
+ // which sits in gSnapshotFloaterView, and needs to pass focus on to normal floater view
+ gFloaterView->focusFrontFloater();
+ }
+}
+
+
+// static
+void LLFloater::onClickClose( LLFloater* self )
+{
+ if (!self)
+ return;
+ self->onClickCloseBtn();
+}
+
+void LLFloater::onClickCloseBtn(bool app_quitting)
+{
+ closeFloater(false);
+}
+
+
+// virtual
+void LLFloater::draw()
+{
+ const F32 alpha = getCurrentTransparency();
+
+ // draw background
+ if( isBackgroundVisible() )
+ {
+ drawShadow(this);
+
+ S32 left = LLPANEL_BORDER_WIDTH;
+ S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH;
+ S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH;
+ S32 bottom = LLPANEL_BORDER_WIDTH;
+
+ LLUIImage* image = NULL;
+ LLColor4 color;
+ LLColor4 overlay_color;
+ if (isBackgroundOpaque())
+ {
+ // NOTE: image may not be set
+ image = getBackgroundImage();
+ color = getBackgroundColor();
+ overlay_color = getBackgroundImageOverlay();
+ }
+ else
+ {
+ image = getTransparentImage();
+ color = getTransparentColor();
+ overlay_color = getTransparentImageOverlay();
+ }
+
+ if (image)
+ {
+ // We're using images for this floater's backgrounds
+ image->draw(getLocalRect(), overlay_color % alpha);
+ }
+ else
+ {
+ // We're not using images, use old-school flat colors
+ gl_rect_2d( left, top, right, bottom, color % alpha );
+
+ // draw highlight on title bar to indicate focus. RDW
+ if(hasFocus()
+ && !getIsChrome()
+ && !getCurrentTitle().empty())
+ {
+ static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor");
+
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ LLRect r = getRect();
+ gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - font->getLineHeight() - 1,
+ titlebar_focus_color % alpha, 0, true);
+ }
+ }
+ }
+
+ LLPanel::updateDefaultBtn();
+
+ if( getDefaultButton() )
+ {
+ if (hasFocus() && getDefaultButton()->getEnabled())
+ {
+ LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
+ // is this button a direct descendent and not a nested widget (e.g. checkbox)?
+ bool focus_is_child_button = dynamic_cast<LLButton*>(focus_ctrl) != NULL && dynamic_cast<LLButton*>(focus_ctrl)->getParent() == this;
+ // only enable default button when current focus is not a button
+ getDefaultButton()->setBorderEnabled(!focus_is_child_button);
+ }
+ else
+ {
+ getDefaultButton()->setBorderEnabled(false);
+ }
+ }
+ if (isMinimized())
+ {
+ for (S32 i = 0; i < BUTTON_COUNT; i++)
+ {
+ drawChild(mButtons[i]);
+ }
+ drawChild(mDragHandle, 0, 0, true);
+ }
+ else
+ {
+ // don't call LLPanel::draw() since we've implemented custom background rendering
+ LLView::draw();
+ }
+
+ // update tearoff button for torn off floaters
+ // when last host goes away
+ if (mCanTearOff && !getHost())
+ {
+ LLFloater* old_host = mLastHostHandle.get();
+ if (!old_host)
+ {
+ setCanTearOff(false);
+ }
+ }
+}
+
+void LLFloater::drawShadow(LLPanel* panel)
+{
+ S32 left = LLPANEL_BORDER_WIDTH;
+ S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH;
+ S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
+ S32 bottom = LLPANEL_BORDER_WIDTH;
+
+ static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow");
+ LLColor4 shadow_color = shadow_color_cached;
+ F32 shadow_offset = (F32)DROP_SHADOW_FLOATER;
+
+ if (!panel->isBackgroundOpaque())
+ {
+ shadow_offset *= 0.2f;
+ shadow_color.mV[VALPHA] *= 0.5f;
+ }
+ gl_drop_shadow(left, top, right, bottom,
+ shadow_color % getCurrentTransparency(),
+ ll_round(shadow_offset));
+}
+
+void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type)
+{
+ if (!view) return;
+ child_list_t children = *view->getChildList();
+ child_list_t::iterator it = children.begin();
+
+ LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(view);
+ if (ctrl)
+ {
+ ctrl->setTransparencyType(transparency_type);
+ }
+
+ for(; it != children.end(); ++it)
+ {
+ updateTransparency(*it, transparency_type);
+ }
+}
+
+void LLFloater::updateTransparency(ETypeTransparency transparency_type)
+{
+ updateTransparency(this, transparency_type);
+}
+
+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);
+ }
+
+ mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized();
+ mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized();
+
+ updateTitleButtons();
+}
+
+void LLFloater::setCanClose(bool can_close)
+{
+ mCanClose = can_close;
+ mButtonsEnabled[BUTTON_CLOSE] = can_close;
+
+ updateTitleButtons();
+}
+
+void LLFloater::setCanTearOff(bool can_tear_off)
+{
+ mCanTearOff = can_tear_off;
+ mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead();
+
+ updateTitleButtons();
+}
+
+
+void LLFloater::setCanResize(bool can_resize)
+{
+ mResizable = can_resize;
+ enableResizeCtrls(can_resize);
+}
+
+void LLFloater::setCanDrag(bool can_drag)
+{
+ // if we delete drag handle, we no longer have access to the floater's title
+ // so just enable/disable it
+ if (!can_drag && mDragHandle->getEnabled())
+ {
+ mDragHandle->setEnabled(false);
+ }
+ else if (can_drag && !mDragHandle->getEnabled())
+ {
+ mDragHandle->setEnabled(true);
+ }
+}
+
+bool LLFloater::getCanDrag()
+{
+ return mDragHandle->getEnabled();
+}
+
+
+void LLFloater::updateTitleButtons()
+{
+ static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+ static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
+ LLRect buttons_rect;
+ S32 button_count = 0;
+ for (S32 i = 0; i < BUTTON_COUNT; i++)
+ {
+ if (!mButtons[i])
+ {
+ continue;
+ }
+
+ bool enabled = mButtonsEnabled[i];
+ if (i == BUTTON_HELP)
+ {
+ // don't show the help button if the floater is minimized
+ // or if it is a docked tear-off floater
+ if (isMinimized() || (mButtonsEnabled[BUTTON_TEAR_OFF] && ! mTornOff))
+ {
+ enabled = false;
+ }
+ }
+ if (i == BUTTON_CLOSE && mButtonScale != 1.f)
+ {
+ //*HACK: always render close button for hosted floaters so
+ //that users don't accidentally hit the button when
+ //closing multiple windows in the chatterbox
+ enabled = true;
+ }
+
+ mButtons[i]->setEnabled(enabled);
+
+ if (enabled)
+ {
+ button_count++;
+
+ LLRect btn_rect;
+ if (mDragOnLeft)
+ {
+ btn_rect.setLeftTopAndSize(
+ LLPANEL_BORDER_WIDTH,
+ getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count,
+ ll_round((F32)floater_close_box_size * mButtonScale),
+ ll_round((F32)floater_close_box_size * mButtonScale));
+ }
+ else
+ {
+ btn_rect.setLeftTopAndSize(
+ getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count,
+ getRect().getHeight() - close_box_from_top,
+ ll_round((F32)floater_close_box_size * mButtonScale),
+ ll_round((F32)floater_close_box_size * mButtonScale));
+ }
+
+ // first time here, init 'buttons_rect'
+ if(1 == button_count)
+ {
+ buttons_rect = btn_rect;
+ }
+ else
+ {
+ // if mDragOnLeft=true then buttons are on top-left side vertically aligned
+ // title is not displayed in this case, calculating 'buttons_rect' for future use
+ mDragOnLeft ? buttons_rect.mBottom -= btn_rect.mBottom :
+ buttons_rect.mLeft = btn_rect.mLeft;
+ }
+ mButtons[i]->setRect(btn_rect);
+ mButtons[i]->setVisible(true);
+ // the restore button should have a tab stop so that it takes action when you Ctrl-Tab to a minimized floater
+ mButtons[i]->setTabStop(i == BUTTON_RESTORE);
+ }
+ else
+ {
+ mButtons[i]->setVisible(false);
+ }
+ }
+ if (mDragHandle)
+ {
+ localRectToOtherView(buttons_rect, &buttons_rect, mDragHandle);
+ mDragHandle->setButtonsRect(buttons_rect);
+ }
+}
+
+void LLFloater::drawConeToOwner(F32 &context_cone_opacity,
+ F32 max_cone_opacity,
+ LLView *owner_view,
+ F32 fade_time,
+ F32 contex_cone_in_alpha,
+ F32 contex_cone_out_alpha)
+{
+ if (owner_view
+ && owner_view->isInVisibleChain()
+ && hasFocus()
+ && context_cone_opacity > 0.001f
+ && gFocusMgr.childHasKeyboardFocus(this))
+ {
+ // draw cone of context pointing back to owner (e.x. texture swatch)
+ LLRect owner_rect;
+ owner_view->localRectToOtherView(owner_view->getLocalRect(), &owner_rect, this);
+ LLRect local_rect = getLocalRect();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLEnable(GL_CULL_FACE);
+ gGL.begin(LLRender::QUADS);
+ {
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop);
+
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+ gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mTop);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+
+
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_out_alpha * context_cone_opacity);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+ gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+ gGL.color4f(0.f, 0.f, 0.f, contex_cone_in_alpha * context_cone_opacity);
+ gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom);
+ gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom);
+ }
+ gGL.end();
+ }
+
+ if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+ {
+ context_cone_opacity = lerp(context_cone_opacity, max_cone_opacity, LLSmoothInterpolation::getInterpolant(fade_time));
+ }
+ else
+ {
+ context_cone_opacity = lerp(context_cone_opacity, 0.f, LLSmoothInterpolation::getInterpolant(fade_time));
+ }
+}
+
+void LLFloater::buildButtons(const Params& floater_params)
+{
+ static LLUICachedControl<S32> floater_close_box_size ("UIFloaterCloseBoxSize", 0);
+ static LLUICachedControl<S32> close_box_from_top ("UICloseBoxFromTop", 0);
+ for (S32 i = 0; i < BUTTON_COUNT; i++)
+ {
+ if (mButtons[i])
+ {
+ removeChild(mButtons[i]);
+ delete mButtons[i];
+ mButtons[i] = NULL;
+ }
+
+ LLRect btn_rect;
+ if (mDragOnLeft)
+ {
+ btn_rect.setLeftTopAndSize(
+ LLPANEL_BORDER_WIDTH,
+ getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * (i + 1),
+ ll_round(floater_close_box_size * mButtonScale),
+ ll_round(floater_close_box_size * mButtonScale));
+ }
+ else
+ {
+ btn_rect.setLeftTopAndSize(
+ getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * (i + 1),
+ getRect().getHeight() - close_box_from_top,
+ ll_round(floater_close_box_size * mButtonScale),
+ ll_round(floater_close_box_size * mButtonScale));
+ }
+
+ LLButton::Params p;
+ p.name(sButtonNames[i]);
+ p.rect(btn_rect);
+ p.image_unselected = getButtonImage(floater_params, (EFloaterButton)i);
+ // Selected, no matter if hovered or not, is "pressed"
+ LLUIImage* pressed_image = getButtonPressedImage(floater_params, (EFloaterButton)i);
+ p.image_selected = pressed_image;
+ p.image_hover_selected = pressed_image;
+ // Use a glow effect when the user hovers over the button
+ // These icons are really small, need glow amount increased
+ p.hover_glow_amount( 0.33f );
+ p.click_callback.function(boost::bind(sButtonCallbacks[i], this));
+ p.tab_stop(false);
+ p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT);
+ p.tool_tip = getButtonTooltip(floater_params, (EFloaterButton)i, getIsChrome());
+ p.scale_image(true);
+ p.chrome(true);
+
+ LLButton* buttonp = LLUICtrlFactory::create<LLButton>(p);
+ addChild(buttonp);
+ mButtons[i] = buttonp;
+ }
+
+ updateTitleButtons();
+}
+
+// static
+LLUIImage* LLFloater::getButtonImage(const Params& p, EFloaterButton e)
+{
+ switch(e)
+ {
+ default:
+ case BUTTON_CLOSE:
+ return p.close_image;
+ case BUTTON_RESTORE:
+ return p.restore_image;
+ case BUTTON_MINIMIZE:
+ return p.minimize_image;
+ case BUTTON_TEAR_OFF:
+ return p.tear_off_image;
+ case BUTTON_DOCK:
+ return p.dock_image;
+ case BUTTON_HELP:
+ return p.help_image;
+ }
+}
+
+// static
+LLUIImage* LLFloater::getButtonPressedImage(const Params& p, EFloaterButton e)
+{
+ switch(e)
+ {
+ default:
+ case BUTTON_CLOSE:
+ return p.close_pressed_image;
+ case BUTTON_RESTORE:
+ return p.restore_pressed_image;
+ case BUTTON_MINIMIZE:
+ return p.minimize_pressed_image;
+ case BUTTON_TEAR_OFF:
+ return p.tear_off_pressed_image;
+ case BUTTON_DOCK:
+ return p.dock_pressed_image;
+ case BUTTON_HELP:
+ return p.help_pressed_image;
+ }
+}
+
+// static
+std::string LLFloater::getButtonTooltip(const Params& p, EFloaterButton e, bool is_chrome)
+{
+ // EXT-4081 (Lag Meter: Ctrl+W does not close floater)
+ // If floater is chrome set 'Close' text for close button's tooltip
+ if(is_chrome && BUTTON_CLOSE == e)
+ {
+ static std::string close_tooltip_chrome = LLTrans::getString("BUTTON_CLOSE_CHROME");
+ return close_tooltip_chrome;
+ }
+ // TODO: per-floater localizable tooltips set in XML
+ return sButtonToolTips[e];
+}
+
+/////////////////////////////////////////////////////
+// LLFloaterView
+
+static LLDefaultChildRegistry::Register<LLFloaterView> r("floater_view");
+
+LLFloaterView::LLFloaterView (const Params& p)
+: LLUICtrl (p),
+ mFocusCycleMode(false),
+ mMinimizePositionVOffset(0),
+ mSnapOffsetBottom(0),
+ mSnapOffsetRight(0)
+{
+ mSnapView = getHandle();
+}
+
+// By default, adjust vertical.
+void LLFloaterView::reshape(S32 width, S32 height, bool called_from_parent)
+{
+ LLView::reshape(width, height, called_from_parent);
+
+ mLastSnapRect = getSnapRect();
+
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLView* viewp = *child_it;
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
+ if (floaterp->isDependent())
+ {
+ // dependents are moved with their "dependee"
+ continue;
+ }
+
+ if (!floaterp->isMinimized() && floaterp->getCanDrag())
+ {
+ LLRect old_rect = floaterp->getRect();
+ floaterp->applyPositioning(NULL, false);
+ LLRect new_rect = floaterp->getRect();
+
+ //LLRect r = floaterp->getRect();
+
+ //// Compute absolute distance from each edge of screen
+ //S32 left_offset = llabs(r.mLeft - 0);
+ //S32 right_offset = llabs(old_right - r.mRight);
+
+ //S32 top_offset = llabs(old_top - r.mTop);
+ //S32 bottom_offset = llabs(r.mBottom - 0);
+
+ S32 translate_x = new_rect.mLeft - old_rect.mLeft;
+ S32 translate_y = new_rect.mBottom - old_rect.mBottom;
+
+ //if (left_offset > right_offset)
+ //{
+ // translate_x = new_right - old_right;
+ //}
+
+ //if (top_offset < bottom_offset)
+ //{
+ // translate_y = new_top - old_top;
+ //}
+
+ // don't reposition immovable floaters
+ //if (floaterp->getCanDrag())
+ //{
+ // floaterp->translate(translate_x, translate_y);
+ //}
+ for (LLHandle<LLFloater> dependent_floater : floaterp->mDependents)
+ {
+ if (dependent_floater.get())
+ {
+ dependent_floater.get()->translate(translate_x, translate_y);
+ }
+ }
+ }
+ }
+}
+
+
+void LLFloaterView::restoreAll()
+{
+ // make sure all subwindows aren't minimized
+ child_list_t child_list = *(getChildList());
+ for (LLView* child : child_list)
+ {
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(child);
+ if (floaterp)
+ {
+ floaterp->setMinimized(false);
+ }
+ }
+
+ // *FIX: make sure dependents are restored
+
+ // children then deleted by default view constructor
+}
+
+
+LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor )
+{
+ LLRect base_rect = reference_floater->getRect();
+ LLRect::tCoordType width = neighbor->getRect().getWidth();
+ LLRect::tCoordType height = neighbor->getRect().getHeight();
+ LLRect new_rect = neighbor->getRect();
+
+ LLRect expanded_base_rect = base_rect;
+ expanded_base_rect.stretch(10);
+ for(LLFloater::handle_set_iter_t dependent_it = reference_floater->mDependents.begin();
+ dependent_it != reference_floater->mDependents.end(); ++dependent_it)
+ {
+ LLFloater* sibling = dependent_it->get();
+ // check for dependents within 10 pixels of base floater
+ if (sibling &&
+ sibling != neighbor &&
+ sibling->getVisible() &&
+ expanded_base_rect.overlaps(sibling->getRect()))
+ {
+ base_rect.unionWith(sibling->getRect());
+ }
+ }
+
+ LLRect::tCoordType left_margin = llmax(0, base_rect.mLeft);
+ LLRect::tCoordType right_margin = llmax(0, getRect().getWidth() - base_rect.mRight);
+ LLRect::tCoordType top_margin = llmax(0, getRect().getHeight() - base_rect.mTop);
+ LLRect::tCoordType bottom_margin = llmax(0, base_rect.mBottom);
+
+ // find position for floater in following order
+ // right->left->bottom->top
+ for (S32 i = 0; i < 5; i++)
+ {
+ if (right_margin > width)
+ {
+ new_rect.translate(base_rect.mRight - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mTop);
+ return new_rect;
+ }
+ else if (left_margin > width)
+ {
+ new_rect.translate(base_rect.mLeft - neighbor->getRect().mRight, base_rect.mTop - neighbor->getRect().mTop);
+ return new_rect;
+ }
+ else if (bottom_margin > height)
+ {
+ new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mBottom - neighbor->getRect().mTop);
+ return new_rect;
+ }
+ else if (top_margin > height)
+ {
+ new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft, base_rect.mTop - neighbor->getRect().mBottom);
+ return new_rect;
+ }
+
+ // keep growing margins to find "best" fit
+ left_margin += 20;
+ right_margin += 20;
+ top_margin += 20;
+ bottom_margin += 20;
+ }
+
+ // didn't find anything, return initial rect
+ return new_rect;
+}
+
+
+void LLFloaterView::bringToFront(LLFloater* child, bool give_focus, bool restore)
+{
+ if (!child)
+ return;
+
+ LLFloater* front_child = mFrontChildHandle.get();
+ if (front_child == child)
+ {
+ if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))
+ {
+ child->setFocus(true);
+ }
+ return;
+ }
+
+ if (front_child && front_child->getVisible())
+ {
+ front_child->goneFromFront();
+ }
+
+ mFrontChildHandle = child->getHandle();
+
+ // *TODO: make this respect floater's mAutoFocus value, instead of
+ // using parameter
+ if (child->getHost())
+ {
+ // this floater is hosted elsewhere and hence not one of our children, abort
+ return;
+ }
+ std::vector<LLFloater*> floaters_to_move;
+ // Look at all floaters...tab
+ for (child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it)
+ {
+ LLFloater* floater = dynamic_cast<LLFloater*>(*child_it);
+
+ // ...but if I'm a dependent floater...
+ if (floater && child->isDependent())
+ {
+ // ...look for floaters that have me as a dependent...
+ LLFloater::handle_set_iter_t found_dependent = floater->mDependents.find(child->getHandle());
+
+ if (found_dependent != floater->mDependents.end())
+ {
+ // ...and make sure all children of that floater (including me) are brought to front...
+ for (LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
+ dependent_it != floater->mDependents.end(); ++dependent_it)
+ {
+ LLFloater* sibling = dependent_it->get();
+ if (sibling)
+ {
+ floaters_to_move.push_back(sibling);
+ }
+ }
+ //...before bringing my parent to the front...
+ floaters_to_move.push_back(floater);
+ }
+ }
+ }
+
+ std::vector<LLFloater*>::iterator floater_it;
+ for(floater_it = floaters_to_move.begin(); floater_it != floaters_to_move.end(); ++floater_it)
+ {
+ LLFloater* floaterp = *floater_it;
+ sendChildToFront(floaterp);
+
+ // always unminimize dependee, but allow dependents to stay minimized
+ if (!floaterp->isDependent())
+ {
+ floaterp->setMinimized(false);
+ }
+ }
+ floaters_to_move.clear();
+
+ // ...then bringing my own dependents to the front...
+ for (LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin();
+ dependent_it != child->mDependents.end(); ++dependent_it)
+ {
+ LLFloater* dependent = dependent_it->get();
+ if (dependent)
+ {
+ sendChildToFront(dependent);
+ }
+ }
+
+ // ...and finally bringing myself to front
+ // (do this last, so that I'm left in front at end of this call)
+ if (*beginChild() != child)
+ {
+ sendChildToFront(child);
+ }
+
+ if(restore)
+ {
+ child->setMinimized(false);
+ }
+
+ if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
+ {
+ child->setFocus(true);
+ // floater did not take focus, so relinquish focus to world
+ if (!child->hasFocus())
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+ }
+}
+
+void LLFloaterView::highlightFocusedFloater()
+{
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLFloater *floater = (LLFloater *)(*child_it);
+
+ // skip dependent floaters, as we'll handle them in a batch along with their dependee(?)
+ if (floater->isDependent())
+ {
+ continue;
+ }
+
+ bool floater_or_dependent_has_focus = gFocusMgr.childHasKeyboardFocus(floater);
+ for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
+ dependent_it != floater->mDependents.end();
+ ++dependent_it)
+ {
+ LLFloater* dependent_floaterp = dependent_it->get();
+ if (dependent_floaterp && gFocusMgr.childHasKeyboardFocus(dependent_floaterp))
+ {
+ floater_or_dependent_has_focus = true;
+ }
+ }
+
+ // now set this floater and all its dependents
+ floater->setForeground(floater_or_dependent_has_focus);
+
+ for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
+ dependent_it != floater->mDependents.end(); )
+ {
+ LLFloater* dependent_floaterp = dependent_it->get();
+ if (dependent_floaterp)
+ {
+ dependent_floaterp->setForeground(floater_or_dependent_has_focus);
+ }
+ ++dependent_it;
+ }
+
+ floater->cleanupHandles();
+ }
+}
+
+LLFloater* LLFloaterView::getFrontmostClosableFloater()
+{
+ child_list_const_iter_t child_it;
+ LLFloater* frontmost_floater = NULL;
+
+ for ( child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ frontmost_floater = (LLFloater *)(*child_it);
+
+ if (frontmost_floater->isInVisibleChain() && frontmost_floater->isCloseable())
+ {
+ return frontmost_floater;
+ }
+ }
+
+ return NULL;
+}
+
+void LLFloaterView::unhighlightFocusedFloater()
+{
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLFloater *floater = (LLFloater *)(*child_it);
+
+ floater->setForeground(false);
+ }
+}
+
+void LLFloaterView::focusFrontFloater()
+{
+ LLFloater* floaterp = getFrontmost();
+ if (floaterp)
+ {
+ floaterp->setFocus(true);
+ }
+}
+
+void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
+{
+ const LLFloater::Params& default_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = default_params.header_height;
+ static LLUICachedControl<S32> minimized_width ("UIMinimizedWidth", 0);
+ LLRect snap_rect_local = getLocalSnapRect();
+ snap_rect_local.mTop += mMinimizePositionVOffset;
+ for(S32 col = snap_rect_local.mLeft;
+ col < snap_rect_local.getWidth() - minimized_width;
+ col += minimized_width)
+ {
+ for(S32 row = snap_rect_local.mTop - floater_header_size;
+ row > floater_header_size;
+ row -= floater_header_size ) //loop rows
+ {
+
+ bool foundGap = true;
+ for(child_list_const_iter_t child_it = getChildList()->begin();
+ child_it != getChildList()->end();
+ ++child_it) //loop floaters
+ {
+ // Examine minimized children.
+ LLFloater* floater = dynamic_cast<LLFloater*>(*child_it);
+ if(floater->isMinimized())
+ {
+ LLRect r = floater->getRect();
+ 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
+ foundGap = false;
+ break;
+ }
+ }
+ } //done floaters
+ if(foundGap)
+ {
+ *left = col;
+ *bottom = row;
+ return; //done
+ }
+ } //done this col
+ }
+
+ // crude - stack'em all at 0,0 when screen is full of minimized
+ // floaters.
+ *left = snap_rect_local.mLeft;
+ *bottom = snap_rect_local.mBottom;
+}
+
+
+void LLFloaterView::destroyAllChildren()
+{
+ LLView::deleteAllChildren();
+}
+
+void LLFloaterView::closeAllChildren(bool app_quitting)
+{
+ // iterate over a copy of the list, because closing windows will destroy
+ // some windows on the list.
+ child_list_t child_list = *(getChildList());
+
+ for (child_list_const_iter_t it = child_list.begin(); it != child_list.end(); ++it)
+ {
+ LLView* viewp = *it;
+ child_list_const_iter_t exists = std::find(getChildList()->begin(), getChildList()->end(), viewp);
+ if (exists == getChildList()->end())
+ {
+ // this floater has already been removed
+ continue;
+ }
+
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
+
+ // Attempt to close floater. This will cause the "do you want to save"
+ // dialogs to appear.
+ // Skip invisible floaters if we're not quitting (STORM-192).
+ if (floaterp->canClose() && !floaterp->isDead() &&
+ (app_quitting || floaterp->getVisible()))
+ {
+ floaterp->closeFloater(app_quitting);
+ }
+ }
+}
+
+void LLFloaterView::hiddenFloaterClosed(LLFloater* floater)
+{
+ for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end();
+ it != end_it;
+ ++it)
+ {
+ if (it->first.get() == floater)
+ {
+ it->second.disconnect();
+ mHiddenFloaters.erase(it);
+ break;
+ }
+ }
+}
+
+void LLFloaterView::hideAllFloaters()
+{
+ child_list_t child_list = *(getChildList());
+
+ for (child_list_iter_t it = child_list.begin(); it != child_list.end(); ++it)
+ {
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
+ if (floaterp && floaterp->getVisible())
+ {
+ floaterp->setVisible(false);
+ boost::signals2::connection connection = floaterp->mCloseSignal.connect(boost::bind(&LLFloaterView::hiddenFloaterClosed, this, floaterp));
+ mHiddenFloaters.push_back(std::make_pair(floaterp->getHandle(), connection));
+ }
+ }
+}
+
+void LLFloaterView::showHiddenFloaters()
+{
+ for (hidden_floaters_t::iterator it = mHiddenFloaters.begin(), end_it = mHiddenFloaters.end();
+ it != end_it;
+ ++it)
+ {
+ LLFloater* floaterp = it->first.get();
+ if (floaterp)
+ {
+ floaterp->setVisible(true);
+ }
+ it->second.disconnect();
+ }
+ mHiddenFloaters.clear();
+}
+
+bool LLFloaterView::allChildrenClosed()
+{
+ // see if there are any visible floaters (some floaters "close"
+ // by setting themselves invisible)
+ for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
+ {
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
+
+ if (floaterp->getVisible() && !floaterp->isDead() && floaterp->isCloseable())
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void LLFloaterView::shiftFloaters(S32 x_offset, S32 y_offset)
+{
+ for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
+ {
+ LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
+
+ if (floaterp && floaterp->isMinimized())
+ {
+ floaterp->translate(x_offset, y_offset);
+ }
+ }
+}
+
+void LLFloaterView::refresh()
+{
+ LLRect snap_rect = getSnapRect();
+ if (snap_rect != mLastSnapRect)
+ {
+ reshape(getRect().getWidth(), getRect().getHeight(), true);
+ }
+
+ // 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 = dynamic_cast<LLFloater*>(*child_it);
+ if (floaterp && floaterp->getVisible() )
+ {
+ // minimized floaters are kept fully onscreen
+ adjustToFitScreen(floaterp, !floaterp->isMinimized());
+ }
+ }
+}
+
+void LLFloaterView::adjustToFitScreen(LLFloater* floater, bool allow_partial_outside, bool snap_in_toolbars/* = false*/)
+{
+ if (floater->getParent() != this)
+ {
+ // floater is hosted elsewhere, so ignore
+ return;
+ }
+
+ if (floater->getDependee() &&
+ floater->getDependee() == floater->getSnapTarget().get())
+ {
+ // floater depends on other and snaps to it, so ignore
+ return;
+ }
+
+ LLRect::tCoordType screen_width = getSnapRect().getWidth();
+ LLRect::tCoordType screen_height = getSnapRect().getHeight();
+
+ // only automatically resize non-minimized, resizable floaters
+ if( floater->isResizable() && !floater->isMinimized() )
+ {
+ LLRect view_rect = floater->getRect();
+ S32 old_width = view_rect.getWidth();
+ S32 old_height = view_rect.getHeight();
+ S32 min_width;
+ S32 min_height;
+ floater->getResizeLimits( &min_width, &min_height );
+
+ // Make sure floater isn't already smaller than its min height/width?
+ S32 new_width = llmax( min_width, old_width );
+ S32 new_height = llmax( min_height, old_height);
+
+ if((new_width > screen_width) || (new_height > screen_height))
+ {
+ // We have to make this window able to fit on screen
+ new_width = llmin(new_width, screen_width);
+ new_height = llmin(new_height, screen_height);
+
+ // ...while respecting minimum width/height
+ new_width = llmax(new_width, min_width);
+ new_height = llmax(new_height, min_height);
+
+ LLRect new_rect;
+ new_rect.setLeftTopAndSize(view_rect.mLeft,view_rect.mTop,new_width, new_height);
+
+ floater->setShape(new_rect);
+
+ if (floater->followsRight())
+ {
+ floater->translate(old_width - new_width, 0);
+ }
+
+ if (floater->followsTop())
+ {
+ floater->translate(0, old_height - new_height);
+ }
+ }
+ }
+
+ const LLRect& constraint = snap_in_toolbars ? getSnapRect() : gFloaterView->getRect();
+ S32 min_overlap_pixels = allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX;
+
+ floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels);
+}
+
+void LLFloaterView::draw()
+{
+ refresh();
+
+ // hide focused floater if in cycle mode, so that it can be drawn on top
+ LLFloater* focused_floater = getFocusedFloater();
+
+ if (mFocusCycleMode && focused_floater)
+ {
+ child_list_const_iter_t child_it = getChildList()->begin();
+ for (;child_it != getChildList()->end(); ++child_it)
+ {
+ if ((*child_it) != focused_floater)
+ {
+ drawChild(*child_it);
+ }
+ }
+
+ drawChild(focused_floater, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET);
+ }
+ else
+ {
+ LLView::draw();
+ }
+}
+
+LLRect LLFloaterView::getSnapRect() const
+{
+ LLRect snap_rect = getLocalRect();
+
+ LLView* snap_view = mSnapView.get();
+ if (snap_view)
+ {
+ snap_view->localRectToOtherView(snap_view->getLocalRect(), &snap_rect, this);
+ }
+
+ return snap_rect;
+}
+
+LLFloater *LLFloaterView::getFocusedFloater() const
+{
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ if ((*child_it)->isCtrl())
+ {
+ LLFloater* ctrlp = dynamic_cast<LLFloater*>(*child_it);
+ if ( ctrlp && ctrlp->hasFocus() )
+ {
+ return ctrlp;
+ }
+ }
+ }
+ return NULL;
+}
+
+LLFloater *LLFloaterView::getFrontmost() const
+{
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLView* viewp = *child_it;
+ if ( viewp->getVisible() && !viewp->isDead())
+ {
+ return (LLFloater *)viewp;
+ }
+ }
+ return NULL;
+}
+
+LLFloater *LLFloaterView::getBackmost() const
+{
+ LLFloater* back_most = NULL;
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLView* viewp = *child_it;
+ if ( viewp->getVisible() )
+ {
+ back_most = (LLFloater *)viewp;
+ }
+ }
+ return back_most;
+}
+
+void LLFloaterView::syncFloaterTabOrder()
+{
+ LLFloater* front_child = mFrontChildHandle.get();
+ if (front_child && front_child->getIsChrome())
+ return;
+
+ // look for a visible modal dialog, starting from first
+ LLModalDialog* modal_dialog = NULL;
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLModalDialog* dialog = dynamic_cast<LLModalDialog*>(*child_it);
+ if (dialog && dialog->isModal() && dialog->getVisible())
+ {
+ modal_dialog = dialog;
+ break;
+ }
+ }
+
+ if (modal_dialog)
+ {
+ // If we have a visible modal dialog, make sure that it has focus
+ LLUI::getInstance()->addPopup(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 = dynamic_cast<LLFloater*>(*child_it);
+ if (gFocusMgr.childHasKeyboardFocus(floaterp))
+ {
+ LLFloater* front_child = mFrontChildHandle.get();
+ if (front_child != floaterp)
+ {
+ // Grab a list of the top floaters that want to stay on top of the focused floater
+ std::list<LLFloater*> listTop;
+ if (front_child && !front_child->canFocusStealFrontmost())
+ {
+ for (LLView* childp : *getChildList())
+ {
+ LLFloater* child_floaterp = static_cast<LLFloater*>(childp);
+ if (child_floaterp->canFocusStealFrontmost())
+ break;
+ listTop.push_back(child_floaterp);
+ }
+ }
+
+ bringToFront(floaterp, false);
+
+ // Restore top floaters
+ if (!listTop.empty())
+ {
+ for (LLView* childp : listTop)
+ {
+ sendChildToFront(childp);
+ }
+ mFrontChildHandle = listTop.back()->getHandle();
+ }
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const
+{
+ LLView* parentp = viewp->getParent();
+
+ while(parentp && parentp != this)
+ {
+ viewp = parentp;
+ parentp = parentp->getParent();
+ }
+
+ if (parentp == this)
+ {
+ return dynamic_cast<LLFloater*>(viewp);
+ }
+
+ return NULL;
+}
+
+S32 LLFloaterView::getZOrder(LLFloater* child)
+{
+ S32 rv = 0;
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
+ {
+ LLView* viewp = *child_it;
+ if(viewp == child)
+ {
+ break;
+ }
+ ++rv;
+ }
+ return rv;
+}
+
+void LLFloaterView::pushVisibleAll(bool visible, const skip_list_t& skip_list)
+{
+ for (child_list_const_iter_t child_iter = getChildList()->begin();
+ child_iter != getChildList()->end(); ++child_iter)
+ {
+ LLView *view = *child_iter;
+ if (skip_list.find(view) == skip_list.end())
+ {
+ view->pushVisible(visible);
+ }
+ }
+
+ LLFloaterReg::blockShowFloaters(true);
+}
+
+void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
+{
+ // make a copy of the list since some floaters change their
+ // order in the childList when changing visibility.
+ child_list_t child_list_copy = *getChildList();
+
+ for (child_list_const_iter_t child_iter = child_list_copy.begin();
+ child_iter != child_list_copy.end(); ++child_iter)
+ {
+ LLView *view = *child_iter;
+ if (skip_list.find(view) == skip_list.end())
+ {
+ view->popVisible();
+ }
+ }
+
+ LLFloaterReg::blockShowFloaters(false);
+}
+
+void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect)
+{
+ switch (tb)
+ {
+ case LLToolBarEnums::TOOLBAR_LEFT:
+ mToolbarLeftRect = toolbar_rect;
+ break;
+ case LLToolBarEnums::TOOLBAR_BOTTOM:
+ mToolbarBottomRect = toolbar_rect;
+ break;
+ case LLToolBarEnums::TOOLBAR_RIGHT:
+ mToolbarRightRect = toolbar_rect;
+ break;
+ default:
+ LL_WARNS() << "setToolbarRect() passed odd toolbar number " << (S32) tb << LL_ENDL;
+ break;
+ }
+}
+
+void LLFloater::setInstanceName(const std::string& name)
+{
+ if (name != mInstanceName)
+ {
+ llassert_always(mInstanceName.empty());
+ mInstanceName = name;
+ if (!mInstanceName.empty())
+ {
+ std::string ctrl_name = getControlName(mInstanceName, mKey);
+ initRectControl();
+ if (!mVisibilityControl.empty())
+ {
+ mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name);
+ }
+ if(!mDocStateControl.empty())
+ {
+ mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name);
+ }
+ }
+}
+}
+
+void LLFloater::setKey(const LLSD& newkey)
+{
+ // Note: We don't have to do anything special with registration when we change keys
+ mKey = newkey;
+}
+
+//static
+void LLFloater::setupParamsForExport(Params& p, LLView* parent)
+{
+ // Do rectangle munging to topleft layout first
+ LLPanel::setupParamsForExport(p, parent);
+
+ // Copy the rectangle out to apply layout constraints
+ LLRect rect = p.rect;
+
+ // Null out other settings
+ p.rect.left.setProvided(false);
+ p.rect.top.setProvided(false);
+ p.rect.right.setProvided(false);
+ p.rect.bottom.setProvided(false);
+
+ // Explicitly set width/height
+ p.rect.width.set( rect.getWidth(), true );
+ p.rect.height.set( rect.getHeight(), true );
+
+ // If you can't resize this floater, don't export min_height
+ // and min_width
+ bool can_resize = p.can_resize;
+ if (!can_resize)
+ {
+ p.min_height.setProvided(false);
+ p.min_width.setProvided(false);
+ }
+}
+
+void LLFloater::initFromParams(const LLFloater::Params& p)
+{
+ // *NOTE: We have too many classes derived from LLFloater to retrofit them
+ // all to pass in params via constructors. So we use this method.
+
+ // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible
+ LLPanel::initFromParams(p);
+
+ // override any follows flags
+ if (mPositioning != LLFloaterEnums::POSITIONING_SPECIFIED)
+ {
+ setFollows(FOLLOWS_NONE);
+ }
+
+ mTitle = p.title;
+ mShortTitle = p.short_title;
+ applyTitle();
+
+ setCanTearOff(p.can_tear_off);
+ setCanMinimize(p.can_minimize);
+ setCanClose(p.can_close);
+ setCanDock(p.can_dock);
+ setCanResize(p.can_resize);
+ setResizeLimits(p.min_width, p.min_height);
+
+ mDragOnLeft = p.can_drag_on_left;
+ mHeaderHeight = p.header_height;
+ mLegacyHeaderHeight = p.legacy_header_height;
+ mSingleInstance = p.single_instance;
+ mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance;
+
+ mDefaultRelativeX = p.rel_x;
+ mDefaultRelativeY = p.rel_y;
+
+ mPositioning = p.positioning;
+ mAutoClose = p.auto_close;
+
+ mSaveRect = p.save_rect;
+ if (p.save_visibility)
+ {
+ mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set
+ }
+ if(p.save_dock_state)
+ {
+ mDocStateControl = "t"; // flag to build mDocStateControl name once mInstanceName is set
+ }
+
+ // open callback
+ if (p.open_callback.isProvided())
+ {
+ setOpenCallback(initCommitCallback(p.open_callback));
+ }
+ // close callback
+ if (p.close_callback.isProvided())
+ {
+ setCloseCallback(initCommitCallback(p.close_callback));
+ }
+
+ if (mDragHandle)
+ {
+ mDragHandle->setTitleVisible(p.show_title);
+ }
+}
+
+boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_t::slot_type& cb )
+{
+ if (!mMinimizeSignal) mMinimizeSignal = new commit_signal_t();
+ return mMinimizeSignal->connect(cb);
+}
+
+boost::signals2::connection LLFloater::setOpenCallback( const commit_signal_t::slot_type& cb )
+{
+ return mOpenSignal.connect(cb);
+}
+
+boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t::slot_type& cb )
+{
+ return mCloseSignal.connect(cb);
+}
+
+bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>());
+ Params params(default_params);
+
+ LLXUIParser parser;
+ parser.readXUI(node, params, filename); // *TODO: Error checking
+
+ std::string xml_filename = params.filename;
+
+ if (!xml_filename.empty())
+ {
+ LLXMLNodePtr referenced_xml;
+
+ if (output_node)
+ {
+ //if we are exporting, we want to export the current xml
+ //not the referenced xml
+ Params output_params;
+ parser.readXUI(node, output_params, LLUICtrlFactory::getInstance()->getCurFileName());
+ setupParamsForExport(output_params, parent);
+ output_node->setName(node->getName()->mString);
+ parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params);
+ return true;
+ }
+
+ LLUICtrlFactory::instance().pushFileName(xml_filename);
+
+ if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml))
+ {
+ LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL;
+
+ return false;
+ }
+
+ Params referenced_params;
+ parser.readXUI(referenced_xml, referenced_params, LLUICtrlFactory::getInstance()->getCurFileName());
+ params.fillFrom(referenced_params);
+
+ // add children using dimensions from referenced xml for consistent layout
+ setShape(params.rect);
+ LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance());
+
+ LLUICtrlFactory::instance().popFileName();
+ }
+
+
+ if (output_node)
+ {
+ Params output_params(params);
+ setupParamsForExport(output_params, parent);
+ output_node->setName(node->getName()->mString);
+ parser.writeXUI(output_node, output_params, LLInitParam::default_parse_rules(), &default_params);
+ }
+
+ // Default floater position to top-left corner of screen
+ // However, some legacy floaters have explicit top or bottom
+ // coordinates set, so respect their wishes.
+ if (!params.rect.top.isProvided() && !params.rect.bottom.isProvided())
+ {
+ params.rect.top.set(0);
+ }
+ if (!params.rect.left.isProvided() && !params.rect.right.isProvided())
+ {
+ params.rect.left.set(0);
+ }
+ params.from_xui = true;
+ applyXUILayout(params, parent, parent == gFloaterView ? gFloaterView->getSnapRect() : parent->getLocalRect());
+ initFromParams(params);
+
+ initFloater(params);
+
+ LLMultiFloater* last_host = LLFloater::getFloaterHost();
+ if (node->hasName("multi_floater"))
+ {
+ LLFloater::setFloaterHost((LLMultiFloater*) this);
+ }
+
+ LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node);
+
+ if (node->hasName("multi_floater"))
+ {
+ LLFloater::setFloaterHost(last_host);
+ }
+
+ // HACK: When we changed the header height to 25 pixels in Viewer 2, rather
+ // than re-layout all the floaters we use this value in pixels to make the
+ // whole floater bigger and change the top-left coordinate for widgets.
+ // The goal is to eventually set mLegacyHeaderHeight to zero, which would
+ // make the top-left corner for widget layout the same as the top-left
+ // corner of the window's content area. James
+ S32 header_stretch = (mHeaderHeight - mLegacyHeaderHeight);
+ if (header_stretch > 0)
+ {
+ // Stretch the floater vertically, don't move widgets
+ LLRect rect = getRect();
+ rect.mTop += header_stretch;
+
+ // This will also update drag handle, title bar, close box, etc.
+ setRect(rect);
+ }
+
+ bool result;
+ result = postBuild();
+
+ if (!result)
+ {
+ LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL;
+ }
+
+ applyRectControl(); // If we have a saved rect control, apply it
+ gFloaterView->adjustToFitScreen(this, false); // Floaters loaded from XML should all fit on screen
+
+ moveResizeHandlesToFront();
+
+ applyDockState();
+
+ return true; // *TODO: Error checking
+}
+
+bool LLFloater::isShown() const
+{
+ return ! isMinimized() && isInVisibleChain();
+}
+
+bool LLFloater::isDetachedAndNotMinimized()
+{
+ return !getHost() && !isMinimized();
+}
+
+/* static */
+bool LLFloater::isShown(const LLFloater* floater)
+{
+ return floater && floater->isShown();
+}
+
+/* static */
+bool LLFloater::isMinimized(const LLFloater* floater)
+{
+ return floater && floater->isMinimized();
+}
+
+/* static */
+bool LLFloater::isVisible(const LLFloater* floater)
+{
+ return floater && floater->getVisible();
+}
+
+bool LLFloater::buildFromFile(const std::string& filename)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ LLXMLNodePtr root;
+
+ if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
+ {
+ LL_WARNS() << "Couldn't find (or parse) floater from: " << filename << LL_ENDL;
+ return false;
+ }
+
+ // root must be called floater
+ if( !(root->hasName("floater") || root->hasName("multi_floater")) )
+ {
+ LL_WARNS() << "Root node should be named floater in: " << filename << LL_ENDL;
+ return false;
+ }
+
+ bool res = true;
+
+ LL_DEBUGS() << "Building floater " << filename << LL_ENDL;
+ LLUICtrlFactory::instance().pushFileName(filename);
+ {
+ if (!getFactoryMap().empty())
+ {
+ LLPanel::sFactoryStack.push_front(&getFactoryMap());
+ }
+
+ // for local registry callbacks; define in constructor, referenced in XUI or postBuild
+ getCommitCallbackRegistrar().pushScope();
+ getEnableCallbackRegistrar().pushScope();
+
+ res = initFloaterXML(root, getParent(), filename, NULL);
+
+ setXMLFilename(filename);
+
+ getCommitCallbackRegistrar().popScope();
+ getEnableCallbackRegistrar().popScope();
+
+ if (!getFactoryMap().empty())
+ {
+ LLPanel::sFactoryStack.pop_front();
+ }
+ }
+ LLUICtrlFactory::instance().popFileName();
+
+ return res;
+}
+
+void LLFloater::stackWith(LLFloater& other)
+{
+ static LLUICachedControl<S32> floater_offset ("UIFloaterOffset", 16);
+
+ LLRect next_rect;
+ if (other.getHost())
+ {
+ next_rect = other.getHost()->getRect();
+ }
+ else
+ {
+ next_rect = other.getRect();
+ }
+ next_rect.translate(floater_offset, -floater_offset);
+
+ const LLRect& rect = getControlGroup()->getRect(mRectControl);
+ if (rect.notEmpty() && !mDefaultRectForGroup && mResizable)
+ {
+ next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
+ }
+ else
+ {
+ next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight());
+ }
+ setShape(next_rect);
+
+ if (!other.getHost())
+ {
+ other.mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP;
+ other.setFollows(FOLLOWS_LEFT | FOLLOWS_TOP);
+ }
+}
+
+void LLFloater::applyRelativePosition()
+{
+ LLRect snap_rect = gFloaterView->getSnapRect();
+ LLRect floater_view_screen_rect = gFloaterView->calcScreenRect();
+ snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom);
+ LLRect floater_screen_rect = calcScreenRect();
+
+ LLCoordGL new_center = mPosition.convert();
+ LLCoordGL cur_center(floater_screen_rect.getCenterX(), floater_screen_rect.getCenterY());
+ translate(new_center.mX - cur_center.mX, new_center.mY - cur_center.mY);
+}
+
+
+LLCoordFloater::LLCoordFloater(F32 x, F32 y, LLFloater& floater)
+: coord_t((S32)x, (S32)y)
+{
+ mFloater = floater.getHandle();
+}
+
+
+LLCoordFloater::LLCoordFloater(const LLCoordCommon& other, LLFloater& floater)
+{
+ mFloater = floater.getHandle();
+ convertFromCommon(other);
+}
+
+LLCoordFloater& LLCoordFloater::operator=(const LLCoordFloater& other)
+{
+ mFloater = other.mFloater;
+ coord_t::operator =(other);
+ return *this;
+}
+
+void LLCoordFloater::setFloater(LLFloater& floater)
+{
+ mFloater = floater.getHandle();
+}
+
+bool LLCoordFloater::operator==(const LLCoordFloater& other) const
+{
+ return mX == other.mX && mY == other.mY && mFloater == other.mFloater;
+}
+
+LLCoordCommon LL_COORD_FLOATER::convertToCommon() const
+{
+ const LLCoordFloater& self = static_cast<const LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this));
+
+ LLRect snap_rect = gFloaterView->getSnapRect();
+ LLRect floater_view_screen_rect = gFloaterView->calcScreenRect();
+ snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom);
+
+ LLFloater* floaterp = mFloater.get();
+ S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0;
+ S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0;
+ LLCoordCommon out;
+ if (self.mX < -0.5f)
+ {
+ out.mX = ll_round(rescale(self.mX, -1.f, -0.5f, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft));
+ }
+ else if (self.mX > 0.5f)
+ {
+ out.mX = ll_round(rescale(self.mX, 0.5f, 1.f, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS));
+ }
+ else
+ {
+ out.mX = ll_round(rescale(self.mX, -0.5f, 0.5f, snap_rect.mLeft, snap_rect.mRight - floater_width));
+ }
+
+ if (self.mY < -0.5f)
+ {
+ out.mY = ll_round(rescale(self.mY, -1.f, -0.5f, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom));
+ }
+ else if (self.mY > 0.5f)
+ {
+ out.mY = ll_round(rescale(self.mY, 0.5f, 1.f, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS));
+ }
+ else
+ {
+ out.mY = ll_round(rescale(self.mY, -0.5f, 0.5f, snap_rect.mBottom, snap_rect.mTop - floater_height));
+ }
+
+ // return center point instead of lower left
+ out.mX += floater_width / 2;
+ out.mY += floater_height / 2;
+
+ return out;
+}
+
+void LL_COORD_FLOATER::convertFromCommon(const LLCoordCommon& from)
+{
+ LLCoordFloater& self = static_cast<LLCoordFloater&>(LLCoordFloater::getTypedCoords(*this));
+ LLRect snap_rect = gFloaterView->getSnapRect();
+ LLRect floater_view_screen_rect = gFloaterView->calcScreenRect();
+ snap_rect.translate(floater_view_screen_rect.mLeft, floater_view_screen_rect.mBottom);
+
+
+ LLFloater* floaterp = mFloater.get();
+ S32 floater_width = floaterp ? floaterp->getRect().getWidth() : 0;
+ S32 floater_height = floaterp ? floaterp->getRect().getHeight() : 0;
+
+ S32 from_x = from.mX - floater_width / 2;
+ S32 from_y = from.mY - floater_height / 2;
+
+ if (from_x < snap_rect.mLeft)
+ {
+ self.mX = rescale(from_x, snap_rect.mLeft - (floater_width - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mLeft, -1.f, -0.5f);
+ }
+ else if (from_x + floater_width > snap_rect.mRight)
+ {
+ self.mX = rescale(from_x, snap_rect.mRight - floater_width, snap_rect.mRight - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f);
+ }
+ else
+ {
+ self.mX = rescale(from_x, snap_rect.mLeft, snap_rect.mRight - floater_width, -0.5f, 0.5f);
+ }
+
+ if (from_y < snap_rect.mBottom)
+ {
+ self.mY = rescale(from_y, snap_rect.mBottom - (floater_height - FLOATER_MIN_VISIBLE_PIXELS), snap_rect.mBottom, -1.f, -0.5f);
+ }
+ else if (from_y + floater_height > snap_rect.mTop)
+ {
+ self.mY = rescale(from_y, snap_rect.mTop - floater_height, snap_rect.mTop - FLOATER_MIN_VISIBLE_PIXELS, 0.5f, 1.f);
+ }
+ else
+ {
+ self.mY = rescale(from_y, snap_rect.mBottom, snap_rect.mTop - floater_height, -0.5f, 0.5f);
+ }
+}