Maelstrom: Moved base checkbox functionality to the library directory and added the first pass of base radio button functionality.

https://github.com/libsdl-org/Maelstrom/commit/5a324209d007d6b938299eb9de338a3e2ab82635

From 5a324209d007d6b938299eb9de338a3e2ab82635 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 29 Oct 2011 10:25:49 -0400
Subject: [PATCH] Moved base checkbox functionality to the library directory
 and added the first pass of base radio button functionality.

---
 UIDialogCheckbox.cpp            |  18 +-----
 UIDialogCheckbox.h              |  13 +---
 screenlib/Makefile.am           |   4 ++
 screenlib/UIElementCheckbox.cpp |  35 +++++++++++
 screenlib/UIElementCheckbox.h   |  46 +++++++++++++++
 screenlib/UIElementRadio.cpp    |  55 +++++++++++++++++
 screenlib/UIElementRadio.h      | 101 ++++++++++++++++++++++++++++++++
 screenlib/UIElementRect.h       |   2 +-
 screenlib/UIManager.cpp         |   8 +++
 9 files changed, 256 insertions(+), 26 deletions(-)
 create mode 100644 screenlib/UIElementCheckbox.cpp
 create mode 100644 screenlib/UIElementCheckbox.h
 create mode 100644 screenlib/UIElementRadio.cpp
 create mode 100644 screenlib/UIElementRadio.h

diff --git a/UIDialogCheckbox.cpp b/UIDialogCheckbox.cpp
index 771eac7c..5017ab20 100644
--- a/UIDialogCheckbox.cpp
+++ b/UIDialogCheckbox.cpp
@@ -11,10 +11,8 @@ UIElementType UIDialogCheckbox::s_elementType;
 
 
 UIDialogCheckbox::UIDialogCheckbox(UIBaseElement *parent, const char *name) :
-	UIElementButton(parent, name)
+	UIElementCheckbox(parent, name)
 {
-	m_checked = false;
-
 	m_color = m_screen->MapRGB(0x00, 0x00, 0x00);
 
 	SetSize(CHECKBOX_SIZE, CHECKBOX_SIZE);
@@ -29,12 +27,10 @@ UIDialogCheckbox::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
 {
 	rapidxml::xml_attribute<> *attr;
 
-	if (!UIElementButton::Load(node, templates)) {
+	if (!UIElementCheckbox::Load(node, templates)) {
 		return false;
 	}
 
-	LoadBool(node, "checked", m_checked);
-
 	attr = node->first_attribute("text", 0, false);
 	if (attr) {
 		UIDialogLabel *label;
@@ -54,7 +50,7 @@ UIDialogCheckbox::Draw()
 {
 	m_screen->DrawRect(X(), Y(), Width(), Height(), m_color);
 
-	if ( m_checked ) {
+	if ( IsChecked() ) {
 		m_screen->DrawLine(X(), Y(),
 				X()+Width()-1, Y()+Height()-1, m_color);
 		m_screen->DrawLine(X(), Y()+Height()-1,
@@ -63,11 +59,3 @@ UIDialogCheckbox::Draw()
 
 	UIElementButton::Draw();
 }
-
-void
-UIDialogCheckbox::OnClick()
-{
-	UIElementButton::OnClick();
-
-	m_checked = !m_checked;
-}
diff --git a/UIDialogCheckbox.h b/UIDialogCheckbox.h
index 35042aa1..fb6943eb 100644
--- a/UIDialogCheckbox.h
+++ b/UIDialogCheckbox.h
@@ -1,32 +1,25 @@
 #ifndef _UIDialogCheckbox_h
 #define _UIDialogCheckbox_h
 
-#include "screenlib/UIElementButton.h"
+#include "screenlib/UIElementCheckbox.h"
 
 
-class UIDialogCheckbox : public UIElementButton
+class UIDialogCheckbox : public UIElementCheckbox
 {
 public:
 	UIDialogCheckbox(UIBaseElement *parent, const char *name = "");
 	virtual ~UIDialogCheckbox();
 
 	virtual bool IsA(UIElementType type) {
-		return UIElementButton::IsA(type) || type == GetType();
-	}
-
-	bool IsChecked() const {
-		return m_checked;
+		return UIElementCheckbox::IsA(type) || type == GetType();
 	}
 
 	virtual bool Load(rapidxml::xml_node<> *node, const UITemplates *templates);
 
 	virtual void Draw();
 
-	virtual void OnClick();
-
 protected:
 	Uint32 m_color;
-	bool m_checked;
 
 protected:
 	static UIElementType s_elementType;
diff --git a/screenlib/Makefile.am b/screenlib/Makefile.am
index 2d8f79d9..c9558dc5 100644
--- a/screenlib/Makefile.am
+++ b/screenlib/Makefile.am
@@ -13,10 +13,14 @@ libSDLscreen_a_SOURCES =	\
 	UIElement.h		\
 	UIElementButton.cpp	\
 	UIElementButton.h	\
+	UIElementCheckbox.cpp	\
+	UIElementCheckbox.h	\
 	UIElementLabel.cpp	\
 	UIElementLabel.h	\
 	UIElementLine.cpp	\
 	UIElementLine.h		\
+	UIElementRadio.cpp	\
+	UIElementRadio.h	\
 	UIElementRect.cpp	\
 	UIElementRect.h		\
 	UIElementTexture.cpp	\
diff --git a/screenlib/UIElementCheckbox.cpp b/screenlib/UIElementCheckbox.cpp
new file mode 100644
index 00000000..3d8226e5
--- /dev/null
+++ b/screenlib/UIElementCheckbox.cpp
@@ -0,0 +1,35 @@
+
+#include "UIElementCheckbox.h"
+
+UIElementType UIElementCheckbox::s_elementType;
+
+
+UIElementCheckbox::UIElementCheckbox(UIBaseElement *parent, const char *name) :
+	UIElementButton(parent, name)
+{
+	m_checked = false;
+}
+
+bool
+UIElementCheckbox::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
+{
+	if (!UIElementButton::Load(node, templates)) {
+		return false;
+	}
+
+	/* Call SetChecked() to trigger derived classes' behaviors */
+	bool checked;
+	if (LoadBool(node, "checked", checked)) {
+		SetChecked(checked);
+	}
+
+	return true;
+}
+
+void
+UIElementCheckbox::OnClick()
+{
+	UIElementButton::OnClick();
+
+	SetChecked(!m_checked);
+}
diff --git a/screenlib/UIElementCheckbox.h b/screenlib/UIElementCheckbox.h
new file mode 100644
index 00000000..53e50bfb
--- /dev/null
+++ b/screenlib/UIElementCheckbox.h
@@ -0,0 +1,46 @@
+#ifndef _UIElementCheckbox_h
+#define _UIElementCheckbox_h
+
+#include "UIElementButton.h"
+
+
+class UIElementCheckbox : public UIElementButton
+{
+public:
+	UIElementCheckbox(UIBaseElement *parent, const char *name = "");
+
+	virtual bool IsA(UIElementType type) {
+		return UIElementButton::IsA(type) || type == GetType();
+	}
+
+	void SetChecked(bool checked) {
+		if (checked != m_checked) {
+			m_checked = checked;
+			OnChecked(checked);
+		}
+	}
+	bool IsChecked() const {
+		return m_checked;
+	}
+	virtual void OnChecked(bool checked) { }
+
+	virtual bool Load(rapidxml::xml_node<> *node, const UITemplates *templates);
+
+	virtual void OnClick();
+
+protected:
+	bool m_checked;
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
+};
+
+#endif // _UIElementCheckbox_h
diff --git a/screenlib/UIElementRadio.cpp b/screenlib/UIElementRadio.cpp
new file mode 100644
index 00000000..763db024
--- /dev/null
+++ b/screenlib/UIElementRadio.cpp
@@ -0,0 +1,55 @@
+
+#include "UIElementRadio.h"
+
+UIElementType UIElementRadioGroup::s_elementType;
+
+
+UIElementRadioGroup::UIElementRadioGroup(UIBaseElement *parent, const char *name) :
+	UIElement(parent, name)
+{
+	m_value = -1;
+}
+
+void
+UIElementRadioGroup::RadioButtonChecked(UIElementRadioButton *button)
+{
+	for (unsigned i = 0; i < m_elements.length(); ++i) {
+		if (m_elements[i] != button &&
+		    m_elements[i]->IsA(UIElementRadioButton::GetType())) {
+			static_cast<UIElementRadioButton*>(m_elements[i])->SetChecked(false);
+		}
+	}
+	m_value = button->GetID();
+}
+
+
+UIElementType UIElementRadioButton::s_elementType;
+
+
+UIElementRadioButton::UIElementRadioButton(UIBaseElement *parent, const char *name) :
+	UIElementCheckbox(parent, name)
+{
+	m_id = -1;
+}
+
+bool
+UIElementRadioButton::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
+{
+	if (!UIElementCheckbox::Load(node, templates)) {
+		return false;
+	}
+
+	LoadNumber(node, "id", m_id);
+
+	return true;
+}
+
+void
+UIElementRadioButton::OnChecked(bool checked)
+{
+	if (checked) {
+		if (m_parent->IsA(UIElementRadioGroup::GetType())) {
+			static_cast<UIElementRadioGroup*>(m_parent)->RadioButtonChecked(this);
+		}
+	}
+}
diff --git a/screenlib/UIElementRadio.h b/screenlib/UIElementRadio.h
new file mode 100644
index 00000000..0c336a17
--- /dev/null
+++ b/screenlib/UIElementRadio.h
@@ -0,0 +1,101 @@
+/*
+    SCREENLIB:  A framebuffer library based on the SDL library
+    Copyright (C) 1997  Sam Lantinga
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifndef _UIElementRadio_h
+#define _UIElementRadio_h
+
+#include "UIElement.h"
+#include "UIElementCheckbox.h"
+
+//
+// This file has two classes:
+//
+// UIElementRadioGroup maintains the state of radio buttons
+//
+// UIElementRadioButton is a member of the radio group and notifies the group
+// when it is clicked.
+
+class UIElementRadioButton;
+
+class UIElementRadioGroup : public UIElement
+{
+public:
+	UIElementRadioGroup(UIBaseElement *parent, const char *name = "");
+
+	virtual bool IsA(UIElementType type) {
+		return UIElement::IsA(type) || type == GetType();
+	}
+
+	void RadioButtonChecked(UIElementRadioButton *button);
+
+	int GetValue() const {
+		return m_value;
+	}
+
+protected:
+	int m_value;
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
+};
+
+class UIElementRadioButton : public UIElementCheckbox
+{
+public:
+	UIElementRadioButton(UIBaseElement *parent, const char *name = "");
+
+	virtual bool IsA(UIElementType type) {
+		return UIElementCheckbox::IsA(type) || type == GetType();
+	}
+
+	int GetID() const {
+		return m_id;
+	}
+
+	virtual bool Load(rapidxml::xml_node<> *node, const UITemplates *templates);
+
+	virtual void OnChecked(bool checked);
+
+protected:
+	int m_id;
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
+};
+
+#endif // _UIElementRadio_h
diff --git a/screenlib/UIElementRect.h b/screenlib/UIElementRect.h
index 5c2dce0c..a84681fe 100644
--- a/screenlib/UIElementRect.h
+++ b/screenlib/UIElementRect.h
@@ -43,7 +43,7 @@ class UIElementRect : public UIElement
 		m_color = color;
 	}
 
-private:
+protected:
 	bool m_fill;
 	Uint32 m_color;
 
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
index d4bdd92b..c61d8b36 100644
--- a/screenlib/UIManager.cpp
+++ b/screenlib/UIManager.cpp
@@ -26,7 +26,9 @@
 #include "UIManager.h"
 #include "UIPanel.h"
 #include "UIElementButton.h"
+#include "UIElementCheckbox.h"
 #include "UIElementLine.h"
+#include "UIElementRadio.h"
 #include "UIElementRect.h"
 
 
@@ -291,6 +293,12 @@ UIManager::CreateElement(UIBaseElement *parent, const char *type)
 		return new UIElementRect(parent);
 	} else if (strcasecmp(type, "Button") == 0) {
 		return new UIElementButton(parent);
+	} else if (strcasecmp(type, "Checkbox") == 0) {
+		return new UIElementCheckbox(parent);
+	} else if (strcasecmp(type, "RadioGroup") == 0) {
+		return new UIElementRadioGroup(parent);
+	} else if (strcasecmp(type, "RadioButton") == 0) {
+		return new UIElementRadioButton(parent);
 	}
 	return NULL;
 }