From 69f9c0bcf9764a1b682bfdd5baa3f340922dcbaa Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 3 Mar 2010 19:37:41 -0800
Subject: WIP - replace top ctrl with LLPopupView

---
 indra/llui/llcombobox.cpp               | 14 ++++++++------
 indra/llui/llcombobox.h                 |  1 +
 indra/llui/llfloater.cpp                |  2 +-
 indra/llui/llfocusmgr.cpp               |  4 ++--
 indra/llui/llfocusmgr.h                 |  2 +-
 indra/llui/llui.cpp                     |  9 +++++++++
 indra/llui/llui.h                       |  2 ++
 indra/newview/llpanelnearbymedia.cpp    |  9 +++++++++
 indra/newview/llpanelnearbymedia.h      |  1 +
 indra/newview/llpanelvolumepulldown.cpp | 14 ++++++++------
 indra/newview/llpanelvolumepulldown.h   |  2 +-
 indra/newview/llpopupview.cpp           | 18 ++++++++++++++++--
 indra/newview/llpopupview.h             |  4 +++-
 indra/newview/llstatusbar.cpp           | 33 +++++++++++----------------------
 indra/newview/llviewerwindow.cpp        | 27 +++++++++++++++++++++++++++
 15 files changed, 100 insertions(+), 42 deletions(-)

diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index de3bf719ee..c679717807 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -160,7 +160,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
 
 	createLineEditor(p);
 
-	setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
+	mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
 }
 
 void LLComboBox::initFromParams(const LLComboBox::Params& p)
@@ -187,6 +187,9 @@ BOOL LLComboBox::postBuild()
 LLComboBox::~LLComboBox()
 {
 	// children automatically deleted, including mMenu, mButton
+
+	// explicitly disconect this signal, since base class destructor might fire top lost
+	mTopLostSignalConnection.disconnect();
 }
 
 
@@ -612,16 +615,14 @@ void LLComboBox::showList()
 
 	mList->setFocus(TRUE);
 
-	// register ourselves as a "top" control
-	// effectively putting us into a special draw layer
-	// and not affecting the bounding rectangle calculation
-	LLUI::addPopup(this);
-
 	// Show the list and push the button down
 	mButton->setToggleState(TRUE);
 	mList->setVisible(TRUE);
 	
+	LLUI::addPopup(this);
+
 	setUseBoundingRect(TRUE);
+	updateBoundingRect();
 }
 
 void LLComboBox::hideList()
@@ -645,6 +646,7 @@ void LLComboBox::hideList()
 
 		setUseBoundingRect(FALSE);
 		LLUI::removePopup(this);
+		updateBoundingRect();
 	}
 }
 
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 4f27588467..aa1e708bec 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -231,5 +231,6 @@ private:
 	commit_callback_t	mTextEntryCallback;
 	commit_callback_t	mSelectionCallback;
 	S32                 mLastSelectedIndex;
+	boost::signals2::connection mTopLostSignalConnection;
 };
 #endif
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index b93b72abf6..c45be34d43 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1354,7 +1354,7 @@ void LLFloater::bringToFront( S32 x, S32 y )
 // virtual
 void LLFloater::setVisibleAndFrontmost(BOOL take_focus)
 {
-	gFocusMgr.setTopCtrl(NULL);
+	LLUI::clearPopups();
 	setVisible(TRUE);
 	setFrontmost(take_focus);
 }
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index ad2940e685..b3af258456 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -437,9 +437,9 @@ void LLFocusMgr::setAppHasFocus(BOOL focus)
 	}
 	
 	// release focus from "top ctrl"s, which generally hides them
-	if (!focus && mTopCtrl)
+	if (!focus)
 	{
-		setTopCtrl(NULL);
+		LLUI::clearPopups();
 	}
 	mAppHasFocus = focus; 
 }
diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h
index 5b08c628d4..86d3ccf111 100644
--- a/indra/llui/llfocusmgr.h
+++ b/indra/llui/llfocusmgr.h
@@ -65,10 +65,10 @@ public:
 	virtual BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent);
 	virtual BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
+	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
 protected:	
 	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
-	virtual void	onTopLost();	// called when registered as top ctrl and user clicks elsewhere
 	focus_signal_t*  mFocusLostCallback;
 	focus_signal_t*  mFocusReceivedCallback;
 	focus_signal_t*  mFocusChangedCallback;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 64df1dbc7a..5121ef5351 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1905,6 +1905,15 @@ void LLUI::removePopup(LLView* viewp)
 	}
 }
 
+//static
+void LLUI::clearPopups()
+{
+	if (sClearPopupsFunc)
+	{
+		sClearPopupsFunc();
+	}
+}
+
 
 //static
 // spawn_x and spawn_y are top left corner of view in screen GL coordinates
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 824d76f526..30f3623ded 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -212,8 +212,10 @@ public:
 	static F32 getMouseIdleTime() { return sMouseIdleTimer.getElapsedTimeF32(); }
 	static void resetMouseIdleTimer() { sMouseIdleTimer.reset(); }
 	static LLWindow* getWindow() { return sWindow; }
+
 	static void addPopup(LLView*);
 	static void removePopup(LLView*);
+	static void clearPopups();
 
 	// Ensures view does not overlap mouse cursor, but is inside
 	// the view's parent rectangle.  Used for tooltips, inspectors.
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index 41e37a9b1b..4bbecc4799 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -82,6 +82,8 @@ LLPanelNearByMedia::LLPanelNearByMedia()
 	  mParcelMediaItem(NULL),
 	  mParcelAudioItem(NULL)
 {
+	mHoverTimer.stop();
+
 	mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
 							gSavedSettings.getBOOL("MediaTentativeAutoPlay");
 
@@ -187,6 +189,13 @@ void LLPanelNearByMedia::onMouseLeave(S32 x, S32 y, MASK mask)
 	LLPanel::onMouseLeave(x,y,mask);
 }
 
+/*virtual*/ 
+void LLPanelNearByMedia::onTopLost()
+{
+	setVisible(FALSE);
+}
+
+
 /*virtual*/ 
 void LLPanelNearByMedia::handleVisibilityChange ( BOOL new_visibility )
 {
diff --git a/indra/newview/llpanelnearbymedia.h b/indra/newview/llpanelnearbymedia.h
index 809a8d81a1..af4659365f 100644
--- a/indra/newview/llpanelnearbymedia.h
+++ b/indra/newview/llpanelnearbymedia.h
@@ -53,6 +53,7 @@ public:
 	/*virtual*/ void draw();
 	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
 	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
+	/*virtual*/ void onTopLost();
 	/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp
index 559997254e..ae52bd3703 100644
--- a/indra/newview/llpanelvolumepulldown.cpp
+++ b/indra/newview/llpanelvolumepulldown.cpp
@@ -56,6 +56,8 @@
 // Default constructor
 LLPanelVolumePulldown::LLPanelVolumePulldown()
 {
+	mHoverTimer.stop();
+
     mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2));
 	mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2));
 	LLUICtrlFactory::instance().buildPanel(this, "panel_volume_pulldown.xml");
@@ -77,6 +79,11 @@ void LLPanelVolumePulldown::onMouseEnter(S32 x, S32 y, MASK mask)
 	LLPanel::onMouseEnter(x,y,mask);
 }
 
+/*virtual*/
+void LLPanelVolumePulldown::onTopLost()
+{
+	setVisible(FALSE);
+}
 
 /*virtual*/
 void LLPanelVolumePulldown::onMouseLeave(S32 x, S32 y, MASK mask)
@@ -95,13 +102,8 @@ void LLPanelVolumePulldown::handleVisibilityChange ( BOOL new_visibility )
 	else
 	{
 		mHoverTimer.stop();
-	}
-}
 
-/*virtual*/ 
-void LLPanelVolumePulldown::onTopLost()
-{
-	setVisible(FALSE);
+	}
 }
 
 void LLPanelVolumePulldown::onAdvancedButtonClick(const LLSD& user_data)
diff --git a/indra/newview/llpanelvolumepulldown.h b/indra/newview/llpanelvolumepulldown.h
index 9f20caa1a8..7fb025f329 100644
--- a/indra/newview/llpanelvolumepulldown.h
+++ b/indra/newview/llpanelvolumepulldown.h
@@ -47,8 +47,8 @@ class LLPanelVolumePulldown : public LLPanel
 	/*virtual*/ void draw();
 	/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
 	/*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask);
-	/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
 	/*virtual*/ void onTopLost();
+	/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
 	/*virtual*/ BOOL postBuild();
 	
  private:
diff --git a/indra/newview/llpopupview.cpp b/indra/newview/llpopupview.cpp
index 964ca4d361..eb750a87e2 100644
--- a/indra/newview/llpopupview.cpp
+++ b/indra/newview/llpopupview.cpp
@@ -100,7 +100,7 @@ BOOL LLPopupView::handleMouseEvent(boost::function<BOOL(LLView*, S32, S32)> func
 
 		S32 popup_x, popup_y;
 		if (localPointToOtherView(x, y, &popup_x, &popup_y, popup) 
-			&& popup->getRect().pointInRect(popup_x, popup_y))
+			&& popup->pointInView(popup_x, popup_y))
 		{
 			if (func(popup, popup_x, popup_y))
 			{
@@ -180,9 +180,9 @@ BOOL LLPopupView::handleToolTip(S32 x, S32 y, MASK mask)
 
 void LLPopupView::addPopup(LLView* popup)
 {
-	removePopup(popup);
 	if (popup)
 	{
+		mPopups.erase(std::find(mPopups.begin(), mPopups.end(), popup->getHandle()));
 		mPopups.push_back(popup->getHandle());
 	}
 }
@@ -191,12 +191,26 @@ void LLPopupView::removePopup(LLView* popup)
 {
 	if (popup)
 	{
+		if (gFocusMgr.childHasKeyboardFocus(popup))
+		{
+			gFocusMgr.setKeyboardFocus(NULL);
+		}
+		popup->onTopLost();
 		mPopups.erase(std::find(mPopups.begin(), mPopups.end(), popup->getHandle()));
 	}
 }
 
 void LLPopupView::clearPopups()
 {
+	for (popup_list_t::iterator popup_it = mPopups.begin();
+		popup_it != mPopups.end();)
+	{
+		LLView* popup = popup_it->get();
+		++popup_it;
+
+		if (popup) popup->onTopLost();
+	}
+
 	mPopups.clear();
 }
 
diff --git a/indra/newview/llpopupview.h b/indra/newview/llpopupview.h
index 591e033161..c5dbb94c4c 100644
--- a/indra/newview/llpopupview.h
+++ b/indra/newview/llpopupview.h
@@ -56,9 +56,11 @@ public:
 	void removePopup(LLView* popup);
 	void clearPopups();
 
+	typedef std::list<LLHandle<LLView> > popup_list_t;
+	popup_list_t getCurrentPopups() { return mPopups; }
+
 private:
 	BOOL handleMouseEvent(boost::function<BOOL(LLView*, S32, S32)>, boost::function<bool(LLView*)>, S32 x, S32 y);
-	typedef std::list<LLHandle<LLView> > popup_list_t;
 	popup_list_t mPopups;
 };
 #endif //LL_LLROOTVIEW_H
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 732c23982b..2ed0718e41 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -239,20 +239,16 @@ BOOL LLStatusBar::postBuild()
 
 	childSetActionTextbox("stat_btn", onClickStatGraph);
 
-	LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder");
-
 	mPanelVolumePulldown = new LLPanelVolumePulldown();
-	popup_holder->addChild(mPanelVolumePulldown);
+	addChild(mPanelVolumePulldown);
+	mPanelVolumePulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
+	mPanelVolumePulldown->setVisible(FALSE);
 
 	mPanelNearByMedia = new LLPanelNearByMedia();
-	popup_holder->addChild(mPanelNearByMedia);
-	gViewerWindow->getRootView()->addMouseDownCallback(boost::bind(&LLStatusBar::onClickScreen, this, _1, _2));
+	addChild(mPanelNearByMedia);
 	mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
 	mPanelNearByMedia->setVisible(FALSE);
 
-	mPanelVolumePulldown->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
-	mPanelVolumePulldown->setVisible(FALSE);
-
 	return TRUE;
 }
 
@@ -538,8 +534,10 @@ void LLStatusBar::onMouseEnterVolume()
 
 
 	// show the master volume pull-down
-	mPanelVolumePulldown->setVisible(TRUE);
+	LLUI::clearPopups();
+	LLUI::addPopup(mPanelVolumePulldown);
 	mPanelNearByMedia->setVisible(FALSE);
+	mPanelVolumePulldown->setVisible(TRUE);
 }
 
 void LLStatusBar::onMouseEnterNearbyMedia()
@@ -558,8 +556,11 @@ void LLStatusBar::onMouseEnterNearbyMedia()
 	
 	// show the master volume pull-down
 	mPanelNearByMedia->setShape(nearby_media_rect);
-	mPanelNearByMedia->setVisible(TRUE);
+	LLUI::clearPopups();
+	LLUI::addPopup(mPanelNearByMedia);
+
 	mPanelVolumePulldown->setVisible(FALSE);
+	mPanelNearByMedia->setVisible(TRUE);
 }
 
 
@@ -648,18 +649,6 @@ void LLStatusBar::onClickStatGraph(void* data)
 	LLFloaterReg::showInstance("lagmeter");
 }
 
-void LLStatusBar::onClickScreen(S32 x, S32 y)
-{
-	if (mPanelNearByMedia->getVisible())
-	{
-		LLRect screen_rect = mPanelNearByMedia->calcScreenRect();
-		if (!screen_rect.pointInRect(x, y))
-		{
-			mPanelNearByMedia->setVisible(FALSE);
-		}
-	}
-}
-
 BOOL can_afford_transaction(S32 cost)
 {
 	return((cost <= 0)||((gStatusBar) && (gStatusBar->getBalance() >=cost)));
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5bd79c67c3..1304a66397 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2590,6 +2590,33 @@ void LLViewerWindow::updateUI()
 	}
 
 	// aggregate visible views that contain mouse cursor in display order
+	LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
+
+	for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
+	{
+		LLView* popup = popup_it->get();
+		if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+		{
+			// iterator over contents of top_ctrl, and throw into mouse_hover_set
+			for (LLView::tree_iterator_t it = popup->beginTreeDFS();
+				it != popup->endTreeDFS();
+				++it)
+			{
+				LLView* viewp = *it;
+				if (viewp->getVisible()
+					&& viewp->calcScreenBoundingRect().pointInRect(x, y))
+				{
+					// we have a view that contains the mouse, add it to the set
+					mouse_hover_set.insert(viewp->getHandle());
+				}
+				else
+				{
+					// skip this view and all of its children
+					it.skipDescendants();
+				}
+			}
+		}
+	}
 
 	// while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
 	if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
-- 
cgit v1.2.3