diff options
Diffstat (limited to 'indra/llui/llfloater.cpp')
-rw-r--r-- | indra/llui/llfloater.cpp | 346 |
1 files changed, 280 insertions, 66 deletions
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index d19e33ea55..432397d3e9 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -62,6 +62,17 @@ // use this to control "jumping" behavior when Ctrl-Tabbing const S32 TABBED_FLOATER_OFFSET = 0; +namespace LLInitParam +{ + void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues() + { + declare("none", LLFloaterEnums::OPEN_POSITIONING_NONE); + declare("cascading", LLFloaterEnums::OPEN_POSITIONING_CASCADING); + declare("centered", LLFloaterEnums::OPEN_POSITIONING_CENTERED); + declare("specified", LLFloaterEnums::OPEN_POSITIONING_SPECIFIED); + } +} + std::string LLFloater::sButtonNames[BUTTON_COUNT] = { "llfloater_close_btn", //BUTTON_CLOSE @@ -154,7 +165,7 @@ LLFloater::Params::Params() : title("title"), short_title("short_title"), single_instance("single_instance", false), - auto_tile("auto_tile", false), + reuse_instance("reuse_instance", false), can_resize("can_resize", false), can_minimize("can_minimize", true), can_close("can_close", true), @@ -164,7 +175,10 @@ LLFloater::Params::Params() save_rect("save_rect", false), save_visibility("save_visibility", false), can_dock("can_dock", false), - open_centered("open_centered", false), + show_title("show_title", true), + open_positioning("open_positioning", LLFloaterEnums::OPEN_POSITIONING_NONE), + specified_left("specified_left"), + specified_bottom("specified_bottom"), header_height("header_height", 0), legacy_header_height("legacy_header_height", 0), close_image("close_image"), @@ -182,7 +196,7 @@ LLFloater::Params::Params() open_callback("open_callback"), close_callback("close_callback") { - visible = false; + changeDefault(visible, false); } @@ -226,13 +240,16 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) 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), - mAutoTile(p.auto_tile), mCanTearOff(p.can_tear_off), mCanMinimize(p.can_minimize), mCanClose(p.can_close), mDragOnLeft(p.can_drag_on_left), mResizable(p.can_resize), + mOpenPositioning(p.open_positioning), + mSpecifiedLeft(p.specified_left), + mSpecifiedBottom(p.specified_bottom), mMinWidth(p.min_width), mMinHeight(p.min_height), mHeaderHeight(p.header_height), @@ -459,15 +476,24 @@ void LLFloater::layoutResizeCtrls() mResizeHandle[3]->setRect(rect); } -void LLFloater::enableResizeCtrls(bool enable) +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) { - mResizeBar[i]->setVisible(enable); - mResizeBar[i]->setEnabled(enable); - - mResizeHandle[i]->setVisible(enable); - mResizeHandle[i]->setEnabled(enable); + mResizeHandle[i]->setVisible(enable && width && height); + mResizeHandle[i]->setEnabled(enable && width && height); } } @@ -515,7 +541,6 @@ LLFloater::~LLFloater() delete mResizeHandle[i]; } - storeRectControl(); setVisible(false); // We're not visible if we're destroyed storeVisibilityControl(); storeDockStateControl(); @@ -660,6 +685,12 @@ void LLFloater::openFloater(const LLSD& key) } 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); } @@ -752,12 +783,19 @@ void LLFloater::closeFloater(bool app_quitting) else { setVisible(FALSE); + if (!mReuseInstance) + { + destroy(); + } } } else { setVisible(FALSE); // hide before destroying (so handleVisibilityChange() gets called) - destroy(); + if (!mReuseInstance) + { + destroy(); + } } } } @@ -766,7 +804,6 @@ void LLFloater::closeFloater(bool app_quitting) void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent) { LLPanel::reshape(width, height, called_from_parent); - storeRectControl(); } void LLFloater::releaseFocus() @@ -823,43 +860,108 @@ LLMultiFloater* LLFloater::getHost() return (LLMultiFloater*)mHostHandle.get(); } -void LLFloater::applySavedVariables() +void LLFloater::applyControlsAndPosition(LLFloater* other) { - applyRectControl(); - applyDockState(); + if (!applyDockState()) + { + if (!applyRectControl()) + { + applyPositioning(other); + } + } } -void LLFloater::applyRectControl() +bool LLFloater::applyRectControl() { - // first, center on screen if requested - if (mOpenCentered) + bool saved_rect = false; + + LLFloater* last_in_group = LLFloaterReg::getLastFloaterInGroup(mInstanceName); + if (last_in_group && last_in_group != this) { - center(); + // other floaters in our group, position ourselves relative to them and don't save the rect + mRectControl.clear(); + mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP; } - - // override center if we have saved rect control - if (mRectControl.size() > 1) + else if (mRectControl.size() > 1) { + // If we have a saved rect, use it const LLRect& rect = getControlGroup()->getRect(mRectControl); - if (rect.getWidth() > 0 && rect.getHeight() > 0) + saved_rect = rect.notEmpty(); + if (saved_rect) { - translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); + setOrigin(rect.mLeft, rect.mBottom); + if (mResizable) { reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); } } } + + return saved_rect; } -void LLFloater::applyDockState() +bool LLFloater::applyDockState() { + bool docked = false; + if (mDocStateControl.size() > 1) { - bool dockState = getControlGroup()->getBOOL(mDocStateControl); - setDocked(dockState); + docked = getControlGroup()->getBOOL(mDocStateControl); + setDocked(docked); } + return docked; +} + +void LLFloater::applyPositioning(LLFloater* other) +{ + // Otherwise position according to the positioning code + switch (mOpenPositioning) + { + case LLFloaterEnums::OPEN_POSITIONING_CENTERED: + center(); + break; + + case LLFloaterEnums::OPEN_POSITIONING_SPECIFIED: + { + // Translate relative to snap rect + setOrigin(mSpecifiedLeft, mSpecifiedBottom); + const LLRect& snap_rect = gFloaterView->getSnapRect(); + translate(snap_rect.mLeft, snap_rect.mBottom); + translateIntoRect(snap_rect, FALSE); + } + break; + + case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP: + case LLFloaterEnums::OPEN_POSITIONING_CASCADING: + 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); + translateIntoRect(snap_rect, FALSE); + } + break; + + case LLFloaterEnums::OPEN_POSITIONING_NONE: + default: + // Do nothing + break; + } } void LLFloater::applyTitle() @@ -968,6 +1070,12 @@ void LLFloater::handleReshape(const LLRect& new_rect, bool by_user) const LLRect old_rect = getRect(); LLView::handleReshape(new_rect, by_user); + if (by_user && !isMinimized()) + { + storeRectControl(); + mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; + } + // if not minimized, adjust all snapped dependents to new shape if (!isMinimized()) { @@ -1025,7 +1133,7 @@ void LLFloater::setMinimized(BOOL minimize) if (minimize == mMinimized) return; - if(mMinimizeSignal) + if (mMinimizeSignal) { (*mMinimizeSignal)(this, LLSD(minimize)); } @@ -1057,10 +1165,6 @@ void LLFloater::setMinimized(BOOL minimize) mButtonsEnabled[BUTTON_RESTORE] = TRUE; } - if (mDragHandle) - { - mDragHandle->setVisible(TRUE); - } setBorderVisible(TRUE); for(handle_set_iter_t dependent_it = mDependents.begin(); @@ -1211,19 +1315,9 @@ void LLFloater::setIsChrome(BOOL is_chrome) mButtons[BUTTON_CLOSE]->setToolTip(LLStringExplicit(getButtonTooltip(Params(), BUTTON_CLOSE, is_chrome))); } - // no titles displayed on "chrome" floaters - if (mDragHandle) - mDragHandle->setTitleVisible(!is_chrome); - LLPanel::setIsChrome(is_chrome); } -void LLFloater::setTitleVisible(bool visible) -{ - if (mDragHandle) - mDragHandle->setTitleVisible(visible); -} - // Change the draw style to account for the foreground state. void LLFloater::setForeground(BOOL front) { @@ -1311,7 +1405,10 @@ void LLFloater::moveResizeHandlesToFront() BOOL LLFloater::isFrontmost() { - return gFloaterView && gFloaterView->getFrontmost() == this && getVisible(); + LLFloaterView* floater_view = getParentByType<LLFloaterView>(); + return getVisible() + && (floater_view + && floater_view->getFrontmost() == this); } void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition) @@ -1384,6 +1481,7 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask) 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; // Otherwise pass to drag handle for movement return mDragHandle->handleMouseDown(x, y, mask); @@ -1489,6 +1587,13 @@ void LLFloater::setDocked(bool docked, bool pop_on_undock) { mDocked = docked; mButtonsEnabled[BUTTON_DOCK] = !mDocked; + + if (mDocked) + { + setMinimized(FALSE); + mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE; + } + updateTitleButtons(); storeDockStateControl(); @@ -1727,7 +1832,7 @@ void LLFloater::draw() { drawChild(mButtons[i]); } - drawChild(mDragHandle); + drawChild(mDragHandle, 0, 0, TRUE); } else { @@ -2048,7 +2153,6 @@ static LLDefaultChildRegistry::Register<LLFloaterView> r("floater_view"); LLFloaterView::LLFloaterView (const Params& p) : LLUICtrl (p), - mFocusCycleMode(FALSE), mMinimizePositionVOffset(0), mSnapOffsetBottom(0), @@ -2059,12 +2163,6 @@ LLFloaterView::LLFloaterView (const Params& p) // By default, adjust vertical. void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) { - reshapeFloater(width, height, called_from_parent, ADJUST_VERTICAL_YES); -} - -// When reshaping this view, make the floaters follow their closest edge. -void LLFloaterView::reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical) -{ S32 old_width = getRect().getWidth(); S32 old_height = getRect().getHeight(); @@ -2109,11 +2207,7 @@ void LLFloaterView::reshapeFloater(S32 width, S32 height, BOOL called_from_paren // "No vertical adjustment" usually means that the bottom of the view // has been pushed up or down. Hence we want the floaters to follow // the top. - if (!adjust_vertical) - { - follow_flags |= FOLLOWS_TOP; - } - else if (top_offset < bottom_offset) + if (top_offset < bottom_offset) { follow_flags |= FOLLOWS_TOP; } @@ -2458,6 +2552,52 @@ void LLFloaterView::closeAllChildren(bool 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() { @@ -2556,7 +2696,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out } // move window fully onscreen - if (floater->translateIntoRect( getLocalRect(), allow_partial_outside )) + if (floater->translateIntoRect( getSnapRect(), allow_partial_outside )) { floater->clearSnapTarget(); } @@ -2782,7 +2922,6 @@ void LLFloater::setInstanceName(const std::string& name) { mDocStateControl = LLFloaterReg::declareDockStateControl(ctrl_name); } - } } @@ -2844,10 +2983,13 @@ void LLFloater::initFromParams(const LLFloater::Params& p) mHeaderHeight = p.header_height; mLegacyHeaderHeight = p.legacy_header_height; mSingleInstance = p.single_instance; - mAutoTile = p.auto_tile; - mOpenCentered = p.open_centered; + mReuseInstance = p.reuse_instance.isProvided() ? p.reuse_instance : p.single_instance; + + mOpenPositioning = p.open_positioning; + mSpecifiedLeft = p.specified_left; + mSpecifiedBottom = p.specified_bottom; - if (p.save_rect) + if (p.save_rect && mRectControl.empty()) { mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set } @@ -2855,7 +2997,6 @@ void LLFloater::initFromParams(const LLFloater::Params& p) { 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 @@ -2864,13 +3005,18 @@ void LLFloater::initFromParams(const LLFloater::Params& p) // open callback if (p.open_callback.isProvided()) { - mOpenSignal.connect(initCommitCallback(p.open_callback)); + 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 ) @@ -2879,19 +3025,67 @@ boost::signals2::connection LLFloater::setMinimizeCallback( const commit_signal_ 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); } LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build"); +static LLFastTimer::DeclareTimer FTM_EXTERNAL_FLOATER_LOAD("Load Extern Floater Reference"); bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node) { - Params params(LLUICtrlFactory::getDefaultParams<LLFloater>()); + 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, &default_params); + return TRUE; + } + + LLUICtrlFactory::instance().pushFileName(xml_filename); + + LLFastTimer _(FTM_EXTERNAL_FLOATER_LOAD); + if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) + { + llwarns << "Couldn't parse panel from: " << xml_filename << llendl; + + 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); @@ -2912,7 +3106,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str { params.rect.left.set(0); } - params.from_xui = true; applyXUILayout(params, parent); initFromParams(params); @@ -3054,3 +3247,24 @@ bool LLFloater::buildFromFile(const std::string& filename, LLXMLNodePtr output_n 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); + + next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); + + setShape(next_rect); +} + |