sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_bmessagebox.cc (10674B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4   Copyright (C) 2018-2019 EXL <exlmotodev@gmail.com>
      5 
      6   This software is provided 'as-is', without any express or implied
      7   warranty.  In no event will the authors be held liable for any damages
      8   arising from the use of this software.
      9 
     10   Permission is granted to anyone to use this software for any purpose,
     11   including commercial applications, and to alter it and redistribute it
     12   freely, subject to the following restrictions:
     13 
     14   1. The origin of this software must not be misrepresented; you must not
     15      claim that you wrote the original software. If you use this software
     16      in a product, an acknowledgment in the product documentation would be
     17      appreciated but is not required.
     18   2. Altered source versions must be plainly marked as such, and must not be
     19      misrepresented as being the original software.
     20   3. This notice may not be removed or altered from any source distribution.
     21 */
     22 
     23 #include "../../SDL_internal.h"
     24 
     25 #if SDL_VIDEO_DRIVER_HAIKU
     26 
     27 #include "SDL_messagebox.h"
     28 
     29 /* For application signature. */
     30 #include "../../main/haiku/SDL_BeApp.h"
     31 
     32 #include <Alert.h>
     33 #include <Application.h>
     34 #include <Button.h>
     35 #include <Font.h>
     36 #include <Layout.h>
     37 #include <String.h>
     38 #include <TextView.h>
     39 #include <View.h>
     40 #include <Window.h>
     41 
     42 #include <InterfaceDefs.h>
     43 #include <SupportDefs.h>
     44 #include <GraphicsDefs.h>
     45 
     46 #include <new>
     47 #include <vector>
     48 #include <algorithm>
     49 
     50 enum
     51 {
     52 	G_CLOSE_BUTTON_ID   = -1,
     53 	G_DEFAULT_BUTTON_ID = 0,
     54 	G_MAX_STRING_LENGTH_BYTES = 120
     55 };
     56 
     57 class HAIKU_SDL_MessageBox : public BAlert
     58 {
     59 	float fComputedMessageBoxWidth;
     60 
     61 	BTextView *fMessageBoxTextView;
     62 
     63 	int fCloseButton;
     64 	int fDefaultButton;
     65 
     66 	bool fCustomColorScheme;
     67 	bool fThereIsLongLine;
     68 	rgb_color fTextColor;
     69 
     70 	const char *fTitle;
     71 	const char *HAIKU_SDL_DefTitle;
     72 	const char *HAIKU_SDL_DefMessage;
     73 	const char *HAIKU_SDL_DefButton;
     74 
     75 	std::vector<const SDL_MessageBoxButtonData *> fButtons;
     76 
     77 	static bool
     78 	SortButtonsPredicate(const SDL_MessageBoxButtonData *aButtonLeft,
     79 	                                 const SDL_MessageBoxButtonData *aButtonRight)
     80 	{
     81 		return aButtonLeft->buttonid < aButtonRight->buttonid;
     82 	}
     83 
     84 	alert_type
     85 	ConvertMessageBoxType(const SDL_MessageBoxFlags aWindowType) const
     86 	{
     87 		switch (aWindowType)
     88 		{
     89 			default:
     90 			case SDL_MESSAGEBOX_WARNING:
     91 			{
     92 				return B_WARNING_ALERT;
     93 			}
     94 			case SDL_MESSAGEBOX_ERROR:
     95 			{
     96 				return B_STOP_ALERT;
     97 			}
     98 			case SDL_MESSAGEBOX_INFORMATION:
     99 			{
    100 				return B_INFO_ALERT;
    101 			}
    102 		}
    103 	}
    104 
    105 	rgb_color
    106 	ConvertColorType(const SDL_MessageBoxColor *aColor) const
    107 	{
    108 		rgb_color color = { aColor->r, aColor->g, aColor->b, color.alpha = 255 };
    109 		return color;
    110 	}
    111 
    112 	int32
    113 	GetLeftPanelWidth(void) const
    114 	{
    115 		// See file "haiku/src/kits/interface/Alert.cpp" for this magic numbers.
    116 		//    IconStripeWidth = 30 * Scale
    117 		//    IconSize = 32 * Scale
    118 		//    Scale = max_c(1, ((int32)be_plain_font->Size() + 15) / 16)
    119 		//    RealWidth = (IconStripeWidth * Scale) + (IconSize * Scale)
    120 
    121 		int32 scale = max_c(1, ((int32)be_plain_font->Size() + 15) / 16);
    122 		return (30 * scale) + (32 * scale);
    123 	}
    124 
    125 	void
    126 	UpdateTextViewWidth(void)
    127 	{
    128 		fComputedMessageBoxWidth = fMessageBoxTextView->PreferredSize().Width() + GetLeftPanelWidth();
    129 	}
    130 
    131 	void
    132 	ParseSdlMessageBoxData(const SDL_MessageBoxData *aMessageBoxData)
    133 	{
    134 		if (aMessageBoxData == NULL)
    135 		{
    136 			SetTitle(HAIKU_SDL_DefTitle);
    137 			SetMessageText(HAIKU_SDL_DefMessage);
    138 			AddButton(HAIKU_SDL_DefButton);
    139 			return;
    140 		}
    141 
    142 		if (aMessageBoxData->numbuttons <= 0)
    143 		{
    144 			AddButton(HAIKU_SDL_DefButton);
    145 		}
    146 		else
    147 		{
    148 			AddSdlButtons(aMessageBoxData->buttons, aMessageBoxData->numbuttons);
    149 		}
    150 
    151 		if (aMessageBoxData->colorScheme != NULL)
    152 		{
    153 			fCustomColorScheme = true;
    154 			ApplyAndParseColorScheme(aMessageBoxData->colorScheme);
    155 		}
    156 
    157 		(aMessageBoxData->title[0]) ?
    158 			SetTitle(aMessageBoxData->title) : SetTitle(HAIKU_SDL_DefTitle);
    159 		(aMessageBoxData->message[0]) ?
    160 			SetMessageText(aMessageBoxData->message) : SetMessageText(HAIKU_SDL_DefMessage);
    161 
    162 		SetType(ConvertMessageBoxType(static_cast<SDL_MessageBoxFlags>(aMessageBoxData->flags)));
    163 	}
    164 
    165 	void
    166 	ApplyAndParseColorScheme(const SDL_MessageBoxColorScheme *aColorScheme)
    167 	{
    168 		SetBackgroundColor(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BACKGROUND]);
    169 		fTextColor = ConvertColorType(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT]);
    170 		SetButtonColors(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER],
    171 		                &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND],
    172 		                &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT],
    173 		                &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED]);
    174 	}
    175 
    176 	void
    177 	SetButtonColors(const SDL_MessageBoxColor *aBorderColor,
    178 	                const SDL_MessageBoxColor *aBackgroundColor,
    179 	                const SDL_MessageBoxColor *aTextColor,
    180 	                const SDL_MessageBoxColor *aSelectedColor)
    181 	{
    182 		if (fCustomColorScheme)
    183 		{
    184 			int32 countButtons = CountButtons();
    185 			for (int i = 0; i < countButtons; ++i)
    186 			{
    187 				ButtonAt(i)->SetViewColor(ConvertColorType(aBorderColor));
    188 				ButtonAt(i)->SetLowColor(ConvertColorType(aBackgroundColor));
    189 
    190 				// This doesn't work. See this why:
    191 				// https://github.com/haiku/haiku/commit/de9c53f8f5008c7b3b0af75d944a628e17f6dffe
    192 				// Let it remain.
    193 				ButtonAt(i)->SetHighColor(ConvertColorType(aTextColor));
    194 			}
    195 		}
    196 		// TODO: Not Implemented.
    197 		// Is it even necessary?!
    198 		(void)aSelectedColor;
    199 	}
    200 
    201 	void
    202 	SetBackgroundColor(const SDL_MessageBoxColor *aColor)
    203 	{
    204 		rgb_color background = ConvertColorType(aColor);
    205 
    206 		GetLayout()->View()->SetViewColor(background);
    207 		// See file "haiku/src/kits/interface/Alert.cpp", the "TAlertView" is the internal name of the left panel.
    208 		FindView("TAlertView")->SetViewColor(background);
    209 		fMessageBoxTextView->SetViewColor(background);
    210 	}
    211 
    212 	bool
    213 	CheckLongLines(const char *aMessage)
    214 	{
    215 		int final = 0;
    216 
    217 		// This UTF-8 friendly.
    218 		BString message = aMessage;
    219 		int32 length = message.CountChars();
    220 
    221 		for (int i = 0, c = 0; i < length; ++i)
    222 		{
    223 			c++;
    224 			if (*(message.CharAt(i)) == '\n')
    225 			{
    226 				c = 0;
    227 			}
    228 			if (c > final)
    229 			{
    230 				final = c;
    231 			}
    232 		}
    233 
    234 		return (final > G_MAX_STRING_LENGTH_BYTES);
    235 	}
    236 
    237 	void
    238 	SetMessageText(const char *aMessage)
    239 	{
    240 		fThereIsLongLine = CheckLongLines(aMessage);
    241 		if (fThereIsLongLine)
    242 		{
    243 			fMessageBoxTextView->SetWordWrap(true);
    244 		}
    245 
    246 		rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
    247 		if (fCustomColorScheme)
    248 		{
    249 			textColor = fTextColor;
    250 		}
    251 
    252 		/*
    253 		if (fNoTitledWindow)
    254 		{
    255 			fMessageBoxTextView->SetFontAndColor(be_bold_font);
    256 			fMessageBoxTextView->Insert(fTitle);
    257 			fMessageBoxTextView->Insert("\n\n");
    258 			fMessageBoxTextView->SetFontAndColor(be_plain_font);
    259 		}
    260 		*/
    261 
    262 		fMessageBoxTextView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
    263 		fMessageBoxTextView->Insert(aMessage);
    264 
    265 		// Be sure to call update width method.
    266 		UpdateTextViewWidth();
    267 	}
    268 
    269 	void
    270 	AddSdlButtons(const SDL_MessageBoxButtonData *aButtons, int aNumButtons)
    271 	{
    272 		for (int i = 0; i < aNumButtons; ++i)
    273 		{
    274 			fButtons.push_back(&aButtons[i]);
    275 		}
    276 
    277 		std::sort(fButtons.begin(), fButtons.end(), &HAIKU_SDL_MessageBox::SortButtonsPredicate);
    278 
    279 		size_t countButtons = fButtons.size();
    280 		for (size_t i = 0; i < countButtons; ++i)
    281 		{
    282 			switch (fButtons[i]->flags)
    283 			{
    284 				case SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT:
    285 				{
    286 					fCloseButton = static_cast<int>(i);
    287 					break;
    288 				}
    289 				case SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT:
    290 				{
    291 					fDefaultButton = static_cast<int>(i);
    292 					break;
    293 				}
    294 				default:
    295 				{
    296 					break;
    297 				}
    298 			}
    299 			AddButton(fButtons[i]->text);
    300 		}
    301 
    302 		SetDefaultButton(ButtonAt(fDefaultButton));
    303 	}
    304 
    305 public:
    306 	explicit
    307 	HAIKU_SDL_MessageBox(const SDL_MessageBoxData *aMessageBoxData)
    308 		: BAlert(NULL, NULL, NULL, NULL, NULL, B_WIDTH_FROM_LABEL, B_WARNING_ALERT),
    309 		  fComputedMessageBoxWidth(0.0f),
    310 		  fCloseButton(G_CLOSE_BUTTON_ID), fDefaultButton(G_DEFAULT_BUTTON_ID),
    311 		  fCustomColorScheme(false), fThereIsLongLine(false),
    312 		  HAIKU_SDL_DefTitle("SDL2 MessageBox"),
    313 		  HAIKU_SDL_DefMessage("Some information has been lost."),
    314 		  HAIKU_SDL_DefButton("OK")
    315 	{
    316 		// MessageBox settings.
    317 		// We need a title to display it.
    318 		SetLook(B_TITLED_WINDOW_LOOK);
    319 		SetFlags(Flags() | B_CLOSE_ON_ESCAPE);
    320 
    321 		// MessageBox TextView settings.
    322 		fMessageBoxTextView = TextView();
    323 		fMessageBoxTextView->SetWordWrap(false);
    324 		fMessageBoxTextView->SetStylable(true);
    325 
    326 		ParseSdlMessageBoxData(aMessageBoxData);
    327 	}
    328 
    329 	int
    330 	GetCloseButtonId(void) const
    331 	{
    332 		return fCloseButton;
    333 	}
    334 
    335 	virtual
    336 	~HAIKU_SDL_MessageBox(void)
    337 	{
    338 		fButtons.clear();
    339 	}
    340 
    341 protected:
    342 	virtual void
    343 	FrameResized(float aNewWidth, float aNewHeight)
    344 	{
    345 		if (fComputedMessageBoxWidth > aNewWidth)
    346 		{
    347 			ResizeTo(fComputedMessageBoxWidth, aNewHeight);
    348 		}
    349 		else
    350 		{
    351 			BAlert::FrameResized(aNewWidth, aNewHeight);
    352 		}
    353 	}
    354 
    355 	virtual void
    356 	SetTitle(const char* aTitle)
    357 	{
    358 		fTitle = aTitle;
    359 		BAlert::SetTitle(aTitle);
    360 	}
    361 };
    362 
    363 #ifdef __cplusplus
    364 extern "C" {
    365 #endif
    366 
    367 int
    368 HAIKU_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
    369 {
    370 	// Initialize button by closed or error value first.
    371 	*buttonid = G_CLOSE_BUTTON_ID;
    372 
    373 	// We need to check "be_app" pointer to "NULL". The "messageboxdata->window" pointer isn't appropriate here
    374 	// because it is possible to create a MessageBox from another thread. This fixes the following errors:
    375 	// "You need a valid BApplication object before interacting with the app_server."
    376 	// "2 BApplication objects were created. Only one is allowed."
    377 	BApplication *application = NULL;
    378 	if (be_app == NULL)
    379 	{
    380 		application = new(std::nothrow) BApplication(signature);
    381 		if (application == NULL)
    382 		{
    383 			return SDL_SetError("Cannot create the BApplication object. Lack of memory?");
    384 		}
    385 	}
    386 
    387 	HAIKU_SDL_MessageBox *SDL_MessageBox = new(std::nothrow) HAIKU_SDL_MessageBox(messageboxdata);
    388 	if (SDL_MessageBox == NULL)
    389 	{
    390 		return SDL_SetError("Cannot create the HAIKU_SDL_MessageBox (BAlert inheritor) object. Lack of memory?");
    391 	}
    392 	const int closeButton = SDL_MessageBox->GetCloseButtonId();
    393 	int pushedButton = SDL_MessageBox->Go();
    394 
    395 	// The close button is equivalent to pressing Escape.
    396 	if (closeButton != G_CLOSE_BUTTON_ID && pushedButton == G_CLOSE_BUTTON_ID)
    397 	{
    398 		pushedButton = closeButton;
    399 	}
    400 
    401 	// It's deleted by itself after the "Go()" method was executed.
    402 	/*
    403 	if (messageBox != NULL)
    404 	{
    405 		delete messageBox;
    406 	}
    407 	*/
    408 	if (application != NULL)
    409 	{
    410 		delete application;
    411 	}
    412 
    413 	// Initialize button by real pushed value then.
    414 	*buttonid = pushedButton;
    415 
    416 	return 0;
    417 }
    418 
    419 #ifdef __cplusplus
    420 }
    421 #endif
    422 
    423 #endif /* SDL_VIDEO_DRIVER_HAIKU */
    424 
    425 /* vi: set ts=4 sw=4 expandtab: */