diff options
author | Richard Nelson <richard@lindenlab.com> | 2009-09-09 01:26:44 +0000 |
---|---|---|
committer | Richard Nelson <richard@lindenlab.com> | 2009-09-09 01:26:44 +0000 |
commit | 58bce2d205bee3f5adb33b15efe73098e77429eb (patch) | |
tree | d591209e661af81fce315ceadc1179d277c579d8 /indra/llui/lltooltip.cpp | |
parent | a67d2dd1a4c490eae337ae930eac98c714033711 (diff) |
merge -r132032-132812 svn+ssh://svn.lindenlab.com/svn/linden/branches/gooey/gooey-1
Diffstat (limited to 'indra/llui/lltooltip.cpp')
-rw-r--r-- | indra/llui/lltooltip.cpp | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp new file mode 100644 index 0000000000..5c017dabd7 --- /dev/null +++ b/indra/llui/lltooltip.cpp @@ -0,0 +1,445 @@ +/** + * @file lltooltip.cpp + * @brief LLToolTipMgr class implementation and related classes + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// self include +#include "lltooltip.h" + +// Library includes +#include "llpanel.h" +#include "lltextbox.h" +#include "lliconctrl.h" +#include "llui.h" // positionViewNearMouse() +#include "llwindow.h" + +// +// Constants +// +const F32 DELAY_BEFORE_SHOW_TIP = 0.35f; + +// +// Local globals +// + +LLToolTipView *gToolTipView = NULL; + +// +// Member functions +// + +LLToolTipView::LLToolTipView(const LLToolTipView::Params& p) +: LLView(p) +{ +} + +void LLToolTipView::draw() +{ + if (LLUI::getWindow()->isCursorHidden() ) + { + LLToolTipMgr::instance().hideToolTips(); + } + + // do the usual thing + LLView::draw(); +} + +BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask) +{ + static S32 last_x = x; + static S32 last_y = y; + + LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance(); + + // hide existing tooltips when mouse moves out of sticky rect + if (tooltip_mgr.toolTipVisible() + && !tooltip_mgr.getStickyRect().pointInRect(x, y)) + { + tooltip_mgr.hideToolTips(); + } + + // allow new tooltips whenever mouse moves + if (x != last_x && y != last_y) + { + tooltip_mgr.enableToolTips(); + } + + last_x = x; + last_y = y; + return LLView::handleHover(x, y, mask); +} + +BOOL LLToolTipView::handleMouseDown(S32 x, S32 y, MASK mask) +{ + LLToolTipMgr::instance().hideToolTips(); + return LLView::handleMouseDown(x, y, mask); +} + +BOOL LLToolTipView::handleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + LLToolTipMgr::instance().hideToolTips(); + return LLView::handleMiddleMouseDown(x, y, mask); +} + +BOOL LLToolTipView::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLToolTipMgr::instance().hideToolTips(); + return LLView::handleRightMouseDown(x, y, mask); +} + + +BOOL LLToolTipView::handleScrollWheel( S32 x, S32 y, S32 clicks ) +{ + LLToolTipMgr::instance().hideToolTips(); + return FALSE; +} + +void LLToolTipView::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLToolTipMgr::instance().hideToolTips(); +} + + +void LLToolTipView::drawStickyRect() +{ + gl_rect_2d(LLToolTipMgr::instance().getStickyRect(), LLColor4::white, false); +} +// +// LLToolTip +// +class LLToolTip : public LLPanel +{ +public: + struct Params : public LLInitParam::Block<Params, LLPanel::Params> + { + Mandatory<F32> visible_time; + + Optional<LLToolTipParams::click_callback_t> click_callback; + Optional<LLUIImage*> image; + + Params() + { + //use_bounding_rect = true; + } + }; + /*virtual*/ void draw(); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + + /*virtual*/ void setValue(const LLSD& value); + /*virtual*/ void setVisible(BOOL visible); + + bool isFading() { return mFadeTimer.getStarted(); } + + LLToolTip(const Params& p); + +private: + LLTextBox* mTextBox; + LLFrameTimer mFadeTimer; + F32 mVisibleTime; + bool mHasClickCallback; +}; + +static LLDefaultChildRegistry::Register<LLToolTip> r("tool_tip"); + +const S32 TOOLTIP_PADDING = 4; + +LLToolTip::LLToolTip(const LLToolTip::Params& p) +: LLPanel(p), + mVisibleTime(p.visible_time), + mHasClickCallback(p.click_callback.isProvided()) +{ + LLTextBox::Params params; + params.text = "tip_text"; + params.name = params.text; + // bake textbox padding into initial rect + params.rect = LLRect (TOOLTIP_PADDING, TOOLTIP_PADDING + 1, TOOLTIP_PADDING + 1, TOOLTIP_PADDING); + params.follows.flags = FOLLOWS_ALL; + params.h_pad = 4; + params.v_pad = 2; + params.mouse_opaque = false; + params.text_color = LLUIColorTable::instance().getColor( "ToolTipTextColor" ); + params.bg_visible = false; + params.font.style = "NORMAL"; + //params.border_drop_shadow_visible = true; + mTextBox = LLUICtrlFactory::create<LLTextBox> (params); + addChild(mTextBox); + + if (p.image.isProvided()) + { + LLIconCtrl::Params icon_params; + icon_params.name = "tooltip_icon"; + LLRect icon_rect; + const S32 TOOLTIP_ICON_SIZE = 18; + icon_rect.setOriginAndSize(TOOLTIP_PADDING, TOOLTIP_PADDING, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE); + icon_params.rect = icon_rect; + icon_params.follows.flags = FOLLOWS_LEFT | FOLLOWS_BOTTOM; + icon_params.image = p.image; + icon_params.mouse_opaque = false; + addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_params)); + + // move text over to fit image in + mTextBox->translate(TOOLTIP_ICON_SIZE,0); + } + + if (p.click_callback.isProvided()) + { + setMouseUpCallback(boost::bind(p.click_callback())); + } +} + +void LLToolTip::setValue(const LLSD& value) +{ + mTextBox->setWrappedText(value.asString()); + mTextBox->reshapeToFitText(); + + // reshape tooltip panel to fit text box + LLRect tooltip_rect = calcBoundingRect(); + tooltip_rect.mTop += TOOLTIP_PADDING; + tooltip_rect.mRight += TOOLTIP_PADDING; + tooltip_rect.mBottom = 0; + tooltip_rect.mLeft = 0; + + setRect(tooltip_rect); +} + +void LLToolTip::setVisible(BOOL visible) +{ + // fade out tooltip over time + if (!visible) + { + // don't actually change mVisible state, start fade out transition instead + if (!mFadeTimer.getStarted()) + { + mFadeTimer.start(); + } + } + else + { + mFadeTimer.stop(); + LLPanel::setVisible(TRUE); + } +} + +BOOL LLToolTip::handleHover(S32 x, S32 y, MASK mask) +{ + LLPanel::handleHover(x, y, mask); + if (mHasClickCallback) + { + getWindow()->setCursor(UI_CURSOR_HAND); + } + return TRUE; +} + +void LLToolTip::draw() +{ + F32 alpha = 1.f; + + if (LLUI::getMouseIdleTime() > mVisibleTime) + { + LLToolTipMgr::instance().hideToolTips(); + } + + if (mFadeTimer.getStarted()) + { + F32 tool_tip_fade_time = LLUI::sSettingGroups["config"]->getF32("ToolTipFadeTime"); + alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, 1.f, 0.f); + if (alpha == 0.f) + { + // finished fading out, so hide ourselves + mFadeTimer.stop(); + LLPanel::setVisible(false); + } + } + + // draw tooltip contents with appropriate alpha + { + LLViewDrawContext context(alpha); + LLPanel::draw(); + } +} + + + +// +// LLToolTipMgr +// +LLToolTipParams::LLToolTipParams() +: pos("pos"), + message("message"), + delay_time("delay_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" )), + visible_time("visible_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTime" )), + sticky_rect("sticky_rect"), + width("width", 200), + image("image") +{} + +LLToolTipMgr::LLToolTipMgr() +: mToolTip(NULL) +{ +} + +LLToolTip* LLToolTipMgr::createToolTip(const LLToolTipParams& params) +{ + S32 mouse_x; + S32 mouse_y; + LLUI::getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y); + + + LLToolTip::Params tooltip_params; + tooltip_params.name = "tooltip"; + tooltip_params.mouse_opaque = true; + tooltip_params.rect = LLRect (0, 1, 1, 0); + tooltip_params.bg_opaque_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" ); + tooltip_params.background_visible = true; + tooltip_params.visible_time = params.visible_time; + if (params.image.isProvided()) + { + tooltip_params.image = params.image; + } + if (params.click_callback.isProvided()) + { + tooltip_params.click_callback = params.click_callback; + } + + LLToolTip* tooltip = LLUICtrlFactory::create<LLToolTip> (tooltip_params); + + // make tooltip fixed width and tall enough to fit text + tooltip->reshape(params.width, 2000); + tooltip->setValue(params.message()); + gToolTipView->addChild(tooltip); + + if (params.pos.isProvided()) + { + // try to spawn at requested position + LLUI::positionViewNearMouse(tooltip, params.pos.x, params.pos.y); + } + else + { + // just spawn at mouse location + LLUI::positionViewNearMouse(tooltip); + } + + //...update "sticky" rect and tooltip position + if (params.sticky_rect.isProvided()) + { + mToolTipStickyRect = params.sticky_rect; + } + else + { + // otherwise just use one pixel rect around mouse cursor + mToolTipStickyRect.setOriginAndSize(mouse_x, mouse_y, 1, 1); + } + + if (params.click_callback.isProvided()) + { + // keep tooltip up when we mouse over it + mToolTipStickyRect.unionWith(tooltip->getRect()); + } + + return tooltip; +} + + +void LLToolTipMgr::show(const std::string& msg) +{ + show(LLToolTipParams().message(msg)); +} + +void LLToolTipMgr::show(const LLToolTipParams& params) +{ + if (!params.validateBlock()) + { + llwarns << "Could not display tooltip!" << llendl; + return; + } + + bool tooltip_shown = mToolTip + && mToolTip->getVisible() + && !mToolTip->isFading(); + + // if tooltip contents change, hide existing tooltip + if (tooltip_shown && mLastToolTipMessage != params.message()) + { + hideToolTips(); + } + + if (!mToolTipsBlocked // we haven't hit a key, moved the mouse, etc. + && LLUI::getMouseIdleTime() > params.delay_time // the mouse has been still long enough + && !tooltip_shown) // tooltip not visible + { + // create new tooltip at mouse cursor position + delete mToolTip; + mToolTip = createToolTip(params); + + // remember this tooltip so we know when it changes + mLastToolTipMessage = params.message(); + } +} + +// allow new tooltips to be created, e.g. after mouse has moved +void LLToolTipMgr::enableToolTips() +{ + mToolTipsBlocked = false; +} + +void LLToolTipMgr::hideToolTips() +{ + mToolTipsBlocked = true; + if (mToolTip) + { + mToolTip->setVisible(FALSE); + } +} + +bool LLToolTipMgr::toolTipVisible() +{ + return mToolTip ? mToolTip->getVisible() : false; +} + +LLRect LLToolTipMgr::getToolTipRect() +{ + if (mToolTip && mToolTip->getVisible()) + { + return mToolTip->getRect(); + } + return LLRect(); +} + + +LLRect LLToolTipMgr::getStickyRect() +{ + if (!mToolTip) return LLRect(); + + return mToolTip->isInVisibleChain() ? mToolTipStickyRect : LLRect(); +} + +// EOF |