Browse Source

haiku: Implement message box for Haiku

Add implementation for functions:

SDL_ShowSimpleMessageBox()
SDL_ShowMessageBox()

Add simple customization support also.
Fix build for x86_gcc2.

Partially fixes Bugzilla #4442.
EXL 5 years ago
parent
commit
b22fb9e2ba

+ 2 - 1
include/SDL_syswm.h

@@ -132,7 +132,8 @@ typedef enum
     SDL_SYSWM_WINRT,
     SDL_SYSWM_ANDROID,
     SDL_SYSWM_VIVANTE,
-    SDL_SYSWM_OS2
+    SDL_SYSWM_OS2,
+    SDL_SYSWM_HAIKU
 } SDL_SYSWM_TYPE;
 
 /**

+ 3 - 2
src/main/haiku/SDL_BeApp.cc

@@ -48,13 +48,14 @@ extern "C" {
 static int SDL_BeAppActive = 0;
 static SDL_Thread *SDL_AppThread = NULL;
 
+/* Default application signature */
+const char *signature = "application/x-SDL-executable";
+
 static int
 StartBeApp(void *unused)
 {
     BApplication *App;
 
-    // default application signature
-    const char *signature = "application/x-SDL-executable";
     // dig resources for correct signature
     image_info info;
     int32 cookie = 0;

+ 3 - 0
src/main/haiku/SDL_BeApp.h

@@ -31,6 +31,9 @@ extern int SDL_InitBeApp(void);
 /* Quit the Be Application, if there's nothing left to do */
 extern void SDL_QuitBeApp(void);
 
+/* Be Application Signature*/
+extern const char *signature;
+
 /* vi: set ts=4 sw=4 expandtab: */
 
 #ifdef __cplusplus

+ 11 - 1
src/video/SDL_video.c

@@ -3846,9 +3846,12 @@ SDL_IsScreenKeyboardShown(SDL_Window *window)
 #if SDL_VIDEO_DRIVER_X11
 #include "x11/SDL_x11messagebox.h"
 #endif
+#if SDL_VIDEO_DRIVER_HAIKU
+#include "haiku/SDL_bmessagebox.h"
+#endif
 
 
-#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 || SDL_VIDEO_DRIVER_HAIKU
 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
 {
     SDL_SysWMinfo info;
@@ -3940,6 +3943,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
         retval = 0;
     }
+#endif
+#if SDL_VIDEO_DRIVER_HAIKU
+    if (retval == -1 &&
+        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_HAIKU) &&
+        BE_ShowMessageBox(messageboxdata, buttonid) == 0) {
+        retval = 0;
+    }
 #endif
     if (retval == -1) {
         SDL_SetError("No message system available");

+ 425 - 0
src/video/haiku/SDL_bmessagebox.cc

@@ -0,0 +1,425 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 2018 EXL <exlmotodev@gmail.com>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_HAIKU
+
+#include "SDL_messagebox.h"
+
+/* For application signature. */
+#include "../../main/haiku/SDL_BeApp.h"
+
+#include <Alert.h>
+#include <Application.h>
+#include <Button.h>
+#include <Font.h>
+#include <Layout.h>
+#include <String.h>
+#include <TextView.h>
+#include <View.h>
+#include <Window.h>
+
+#include <InterfaceDefs.h>
+#include <SupportDefs.h>
+#include <GraphicsDefs.h>
+
+#include <new>
+#include <vector>
+#include <algorithm>
+
+enum
+{
+	G_CLOSE_BUTTON_ID   = -1,
+	G_DEFAULT_BUTTON_ID = 0,
+	G_MAX_STRING_LENGTH_BYTES = 120
+};
+
+class BE_SDL_MessageBox : public BAlert
+{
+	float fComputedMessageBoxWidth;
+
+	BTextView *fMessageBoxTextView;
+
+	int fCloseButton;
+	int fDefaultButton;
+
+	bool fCustomColorScheme;
+	bool fThereIsLongLine;
+	rgb_color fTextColor;
+
+	const char *fTitle;
+	const char *BE_SDL_DefTitle;
+	const char *BE_SDL_DefMessage;
+	const char *BE_SDL_DefButton;
+
+	std::vector<const SDL_MessageBoxButtonData *> fButtons;
+
+	static bool
+	SortButtonsPredicate(const SDL_MessageBoxButtonData *aButtonLeft,
+	                                 const SDL_MessageBoxButtonData *aButtonRight)
+	{
+		return aButtonLeft->buttonid < aButtonRight->buttonid;
+	}
+
+	alert_type
+	ConvertMessageBoxType(const SDL_MessageBoxFlags aWindowType) const
+	{
+		switch (aWindowType)
+		{
+			default:
+			case SDL_MESSAGEBOX_WARNING:
+			{
+				return B_WARNING_ALERT;
+			}
+			case SDL_MESSAGEBOX_ERROR:
+			{
+				return B_STOP_ALERT;
+			}
+			case SDL_MESSAGEBOX_INFORMATION:
+			{
+				return B_INFO_ALERT;
+			}
+		}
+	}
+
+	rgb_color
+	ConvertColorType(const SDL_MessageBoxColor *aColor) const
+	{
+		rgb_color color = { aColor->r, aColor->g, aColor->b, color.alpha = 255 };
+		return color;
+	}
+
+	int32
+	GetLeftPanelWidth(void) const
+	{
+		// See file "haiku/src/kits/interface/Alert.cpp" for this magic numbers.
+		//    IconStripeWidth = 30 * Scale
+		//    IconSize = 32 * Scale
+		//    Scale = max_c(1, ((int32)be_plain_font->Size() + 15) / 16)
+		//    RealWidth = (IconStripeWidth * Scale) + (IconSize * Scale)
+
+		int32 scale = max_c(1, ((int32)be_plain_font->Size() + 15) / 16);
+		return (30 * scale) + (32 * scale);
+	}
+
+	void
+	UpdateTextViewWidth(void)
+	{
+		fComputedMessageBoxWidth = fMessageBoxTextView->PreferredSize().Width() + GetLeftPanelWidth();
+	}
+
+	void
+	ParseSdlMessageBoxData(const SDL_MessageBoxData *aMessageBoxData)
+	{
+		if (aMessageBoxData == NULL)
+		{
+			SetTitle(BE_SDL_DefTitle);
+			SetMessageText(BE_SDL_DefMessage);
+			AddButton(BE_SDL_DefButton);
+			return;
+		}
+
+		if (aMessageBoxData->numbuttons <= 0)
+		{
+			AddButton(BE_SDL_DefButton);
+		}
+		else
+		{
+			AddSdlButtons(aMessageBoxData->buttons, aMessageBoxData->numbuttons);
+		}
+
+		if (aMessageBoxData->colorScheme != NULL)
+		{
+			fCustomColorScheme = true;
+			ApplyAndParseColorScheme(aMessageBoxData->colorScheme);
+		}
+
+		(aMessageBoxData->title != NULL) ?
+			SetTitle(aMessageBoxData->title) : SetTitle(BE_SDL_DefTitle);
+		(aMessageBoxData->message != NULL) ?
+			SetMessageText(aMessageBoxData->message) : SetMessageText(BE_SDL_DefMessage);
+
+		SetType(ConvertMessageBoxType(static_cast<SDL_MessageBoxFlags>(aMessageBoxData->flags)));
+	}
+
+	void
+	ApplyAndParseColorScheme(const SDL_MessageBoxColorScheme *aColorScheme)
+	{
+		SetBackgroundColor(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BACKGROUND]);
+		fTextColor = ConvertColorType(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT]);
+		SetButtonColors(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER],
+		                &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND],
+		                &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT],
+		                &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED]);
+	}
+
+	void
+	SetButtonColors(const SDL_MessageBoxColor *aBorderColor,
+	                const SDL_MessageBoxColor *aBackgroundColor,
+	                const SDL_MessageBoxColor *aTextColor,
+	                const SDL_MessageBoxColor *aSelectedColor)
+	{
+		if (fCustomColorScheme)
+		{
+			int32 countButtons = CountButtons();
+			for (int i = 0; i < countButtons; ++i)
+			{
+				ButtonAt(i)->SetViewColor(ConvertColorType(aBorderColor));
+				ButtonAt(i)->SetLowColor(ConvertColorType(aBackgroundColor));
+
+				// This doesn't work. See this why:
+				// https://github.com/haiku/haiku/commit/de9c53f8f5008c7b3b0af75d944a628e17f6dffe
+				// Let it remain.
+				ButtonAt(i)->SetHighColor(ConvertColorType(aTextColor));
+			}
+		}
+		// TODO: Not Implemented.
+		// Is it even necessary?!
+		(void)aSelectedColor;
+	}
+
+	void
+	SetBackgroundColor(const SDL_MessageBoxColor *aColor)
+	{
+		rgb_color background = ConvertColorType(aColor);
+
+		GetLayout()->View()->SetViewColor(background);
+		// See file "haiku/src/kits/interface/Alert.cpp", the "TAlertView" is the internal name of the left panel.
+		FindView("TAlertView")->SetViewColor(background);
+		fMessageBoxTextView->SetViewColor(background);
+	}
+
+	bool
+	CheckLongLines(const char *aMessage)
+	{
+		int final = 0;
+
+		// This UTF-8 friendly.
+		BString message = aMessage;
+		int32 length = message.CountChars();
+
+		for (int i = 0, c = 0; i < length; ++i)
+		{
+			c++;
+			if (*(message.CharAt(i)) == '\n')
+			{
+				c = 0;
+			}
+			if (c > final)
+			{
+				final = c;
+			}
+		}
+
+		return (final > G_MAX_STRING_LENGTH_BYTES);
+	}
+
+	void
+	SetMessageText(const char *aMessage)
+	{
+		fThereIsLongLine = CheckLongLines(aMessage);
+		if (fThereIsLongLine)
+		{
+			fMessageBoxTextView->SetWordWrap(true);
+		}
+
+		rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
+		if (fCustomColorScheme)
+		{
+			textColor = fTextColor;
+		}
+
+		/*
+		if (fNoTitledWindow)
+		{
+			fMessageBoxTextView->SetFontAndColor(be_bold_font);
+			fMessageBoxTextView->Insert(fTitle);
+			fMessageBoxTextView->Insert("\n\n");
+			fMessageBoxTextView->SetFontAndColor(be_plain_font);
+		}
+		*/
+
+		fMessageBoxTextView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
+		fMessageBoxTextView->Insert(aMessage);
+
+		// Be sure to call update width method.
+		UpdateTextViewWidth();
+	}
+
+	void
+	AddSdlButtons(const SDL_MessageBoxButtonData *aButtons, int aNumButtons)
+	{
+		for (int i = 0; i < aNumButtons; ++i)
+		{
+			fButtons.push_back(&aButtons[i]);
+		}
+
+		std::sort(fButtons.begin(), fButtons.end(), &BE_SDL_MessageBox::SortButtonsPredicate);
+
+		size_t countButtons = fButtons.size();
+		for (size_t i = 0; i < countButtons; ++i)
+		{
+			switch (fButtons[i]->flags)
+			{
+				case SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT:
+				{
+					fCloseButton = static_cast<int>(i);
+					break;
+				}
+				case SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT:
+				{
+					fDefaultButton = static_cast<int>(i);
+					break;
+				}
+				default:
+				{
+					break;
+				}
+			}
+			AddButton(fButtons[i]->text);
+		}
+
+		SetDefaultButton(ButtonAt(fDefaultButton));
+	}
+
+public:
+	explicit
+	BE_SDL_MessageBox(const SDL_MessageBoxData *aMessageBoxData)
+		: BAlert(NULL, NULL, NULL, NULL, NULL, B_WIDTH_FROM_LABEL, B_WARNING_ALERT),
+		  fComputedMessageBoxWidth(0.0f),
+		  fCloseButton(G_CLOSE_BUTTON_ID), fDefaultButton(G_DEFAULT_BUTTON_ID),
+		  fCustomColorScheme(false), fThereIsLongLine(false),
+		  BE_SDL_DefTitle("SDL2 MessageBox"),
+		  BE_SDL_DefMessage("Some information has been lost."),
+		  BE_SDL_DefButton("OK")
+	{
+		// MessageBox settings.
+		// We need a title to display it.
+		SetLook(B_TITLED_WINDOW_LOOK);
+		SetFlags(Flags() | B_CLOSE_ON_ESCAPE);
+
+		// MessageBox TextView settings.
+		fMessageBoxTextView = TextView();
+		fMessageBoxTextView->SetWordWrap(false);
+		fMessageBoxTextView->SetStylable(true);
+
+		ParseSdlMessageBoxData(aMessageBoxData);
+	}
+
+	int
+	GetCloseButtonId(void) const
+	{
+		return fCloseButton;
+	}
+
+	virtual
+	~BE_SDL_MessageBox(void)
+	{
+		fButtons.clear();
+	}
+
+protected:
+	virtual void
+	FrameResized(float aNewWidth, float aNewHeight)
+	{
+		if (fComputedMessageBoxWidth > aNewWidth)
+		{
+			ResizeTo(fComputedMessageBoxWidth, aNewHeight);
+		}
+		else
+		{
+			BAlert::FrameResized(aNewWidth, aNewHeight);
+		}
+	}
+
+	virtual void
+	SetTitle(const char* aTitle)
+	{
+		fTitle = aTitle;
+		BAlert::SetTitle(aTitle);
+	}
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+BE_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
+{
+	// Initialize button by closed or error value first.
+	*buttonid = G_CLOSE_BUTTON_ID;
+
+	// We need to check "be_app" pointer to "NULL". The "messageboxdata->window" pointer isn't appropriate here
+	// because it is possible to create a MessageBox from another thread. This fixes the following errors:
+	// "You need a valid BApplication object before interacting with the app_server."
+	// "2 BApplication objects were created. Only one is allowed."
+	BApplication *application = NULL;
+	if (be_app == NULL)
+	{
+		application = new(std::nothrow) BApplication(signature);
+		if (application == NULL)
+		{
+			return SDL_SetError("Cannot create the BApplication object. Lack of memory?");
+		}
+	}
+
+	BE_SDL_MessageBox *SDL_MessageBox = new(std::nothrow) BE_SDL_MessageBox(messageboxdata);
+	if (SDL_MessageBox == NULL)
+	{
+		return SDL_SetError("Cannot create the BE_SDL_MessageBox (BAlert inheritor) object. Lack of memory?");
+	}
+	const int closeButton = SDL_MessageBox->GetCloseButtonId();
+	int pushedButton = SDL_MessageBox->Go();
+
+	// The close button is equivalent to pressing Escape.
+	if (closeButton != G_CLOSE_BUTTON_ID && pushedButton == G_CLOSE_BUTTON_ID)
+	{
+		pushedButton = closeButton;
+	}
+
+	// It's deleted by itself after the "Go()" method was executed.
+	/*
+	if (messageBox != NULL)
+	{
+		delete messageBox;
+	}
+	*/
+	if (application != NULL)
+	{
+		delete application;
+	}
+
+	// Initialize button by real pushed value then.
+	*buttonid = pushedButton;
+
+	return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDL_VIDEO_DRIVER_HAIKU */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 45 - 0
src/video/haiku/SDL_bmessagebox.h

@@ -0,0 +1,45 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 2018 EXL <exlmotodev@gmail.com>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_BMESSAGEBOX_H
+#define SDL_BMESSAGEBOX_H
+
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_HAIKU
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int
+BE_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDL_VIDEO_DRIVER_HAIKU */
+
+#endif
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 11 - 1
src/video/haiku/SDL_bwindow.cc

@@ -26,6 +26,8 @@
 #include "SDL_BWin.h"
 #include <new>
 
+#include "SDL_syswm.h"
+
 /* Define a path to window's BWIN data */
 #ifdef __cplusplus
 extern "C" {
@@ -217,7 +219,15 @@ void HAIKU_DestroyWindow(_THIS, SDL_Window * window) {
 SDL_bool HAIKU_GetWindowWMInfo(_THIS, SDL_Window * window,
                                     struct SDL_SysWMinfo *info) {
     /* FIXME: What is the point of this? What information should be included? */
-    return SDL_FALSE;
+	if (info->version.major == SDL_MAJOR_VERSION &&
+	    info->version.minor == SDL_MINOR_VERSION) {
+	    info->subsystem = SDL_SYSWM_HAIKU;
+	    return SDL_TRUE;
+	} else {
+	    SDL_SetError("Application not compiled with SDL %d.%d",
+	                 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
+	    return SDL_FALSE;
+	}
 }