123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- /**
- * @file lldraghandle.cpp
- * @brief LLDragHandle base class
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- // A widget for dragging a view around the screen using the mouse.
- #include "linden_common.h"
- #include "lldraghandle.h"
- #include "llcontrol.h"
- #include "llmenugl.h"
- #include "lltextbox.h"
- #include "llwindow.h"
- constexpr S32 LEADING_PAD = 5;
- constexpr S32 TITLE_PAD = 8;
- constexpr S32 BORDER_PAD = 1;
- constexpr S32 LEFT_PAD = BORDER_PAD + TITLE_PAD + LEADING_PAD;
- constexpr S32 RIGHT_PAD = BORDER_PAD + 32; // 32=space for close & minimize btn
- LLDragHandle::LLDragHandle(const std::string& name, const LLRect& rect,
- const std::string& title)
- : LLView(name, rect, true),
- mTitleBox(NULL),
- mClickedCallback(NULL),
- mCallbackUserData(NULL),
- mDragLastScreenX(0),
- mDragLastScreenY(0),
- mLastMouseScreenX(0),
- mLastMouseScreenY(0),
- mMaxTitleWidth(0),
- mForeground(true)
- {
- setSaveToXML(false);
- }
- LLDragHandle::~LLDragHandle()
- {
- setTitleBox(NULL);
- }
- void LLDragHandle::setTitleVisible(bool visible)
- {
- if (mTitleBox)
- {
- mTitleBox->setVisible(visible);
- }
- }
- void LLDragHandle::setTitleBox(LLTextBox* titlebox)
- {
- if (mTitleBox)
- {
- removeChild(mTitleBox);
- delete mTitleBox;
- }
- mTitleBox = titlebox;
- if (mTitleBox)
- {
- addChild(mTitleBox);
- }
- }
- LLDragHandleTop::LLDragHandleTop(const std::string& name, const LLRect &rect,
- const std::string& title)
- : LLDragHandle(name, rect, title)
- {
- mFont = LLFontGL::getFontSansSerif();
- setFollowsAll();
- setTitle(title);
- }
- LLDragHandleLeft::LLDragHandleLeft(const std::string& name, const LLRect &rect,
- const std::string& title)
- : LLDragHandle(name, rect, title)
- {
- setFollowsAll();
- setTitle(title);
- }
- void LLDragHandleTop::setTitle(const std::string& title)
- {
- std::string trimmed_title = title;
- LLStringUtil::trim(trimmed_title);
- if (mTitleBox)
- {
- mTitleBox->setText(trimmed_title);
- }
- else
- {
- mTitleBox = new LLTextBox("Drag Handle Title", getRect(),
- trimmed_title, mFont);
- mTitleBox->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
- mTitleBox->setFontStyle(LLFontGL::DROP_SHADOW_SOFT);
- addChild(mTitleBox);
- }
- reshapeTitleBox();
- }
- const std::string& LLDragHandleTop::getTitle() const
- {
- return mTitleBox ? mTitleBox->getText() : LLStringUtil::null;
- }
- void LLDragHandleLeft::setTitle(const std::string&)
- {
- setTitleBox(NULL);
- /* no title on left edge */
- }
- const std::string& LLDragHandleLeft::getTitle() const
- {
- return LLStringUtil::null;
- }
- void LLDragHandleTop::draw()
- {
- // Colorize the text to match the frontmost state
- if (mTitleBox)
- {
- mTitleBox->setEnabled(getForeground());
- }
- LLView::draw();
- }
- // Assumes GL state is set for 2D
- void LLDragHandleLeft::draw()
- {
- // Colorize the text to match the frontmost state
- if (mTitleBox)
- {
- mTitleBox->setEnabled(getForeground());
- }
- LLView::draw();
- }
- void LLDragHandleTop::reshapeTitleBox()
- {
- if (!mTitleBox)
- {
- return;
- }
- S32 title_width = mFont->getWidth(mTitleBox->getText()) + TITLE_PAD;
- if (getMaxTitleWidth() > 0)
- {
- title_width = llmin(title_width, getMaxTitleWidth());
- }
- S32 title_height = ll_roundp(mFont->getLineHeight());
- LLRect title_rect;
- title_rect.setLeftTopAndSize(LEFT_PAD, getRect().getHeight() - BORDER_PAD,
- getRect().getWidth() - LEFT_PAD - RIGHT_PAD,
- title_height);
- mTitleBox->setRect(title_rect);
- }
- void LLDragHandleTop::reshape(S32 width, S32 height, bool called_from_parent)
- {
- LLView::reshape(width, height, called_from_parent);
- reshapeTitleBox();
- }
- void LLDragHandleLeft::reshape(S32 width, S32 height, bool called_from_parent)
- {
- LLView::reshape(width, height, called_from_parent);
- }
- //-------------------------------------------------------------
- // UI event handling
- //-------------------------------------------------------------
- bool LLDragHandle::handleMouseDown(S32 x, S32 y, MASK mask)
- {
- // Route future Mouse messages here preemptively (release on mouse up).
- // No handler needed for focus lost since this clas has no state that
- // depends on it.
- gFocusMgr.setMouseCapture(this);
- localPointToScreen(x, y, &mDragLastScreenX, &mDragLastScreenY);
- mLastMouseScreenX = mDragLastScreenX;
- mLastMouseScreenY = mDragLastScreenY;
- if (mClickedCallback && getSoundFlags() & MOUSE_DOWN)
- {
- make_ui_sound("UISndClick");
- }
- // Note: do not pass on to children
- return true;
- }
- bool LLDragHandle::handleMouseUp(S32 x, S32 y, MASK mask)
- {
- if (hasMouseCapture())
- {
- // Release the mouse
- gFocusMgr.setMouseCapture(NULL);
- }
- if (mClickedCallback)
- {
- if (getSoundFlags() & MOUSE_UP)
- {
- make_ui_sound("UISndClickRelease");
- }
- // DO THIS AT THE VERY END to allow the handle to be destroyed as a
- // result of being clicked. If mouseup in the widget, it has been
- // clicked.
- (*mClickedCallback)(x, y, mCallbackUserData);
- }
- // Note: do not pass on to children
- return true;
- }
- bool LLDragHandle::handleHover(S32 x, S32 y, MASK mask)
- {
- bool handled = false;
- // We only handle the click if the click both started and ended within us
- if (hasMouseCapture())
- {
- S32 screen_x;
- S32 screen_y;
- localPointToScreen(x, y, &screen_x, &screen_y);
- // Resize the parent
- S32 delta_x = screen_x - mDragLastScreenX;
- S32 delta_y = screen_y - mDragLastScreenY;
- LLRect original_rect = getParent()->getRect();
- LLRect translated_rect = getParent()->getRect();
- translated_rect.translate(delta_x, delta_y);
- // Temporarily slam dragged window to new position
- getParent()->setRect(translated_rect);
- S32 pre_snap_x = getParent()->getRect().mLeft;
- S32 pre_snap_y = getParent()->getRect().mBottom;
- mDragLastScreenX = screen_x;
- mDragLastScreenY = screen_y;
- LLRect new_rect;
- LLCoordGL mouse_dir;
- // Use hysteresis on mouse motion to preserve user intent when mouse
- // stops moving
- mouse_dir.mX = screen_x == mLastMouseScreenX ? mLastMouseDir.mX
- : screen_x -
- mLastMouseScreenX;
- mouse_dir.mY = screen_y == mLastMouseScreenY ? mLastMouseDir.mY
- : screen_y -
- mLastMouseScreenY;
- mLastMouseDir = mouse_dir;
- mLastMouseScreenX = screen_x;
- mLastMouseScreenY = screen_y;
- LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir,
- SNAP_PARENT_AND_SIBLINGS,
- LLUI::sSnapMargin);
- getParent()->snappedTo(snap_view);
- delta_x = new_rect.mLeft - pre_snap_x;
- delta_y = new_rect.mBottom - pre_snap_y;
- translated_rect.translate(delta_x, delta_y);
- // Restore original rect so delta are detected, then call user reshape
- // method to handle snapped floaters, etc
- getParent()->setRect(original_rect);
- getParent()->userSetShape(translated_rect);
- mDragLastScreenX += delta_x;
- mDragLastScreenY += delta_y;
- gWindowp->setCursor(UI_CURSOR_ARROW);
- LL_DEBUGS("UserInput") << "hover handled by " << getName()
- << " (active)" << LL_ENDL;
- handled = true;
- }
- else
- {
- gWindowp->setCursor(UI_CURSOR_ARROW);
- LL_DEBUGS("UserInput") << "hover handled by " << getName()
- << " (inactive)" << LL_ENDL;
- handled = true;
- }
- // Note: do not pass on to children
- return handled;
- }
- void LLDragHandle::setValue(const LLSD& value)
- {
- setTitle(value.asString());
- }
|