From 6a49f2947f05963c577a1644c16a8affc779da63 Mon Sep 17 00:00:00 2001
From: Richard Nelson <richard@lindenlab.com>
Date: Wed, 28 Sep 2011 16:25:32 -0700
Subject: EXP-1234 WIP experimental drag and drop

---
 indra/llui/lltoolbar.cpp     | 93 ++++++++++++++++++++++++++++++--------------
 indra/llui/lltoolbar.h       | 16 +++++++-
 indra/llui/lltoolbarview.cpp | 41 ++++++++++++++++++-
 indra/llui/lltoolbarview.h   |  9 ++++-
 indra/llui/llview.h          | 14 +++++++
 5 files changed, 140 insertions(+), 33 deletions(-)

diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index c5219b11e8..fe989cee22 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -33,6 +33,7 @@
 #include "llcommandmanager.h"
 #include "llmenugl.h"
 #include "lltrans.h"
+#include "lltoolbarview.h"
 
 // uncomment this and remove the one in llui.cpp when there is an external reference to this translation unit
 // thanks, MSVC!
@@ -201,35 +202,27 @@ void LLToolBar::initFromParams(const LLToolBar::Params& p)
 bool LLToolBar::addCommand(const LLCommandId& commandId)
 {
 	LLCommand * command = LLCommandManager::instance().getCommand(commandId);
+	if (!command) return false;
 
-	bool add_command = (command != NULL);
-
-	if (add_command)
-	{
-		mButtonCommands.push_back(commandId);
-		createButton(commandId);
-	}
+	mButtonCommands.push_back(commandId);
+	LLToolBarButton* button = createButton(commandId);
+	mButtons.push_back(button);
+	mButtonPanel->addChild(button);
+	mButtonMap.insert(std::make_pair(commandId, button));
+	mNeedsLayout = true;
 
-	return add_command;
+	return true;
 }
 
 bool LLToolBar::hasCommand(const LLCommandId& commandId) const
 {
-	bool has_command = false;
-
 	if (commandId != LLCommandId::null)
 	{
-		BOOST_FOREACH(LLCommandId cmd, mButtonCommands)
-		{
-			if (cmd == commandId)
-			{
-				has_command = true;
-				break;
-			}
-		}
+		command_id_map::const_iterator it = mButtonMap.find(commandId);
+		return (it != mButtonMap.end());
 	}
 
-	return has_command;
+	return false;
 }
 
 bool LLToolBar::enableCommand(const LLCommandId& commandId, bool enabled)
@@ -238,11 +231,10 @@ bool LLToolBar::enableCommand(const LLCommandId& commandId, bool enabled)
 	
 	if (commandId != LLCommandId::null)
 	{
-		command_button = mButtonPanel->findChild<LLButton>(commandId.name());
-
-		if (command_button)
+		command_id_map::iterator it = mButtonMap.find(commandId);
+		if (it != mButtonMap.end())
 		{
-			command_button->setEnabled(enabled);
+			it->second->setEnabled(enabled);
 		}
 	}
 
@@ -498,15 +490,19 @@ void LLToolBar::createButtons()
 	
 	BOOST_FOREACH(LLCommandId& command_id, mButtonCommands)
 	{
-		createButton(command_id);
+		LLToolBarButton* button = createButton(command_id);
+		mButtons.push_back(button);
+		mButtonPanel->addChild(button);
+		mButtonMap.insert(std::make_pair(command_id, button));
 	}
+	mNeedsLayout = true;
 
 }
 
-void LLToolBar::createButton(const LLCommandId& id)
+LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
 {
 	LLCommand* commandp = LLCommandManager::instance().getCommand(id);
-	if (!commandp) return;
+	if (!commandp) return NULL;
 
 	LLToolBarButton::Params button_p;
 	button_p.label = LLTrans::getString(commandp->labelRef());
@@ -515,8 +511,47 @@ void LLToolBar::createButton(const LLCommandId& id)
 	button_p.overwriteFrom(mButtonParams[mButtonType]);
 	LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p);
 
-	mButtons.push_back(button);
-	mButtonPanel->addChild(button);
+	button->setCommandId(id);
+	return button;
+}
 
-	mNeedsLayout = true;
+//
+// LLToolBarButton
+//
+
+LLToolBarButton::LLToolBarButton(const Params& p) 
+:	LLButton(p),
+	mMouseDownX(0),
+	mMouseDownY(0),
+	mId("")
+{}
+
+
+BOOL LLToolBarButton::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	mMouseDownX = x;
+	mMouseDownY = y;
+	return LLButton::handleMouseDown(x, y, mask);
+}
+
+BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
+{
+	if (hasMouseCapture())
+	{
+		S32 dist_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY);
+		S32 threshold = LLUI::sSettingGroups["config"]->getS32("DragAndDropDistanceThreshold");
+		S32 threshold_squared = threshold * threshold;
+		if (dist_squared > threshold_squared)
+		{
+			// start drag and drop
+			LLToolBarView* view = getParentByType<LLToolBarView>();
+			LLToolBar* bar = getParentByType<LLToolBar>();
+			if (view)
+			{
+				view->startDrag(bar->createButton(mId));
+				setVisible(FALSE);
+			}
+		}
+	}
+	return LLButton::handleHover(x, y, mask);
 }
diff --git a/indra/llui/lltoolbar.h b/indra/llui/lltoolbar.h
index 8e484c7e13..77bac87dbc 100644
--- a/indra/llui/lltoolbar.h
+++ b/indra/llui/lltoolbar.h
@@ -42,7 +42,15 @@ public:
 	{
 	};
 
-	LLToolBarButton(const Params& p) : LLButton(p) {}
+	LLToolBarButton(const Params& p);
+
+	BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	BOOL handleHover(S32 x, S32 y, MASK mask);
+	void setCommandId(const LLCommandId& id) { mId = id; }
+private:
+	LLCommandId		mId;
+	S32				mMouseDownX;
+	S32				mMouseDownY;
 };
 
 
@@ -125,6 +133,8 @@ public:
 	bool enableCommand(const LLCommandId& commandId, bool enabled);
 	command_id_list_t& getCommandsList() { return mButtonCommands; }
 
+	LLToolBarButton* createButton(const LLCommandId& id);
+
 protected:
 	friend class LLUICtrlFactory;
 	LLToolBar(const Params&);
@@ -136,7 +146,6 @@ private:
 	void createContextMenu();
 	void updateLayoutAsNeeded();
 	void createButtons();
-	void createButton(const LLCommandId& id);
 	void resizeButtonsInRow(std::vector<LLToolBarButton*>& buttons_in_row, S32 max_row_girth);
 	BOOL isSettingChecked(const LLSD& userdata);
 	void onSettingEnable(const LLSD& userdata);
@@ -145,6 +154,9 @@ private:
 
 	std::list<LLToolBarButton*>		mButtons;
 	command_id_list_t				mButtonCommands;
+	typedef std::map<LLCommandId, LLToolBarButton*> command_id_map;
+	command_id_map					mButtonMap;
+
 	LLToolBarEnums::ButtonType		mButtonType;
 	LLLayoutStack*					mCenteringStack;
 	LLLayoutStack*					mWrapStack;
diff --git a/indra/llui/lltoolbarview.cpp b/indra/llui/lltoolbarview.cpp
index b374a0bfc4..0c3a6bd0ac 100644
--- a/indra/llui/lltoolbarview.cpp
+++ b/indra/llui/lltoolbarview.cpp
@@ -55,7 +55,10 @@ LLToolBarView::LLToolBarView(const LLToolBarView::Params& p)
 :	LLUICtrl(p),
 	mToolbarLeft(NULL),
 	mToolbarRight(NULL),
-	mToolbarBottom(NULL)
+	mToolbarBottom(NULL),
+	mDragButton(NULL),
+	mMouseX(0),
+	mMouseY(0)
 {
 }
 
@@ -283,4 +286,40 @@ void LLToolBarView::draw()
 	//gl_rect_2d(right_rect, back_color_vert, TRUE);
 	
 	LLUICtrl::draw();
+
+	if (mDragButton)
+	{
+		S32 cursor_x, cursor_y;
+		mDragButton->setOrigin(mMouseX - mDragButton->getRect().getWidth(), mMouseY - mDragButton->getRect().getHeight());
+		drawChild(mDragButton);
+	}
+}
+
+void LLToolBarView::startDrag(LLToolBarButton* button)
+{
+	mDragButton = button;
+	addChild(mDragButton);
+	gFocusMgr.setMouseCapture(this);
+}
+
+BOOL LLToolBarView::handleHover(S32 x, S32 y, MASK mask)
+{
+	mMouseX = x;
+	mMouseY = y;
+	return LLUICtrl::handleHover(x, y, mask);
+}
+
+BOOL LLToolBarView::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	if (hasMouseCapture())
+	{
+		gFocusMgr.setMouseCapture(NULL);
+	}
+	return LLUICtrl::handleMouseUp(x, y, mask);
+}
+
+void LLToolBarView::onMouseCaptureLost()
+{
+	delete mDragButton;
+	mDragButton = NULL;
 }
diff --git a/indra/llui/lltoolbarview.h b/indra/llui/lltoolbarview.h
index 646a1fd636..cbe3d6c083 100644
--- a/indra/llui/lltoolbarview.h
+++ b/indra/llui/lltoolbarview.h
@@ -65,7 +65,10 @@ public:
 	virtual ~LLToolBarView();
 	virtual BOOL postBuild();
 	virtual void draw();
-
+	virtual BOOL handleHover(S32 x, S32 y, MASK mask);
+	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
+	virtual void onMouseCaptureLost();
+	void startDrag(LLToolBarButton*);
 	// Toolbar view interface with the rest of the world
 	bool hasCommand(const LLCommandId& commandId) const;
 	
@@ -85,6 +88,10 @@ private:
 	LLToolBar*	mToolbarLeft;
 	LLToolBar*	mToolbarRight;
 	LLToolBar*	mToolbarBottom;
+	bool		mDragging;
+	LLToolBarButton* mDragButton;
+	S32			mMouseX;
+	S32			mMouseY;
 };
 
 extern LLToolBarView* gToolBarView;
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 9039366e7e..f4e31b109a 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -465,6 +465,20 @@ public:
 		return dynamic_cast<T*>(widgetp);
 	}
 
+	template <class T> T* getParentByType() const
+	{
+		LLView* parent = getParent();
+		while(parent)
+		{
+			if (dynamic_cast<T*>(parent))
+			{
+				return static_cast<T*>(parent);
+			}
+			parent = parent->getParent();
+		}
+		return NULL;
+	}
+
 	//////////////////////////////////////////////
 	// statics
 	//////////////////////////////////////////////
-- 
cgit v1.2.3