Maelstrom: Make sure that dropdowns close no matter where else we click

https://github.com/libsdl-org/Maelstrom/commit/313b1f1c7290fba0c46da0d713731c5391f463ec

From 313b1f1c7290fba0c46da0d713731c5391f463ec Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 16 Dec 2012 23:17:03 -0800
Subject: [PATCH] Make sure that dropdowns close no matter where else we click

---
 screenlib/UIElementDropdown.cpp | 10 ++++++++++
 screenlib/UIElementDropdown.h   |  2 +-
 screenlib/UIManager.cpp         | 34 ++++++++++++++++++++++++++++++++-
 screenlib/UIManager.h           |  5 +++++
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/screenlib/UIElementDropdown.cpp b/screenlib/UIElementDropdown.cpp
index c2c088dd..3b158a5a 100644
--- a/screenlib/UIElementDropdown.cpp
+++ b/screenlib/UIElementDropdown.cpp
@@ -19,6 +19,7 @@
   3. This notice may not be removed or altered from any source distribution.
 */
 
+#include "UIManager.h"
 #include "UIElementDropdown.h"
 
 UIElementType UIElementDropdown::s_elementType;
@@ -30,6 +31,11 @@ UIElementDropdown::UIElementDropdown(UIBaseElement *parent, const char *name, UI
 	m_showingElements = true;
 }
 
+UIElementDropdown::~UIElementDropdown()
+{
+	GetUI()->ReleaseEvents(this);
+}
+
 bool
 UIElementDropdown::FinishLoading()
 {
@@ -76,6 +82,8 @@ UIElementDropdown::OnClick()
 void
 UIElementDropdown::ShowElements()
 {
+	GetUI()->CaptureEvents(this);
+
 	for (unsigned int i = 0; i < m_elements.length(); ++i) {
 		m_elements[i]->Show();
 	}
@@ -85,6 +93,8 @@ UIElementDropdown::ShowElements()
 void
 UIElementDropdown::HideElements()
 {
+	GetUI()->ReleaseEvents(this);
+
 	for (unsigned int i = 0; i < m_elements.length(); ++i) {
 		m_elements[i]->Hide();
 	}
diff --git a/screenlib/UIElementDropdown.h b/screenlib/UIElementDropdown.h
index 0e6707ea..850b4b8b 100644
--- a/screenlib/UIElementDropdown.h
+++ b/screenlib/UIElementDropdown.h
@@ -30,7 +30,7 @@ class UIElementDropdown : public UIElementButton
 DECLARE_TYPESAFE_CLASS(UIElementButton)
 public:
 	UIElementDropdown(UIBaseElement *parent, const char *name, UIDrawEngine *drawEngine);
-	virtual ~UIElementDropdown() { }
+	virtual ~UIElementDropdown();
 
 	override bool FinishLoading();
 
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
index 3b1319cf..8801cf09 100644
--- a/screenlib/UIManager.cpp
+++ b/screenlib/UIManager.cpp
@@ -305,6 +305,26 @@ UIManager::DeletePanel(UIPanel *panel)
 	}
 }
 
+void
+UIManager::CaptureEvents(UIBaseElement *element)
+{
+	if (!IsCapturingEvents(element)) {
+		m_eventCapture.add(element);
+	}
+}
+
+void
+UIManager::ReleaseEvents(UIBaseElement *element)
+{
+	m_eventCapture.remove(element);
+}
+
+bool
+UIManager::IsCapturingEvents(UIBaseElement *element)
+{
+	return m_eventCapture.find(element);
+}
+
 void
 UIManager::HideDialogs()
 {
@@ -394,6 +414,8 @@ UIManager::Draw(bool fullUpdate)
 bool
 UIManager::HandleEvent(const SDL_Event &event)
 {
+	unsigned int i;
+
 	if (event.type == SDL_WINDOWEVENT &&
 	    event.window.event == SDL_WINDOWEVENT_RESIZED &&
 	    m_screen->Resizable()) {
@@ -413,7 +435,17 @@ UIManager::HandleEvent(const SDL_Event &event)
 	// In case it's not called any other time...
 	Poll();
 
-	for (unsigned i = m_visible.length(); i--; ) {
+	for (i = m_eventCapture.length(); i--; ) {
+		UIBaseElement *element = m_eventCapture[i];
+
+		for (int drawLevel = NUM_DRAWLEVELS; drawLevel--; ) {
+			if (element->DispatchEvent(event, (DRAWLEVEL)drawLevel)) {
+				return true;
+			}
+		}
+	}
+
+	for (i = m_visible.length(); i--; ) {
 		UIPanel *panel = m_visible[i];
 
 		for (int drawLevel = NUM_DRAWLEVELS; drawLevel--; ) {
diff --git a/screenlib/UIManager.h b/screenlib/UIManager.h
index 4e29335f..8d52fd11 100644
--- a/screenlib/UIManager.h
+++ b/screenlib/UIManager.h
@@ -111,6 +111,10 @@ class UIManager : public UIArea, public UIFontInterface, public UIImageInterface
 		return m_panelTransition;
 	}
 
+	void CaptureEvents(UIBaseElement *element);
+	void ReleaseEvents(UIBaseElement *element);
+	bool IsCapturingEvents(UIBaseElement *element);
+
 	void HideDialogs();
 
 	void SetCondition(const char *token, bool isTrue = true);
@@ -149,6 +153,7 @@ class UIManager : public UIArea, public UIFontInterface, public UIImageInterface
 	array<UIPanel *> m_panels;
 	array<UIPanel *> m_visible;
 	array<UIPanel *> m_delete;
+	array<UIBaseElement *> m_eventCapture;
 	PANEL_TRANSITION_TYPE m_panelTransition;
 	HashTable *m_conditions;
 };