#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_HAIKU
#include "../../core/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>
#include <memory>
enum
{
G_CLOSE_BUTTON_ID = -1,
G_DEFAULT_BUTTON_ID = 0,
G_MAX_STRING_LENGTH_BYTES = 120
};
class HAIKU_SDL_MessageBox : public BAlert
{
float fComputedMessageBoxWidth;
BTextView *fMessageBoxTextView;
int fCloseButton;
int fDefaultButton;
bool fCustomColorScheme;
bool fThereIsLongLine;
rgb_color fTextColor;
const char *fTitle;
const char *HAIKU_SDL_DefTitle;
const char *HAIKU_SDL_DefMessage;
const char *HAIKU_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
{
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(HAIKU_SDL_DefTitle);
SetMessageText(HAIKU_SDL_DefMessage);
AddButton(HAIKU_SDL_DefButton);
return;
}
if (aMessageBoxData->numbuttons <= 0) {
AddButton(HAIKU_SDL_DefButton);
} else {
AddSdlButtons(aMessageBoxData->buttons, aMessageBoxData->numbuttons);
}
if (aMessageBoxData->colorScheme != NULL) {
fCustomColorScheme = true;
ApplyAndParseColorScheme(aMessageBoxData->colorScheme);
}
(aMessageBoxData->title[0]) ?
SetTitle(aMessageBoxData->title) : SetTitle(HAIKU_SDL_DefTitle);
(aMessageBoxData->message[0]) ?
SetMessageText(aMessageBoxData->message) : SetMessageText(HAIKU_SDL_DefMessage);
SetType(ConvertMessageBoxType(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));
ButtonAt(i)->SetHighColor(ConvertColorType(aTextColor));
}
}
(void)aSelectedColor;
}
void
SetBackgroundColor(const SDL_MessageBoxColor *aColor)
{
rgb_color background = ConvertColorType(aColor);
GetLayout()->View()->SetViewColor(background);
FindView("TAlertView")->SetViewColor(background);
fMessageBoxTextView->SetViewColor(background);
}
bool
CheckLongLines(const char *aMessage)
{
int final = 0;
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;
}
fMessageBoxTextView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
fMessageBoxTextView->Insert(aMessage);
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(), &HAIKU_SDL_MessageBox::SortButtonsPredicate);
size_t countButtons = fButtons.size();
for (size_t i = 0; i < countButtons; ++i) {
if (fButtons[i]->flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
fCloseButton = static_cast<int>(i);
}
if (fButtons[i]->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
fDefaultButton = static_cast<int>(i);
}
AddButton(fButtons[i]->text);
}
SetDefaultButton(ButtonAt(fDefaultButton));
}
public:
explicit
HAIKU_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),
HAIKU_SDL_DefTitle("SDL MessageBox"),
HAIKU_SDL_DefMessage("Some information has been lost."),
HAIKU_SDL_DefButton("OK")
{
SetLook(B_TITLED_WINDOW_LOOK);
SetFlags(Flags() | B_CLOSE_ON_ESCAPE);
fMessageBoxTextView = TextView();
fMessageBoxTextView->SetWordWrap(false);
fMessageBoxTextView->SetStylable(true);
ParseSdlMessageBoxData(aMessageBoxData);
}
int
GetCloseButtonId(void) const
{
return fCloseButton;
}
virtual
~HAIKU_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
bool HAIKU_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
*buttonID = G_CLOSE_BUTTON_ID;
std::unique_ptr<BApplication> application;
if (!be_app) {
application = std::unique_ptr<BApplication>(new(std::nothrow) BApplication(SDL_signature));
if (!application) {
return SDL_SetError("Cannot create the BApplication object. Lack of memory?");
}
}
HAIKU_SDL_MessageBox *SDL_MessageBox = new(std::nothrow) HAIKU_SDL_MessageBox(messageboxdata);
if (!SDL_MessageBox) {
return SDL_SetError("Cannot create the HAIKU_SDL_MessageBox (BAlert inheritor) object. Lack of memory?");
}
const int closeButton = SDL_MessageBox->GetCloseButtonId();
int pushedButton = SDL_MessageBox->Go();
if (closeButton != G_CLOSE_BUTTON_ID && pushedButton == G_CLOSE_BUTTON_ID) {
pushedButton = closeButton;
}
*buttonID = pushedButton;
return true;
}
#ifdef __cplusplus
}
#endif
#endif