Maelstrom: Added dialog buttons

https://github.com/libsdl-org/Maelstrom/commit/7f877fc4007774668d71bf5b06c3e0c34e401024

From 7f877fc4007774668d71bf5b06c3e0c34e401024 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 29 Oct 2011 01:14:08 -0400
Subject: [PATCH] Added dialog buttons

---
 MaelstromUI.cpp          |   3 +
 Makefile.am              |   2 +
 UI/dawn.xml              |   5 ++
 UIDialogButton.cpp       | 185 +++++++++++++++++++++++++++++++++++++++
 UIDialogButton.h         |  45 ++++++++++
 screenlib/SDL_FrameBuf.h |   5 ++
 6 files changed, 245 insertions(+)
 create mode 100644 UIDialogButton.cpp
 create mode 100644 UIDialogButton.h

diff --git a/MaelstromUI.cpp b/MaelstromUI.cpp
index c8586a0f..d3797ccc 100644
--- a/MaelstromUI.cpp
+++ b/MaelstromUI.cpp
@@ -6,6 +6,7 @@
 #include "netlogic/about.h"
 #include "netlogic/game.h"
 #include "utils/hashtable.h"
+#include "UIDialogButton.h"
 #include "UIDialogLabel.h"
 #include "UIElementIcon.h"
 #include "UIElementKeyButton.h"
@@ -161,6 +162,8 @@ MaelstromUI::CreateElement(UIBaseElement *parent, const char *type)
 		return new UIElementLabel(parent);
 	} else if (strcasecmp(type, "DialogLabel") == 0) {
 		return new UIDialogLabel(parent);
+	} else if (strcasecmp(type, "DialogButton") == 0) {
+		return new UIDialogButton(parent);
 	} else if (strcasecmp(type, "KeyButton") == 0) {
 		return new UIElementKeyButton(parent);
 	} else if (strcasecmp(type, "Icon") == 0) {
diff --git a/Makefile.am b/Makefile.am
index af7fafae..8ddca93e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,6 +34,8 @@ Maelstrom_SOURCES =		\
 	scores.h		\
 	UIDialog.cpp		\
 	UIDialog.h		\
+	UIDialogButton.cpp	\
+	UIDialogButton.h	\
 	UIDialogLabel.cpp	\
 	UIDialogLabel.h		\
 	UIElementIcon.cpp	\
diff --git a/UI/dawn.xml b/UI/dawn.xml
index 0f8a0020..1aeddd61 100644
--- a/UI/dawn.xml
+++ b/UI/dawn.xml
@@ -23,5 +23,10 @@
 		<DialogLabel name="line6" text="dawn.">
 			<Anchor anchorFrom="TOPLEFT" anchorTo="BOTTOMRIGHT" anchor="line5" x="2" y="2"/>
 		</DialogLabel>
+
+		<DialogButton text="OK" default="true" closeDialog="true">
+			<Size w="90"/>
+			<Anchor anchorFrom="TOPLEFT" anchorTo="TOPLEFT" x="210" y="160"/>
+		</DialogButton>
 	</Elements>
 </Dialog>
diff --git a/UIDialogButton.cpp b/UIDialogButton.cpp
new file mode 100644
index 00000000..f3663b0f
--- /dev/null
+++ b/UIDialogButton.cpp
@@ -0,0 +1,185 @@
+
+#include "screenlib/SDL_FrameBuf.h"
+#include "screenlib/UIManager.h"
+#include "UIDialogButton.h"
+#include "UIDialogLabel.h"
+
+/* Default dialog button size */
+#define BUTTON_WIDTH	75
+#define BUTTON_HEIGHT	19
+
+
+UIElementType UIDialogButton::s_elementType;
+
+
+UIDialogButton::UIDialogButton(UIBaseElement *parent, const char *name) :
+	UIElementButton(parent, name)
+{
+	m_default = false;
+	m_closeDialog = false;
+
+	m_colors[0] = m_screen->MapRGB(0xFF, 0xFF, 0xFF);
+	m_colors[1] = m_screen->MapRGB(0x00, 0x00, 0x00);
+
+	SetSize(BUTTON_WIDTH, BUTTON_HEIGHT);
+}
+
+UIDialogButton::~UIDialogButton()
+{
+}
+
+bool
+UIDialogButton::Load(rapidxml::xml_node<> *node, const UITemplates *templates)
+{
+	rapidxml::xml_attribute<> *attr;
+
+	if (!UIElementButton::Load(node, templates)) {
+		return false;
+	}
+
+	attr = node->first_attribute("default", 0, false);
+	if (attr) {
+		const char *value = attr->value();
+
+		if (*value == '1' || *value == 't' || *value == 'T') {
+			m_default = true;
+		}
+	}
+
+	attr = node->first_attribute("closeDialog", 0, false);
+	if (attr) {
+		const char *value = attr->value();
+
+		if (*value == '1' || *value == 't' || *value == 'T') {
+			m_closeDialog = true;
+		}
+	}
+
+	attr = node->first_attribute("text", 0, false);
+	if (attr) {
+		UIDialogLabel *label;
+
+		label = new UIDialogLabel(this, "label");
+		label->SetText(attr->value());
+		AddElement(label);
+	}
+
+	return true;
+}
+
+void
+UIDialogButton::Draw()
+{
+	Uint32 bg, fg;
+	int x, y, maxx, maxy;
+
+	/* The colors are inverted when the mouse is pressed */
+	bg = m_colors[m_mousePressed];
+	fg = m_colors[!m_mousePressed];
+
+	/* First draw the background */
+	m_screen->FillRect(X(), Y(), Width(), Height(), bg);
+
+	/* Draw the beveled edge */
+	x = X();
+	maxx = x+Width()-1;
+	y = Y();
+	maxy = y+Height()-1;
+
+	/* Top and upper corners */
+	m_screen->DrawLine(x+3, y, maxx-3, y, fg);
+	m_screen->DrawLine(x+1, y+1, x+2, y+1, fg);
+	m_screen->DrawLine(maxx-2, y+1, maxx-1, y+1, fg);
+	m_screen->DrawLine(x+1, y+2, x+1, y+2, fg);
+	m_screen->DrawLine(maxx-1, y+2, maxx-1, y+2, fg);
+
+	/* Sides */
+	m_screen->DrawLine(x, y+3, x, maxy-3, fg);
+	m_screen->DrawLine(maxx, y+3, maxx, maxy-3, fg);
+
+	/* Bottom and lower corners */
+	m_screen->DrawLine(x+1, maxy-2, x+1, maxy-2, fg);
+	m_screen->DrawLine(maxx-1, maxy-2, maxx-1, maxy-2, fg);
+	m_screen->DrawLine(x+1, maxy-1, x+2, maxy-1, fg);
+	m_screen->DrawLine(maxx-2, maxy-1, maxx-1, maxy-1, fg);
+	m_screen->DrawLine(x+3, maxy, maxx-3, maxy, fg);
+
+	if (m_default) {
+		/* Show the thick edge */
+		x = X()-4;
+		maxx = x+4+Width()+4-1;
+		y = Y()-4;
+		maxy = y+4+Height()+4-1;
+
+		/* The edge always uses the real foreground color */
+		fg = m_colors[1];
+
+		m_screen->DrawLine(x+5, y, maxx-5, y, fg);
+		m_screen->DrawLine(x+3, y+1, maxx-3, y+1, fg);
+		m_screen->DrawLine(x+2, y+2, maxx-2, y+2, fg);
+		m_screen->DrawLine(x+1, y+3, x+5, y+3, fg);
+		m_screen->DrawLine(maxx-5, y+3, maxx-1, y+3, fg);
+		m_screen->DrawLine(x+1, y+4, x+3, y+4, fg);
+		m_screen->DrawLine(maxx-3, y+4, maxx-1, y+4, fg);
+		m_screen->DrawLine(x, y+5, x+3, y+5, fg);
+		m_screen->DrawLine(maxx-3, y+5, maxx, y+5, fg);
+
+		m_screen->DrawLine(x, y+6, x, maxy-6, fg);
+		m_screen->DrawLine(maxx, y+6, maxx, maxy-6, fg);
+		m_screen->DrawLine(x+1, y+6, x+1, maxy-6, fg);
+		m_screen->DrawLine(maxx-1, y+6, maxx-1, maxy-6, fg);
+		m_screen->DrawLine(x+2, y+6, x+2, maxy-6, fg);
+		m_screen->DrawLine(maxx-2, y+6, maxx-2, maxy-6, fg);
+
+		m_screen->DrawLine(x, maxy-5, x+3, maxy-5, fg);
+		m_screen->DrawLine(maxx-3, maxy-5, maxx, maxy-5, fg);
+		m_screen->DrawLine(x+1, maxy-4, x+3, maxy-4, fg);
+		m_screen->DrawLine(maxx-3, maxy-4, maxx-1, maxy-4, fg);
+		m_screen->DrawLine(x+1, maxy-3, x+5, maxy-3, fg);
+		m_screen->DrawLine(maxx-5, maxy-3, maxx-1, maxy-3, fg);
+		m_screen->DrawLine(x+2, maxy-2, maxx-2, maxy-2, fg);
+		m_screen->DrawLine(x+3, maxy-1, maxx-3, maxy-1, fg);
+		m_screen->DrawLine(x+5, maxy, maxx-5, maxy, fg);
+	}
+
+	UIElementButton::Draw();
+}
+
+void
+UIDialogButton::OnMouseDown()
+{
+	SetElementColor(m_colors[0]);
+
+	UIElementButton::OnMouseDown();
+}
+
+void
+UIDialogButton::OnMouseUp()
+{
+	SetElementColor(m_colors[1]);
+
+	UIElementButton::OnMouseUp();
+}
+
+void
+UIDialogButton::OnClick()
+{
+	UIElementButton::OnClick();
+
+	if (m_closeDialog) {
+		GetUI()->HidePanel(GetUI()->GetCurrentPanel());
+	}
+}
+
+void
+UIDialogButton::SetElementColor(Uint32 color)
+{
+	Uint8 R, G, B;
+
+	m_screen->GetRGB(color, &R, &G, &B);
+	for (unsigned i = 0; i < m_elements.length(); ++i) {
+		if (m_elements[i]->IsA(UIElementLabel::GetType())) {
+			static_cast<UIElementLabel*>(m_elements[i])->SetTextColor(R, G, B);
+		}
+	}
+}
diff --git a/UIDialogButton.h b/UIDialogButton.h
new file mode 100644
index 00000000..0e872e67
--- /dev/null
+++ b/UIDialogButton.h
@@ -0,0 +1,45 @@
+#ifndef _UIDialogButton_h
+#define _UIDialogButton_h
+
+#include "screenlib/UIElementButton.h"
+
+
+class UIDialogButton : public UIElementButton
+{
+public:
+	UIDialogButton(UIBaseElement *parent, const char *name = "");
+	virtual ~UIDialogButton();
+
+	virtual bool IsA(UIElementType type) {
+		return UIElementButton::IsA(type) || type == GetType();
+	}
+
+	virtual bool Load(rapidxml::xml_node<> *node, const UITemplates *templates);
+
+	virtual void Draw();
+
+	virtual void OnMouseDown();
+	virtual void OnMouseUp();
+	virtual void OnClick();
+
+protected:
+	Uint32 m_colors[2];
+	bool m_default;
+	bool m_closeDialog;
+
+protected:
+	void SetElementColor(Uint32 color);
+
+protected:
+	static UIElementType s_elementType;
+
+public:
+	static UIElementType GetType() {
+		if (!s_elementType) {
+			s_elementType = GenerateType();
+		}
+		return s_elementType;
+	}
+};
+
+#endif // _UIDialogButton_h
diff --git a/screenlib/SDL_FrameBuf.h b/screenlib/SDL_FrameBuf.h
index 1a440be8..08e72641 100644
--- a/screenlib/SDL_FrameBuf.h
+++ b/screenlib/SDL_FrameBuf.h
@@ -54,6 +54,11 @@ class FrameBuf : public ErrorBase {
 	Uint32 MapRGB(Uint8 R, Uint8 G, Uint8 B) {
 		return (0xFF000000 | ((Uint32)R << 16) | ((Uint32)G << 8) | B);
 	}
+	void GetRGB(Uint32 color, Uint8 *R, Uint8 *G, Uint8 *B) {
+		*R = (Uint8)((color >> 16) & 0xFF);
+		*G = (Uint8)((color >>  8) & 0xFF);
+		*B = (Uint8)((color >>  0) & 0xFF);
+	}
 	/* Set the blit clipping rectangle */
 	void   ClipBlit(SDL_Rect *cliprect) {
 		clip = *cliprect;