You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

200 lines
6.0 KiB

#include "DiabloUI/dialogs.h"
#include <utility>
#include "DiabloUI/button.h"
#include "DiabloUI/diabloui.h"
#include "control.h"
#include "controls/input.h"
#include "controls/menu_controls.h"
#include "engine/clx_sprite.hpp"
#include "engine/dx.h"
#include "engine/load_clx.hpp"
#include "engine/load_pcx.hpp"
#include "engine/palette.h"
#include "hwcursor.hpp"
#include "utils/display.h"
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/stdcompat/string_view.hpp"
namespace devilution {
namespace {
OptionalOwnedClxSpriteList ownedDialogSprite;
std::string wrappedText;
bool dialogEnd;
void DialogActionOK()
{
dialogEnd = true;
}
std::vector<std::unique_ptr<UiItemBase>> vecNULL;
std::vector<std::unique_ptr<UiItemBase>> vecOkDialog;
OptionalClxSprite LoadDialogSprite(bool hasCaption, bool isError)
{
constexpr uint8_t TransparentColor = 255;
if (!hasCaption) {
ownedDialogSprite = LoadPcx(isError ? "ui_art\\srpopup" : "ui_art\\spopup", TransparentColor);
} else if (isError) {
ownedDialogSprite = LoadOptionalClx("ui_art\\dvl_lrpopup.clx");
if (!ownedDialogSprite) {
ownedDialogSprite = LoadPcx("ui_art\\lrpopup", TransparentColor);
}
} else {
ownedDialogSprite = LoadPcx("ui_art\\lpopup", TransparentColor);
}
if (!ownedDialogSprite)
return std::nullopt;
return (*ownedDialogSprite)[0];
}
bool Init(string_view caption, string_view text, bool error, bool renderBehind)
{
if (!renderBehind) {
if (!UiLoadBlackBackground()) {
if (SDL_ShowCursor(SDL_ENABLE) <= -1)
LogError("{}", SDL_GetError());
}
}
LoadDialogButtonGraphics();
OptionalClxSprite dialogSprite = LoadDialogSprite(!caption.empty(), error);
if (!dialogSprite)
return false;
const int dialogWidth = dialogSprite->width();
const int textWidth = dialogWidth - 40;
wrappedText = WordWrapString(text, textWidth, FontSizeDialog);
const Point uiPosition = GetUIRectangle().position;
if (caption.empty()) {
SDL_Rect rect1 = MakeSdlRect(uiPosition.x + 180, uiPosition.y + 168, dialogSprite->width(), dialogSprite->height());
vecOkDialog.push_back(std::make_unique<UiImageClx>(*dialogSprite, rect1));
SDL_Rect rect2 = MakeSdlRect(uiPosition.x + 200, uiPosition.y + 211, textWidth, 80);
vecOkDialog.push_back(std::make_unique<UiText>(wrappedText, rect2, UiFlags::AlignCenter | UiFlags::ColorDialogWhite));
SDL_Rect rect3 = MakeSdlRect(uiPosition.x + 265, uiPosition.y + 265, DialogButtonWidth, DialogButtonHeight);
vecOkDialog.push_back(std::make_unique<UiButton>(_("OK"), &DialogActionOK, rect3));
} else {
SDL_Rect rect1 = MakeSdlRect(uiPosition.x + 127, uiPosition.y + 100, dialogSprite->width(), dialogSprite->height());
vecOkDialog.push_back(std::make_unique<UiImageClx>(*dialogSprite, rect1));
SDL_Rect rect2 = MakeSdlRect(uiPosition.x + 147, uiPosition.y + 110, textWidth, 20);
vecOkDialog.push_back(std::make_unique<UiText>(caption, rect2, UiFlags::AlignCenter | UiFlags::ColorYellow));
SDL_Rect rect3 = MakeSdlRect(uiPosition.x + 147, uiPosition.y + 141, textWidth, 190);
vecOkDialog.push_back(std::make_unique<UiText>(wrappedText, rect3, UiFlags::AlignCenter | UiFlags::ColorDialogWhite));
SDL_Rect rect4 = MakeSdlRect(uiPosition.x + 264, uiPosition.y + 335, DialogButtonWidth, DialogButtonHeight);
vecOkDialog.push_back(std::make_unique<UiButton>(_("OK"), &DialogActionOK, rect4));
}
return true;
}
void Deinit()
{
ownedDialogSprite = std::nullopt;
vecOkDialog.clear();
FreeDialogButtonGraphics();
}
void DialogLoop(const std::vector<std::unique_ptr<UiItemBase>> &items, const std::vector<std::unique_ptr<UiItemBase>> &renderBehind)
{
SDL_Event event;
dialogEnd = false;
do {
while (PollEvent(&event) != 0) {
switch (event.type) {
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
UiItemMouseEvents(&event, items);
break;
default:
for (MenuAction menuAction : GetMenuActions(event)) {
if (IsNoneOf(menuAction, MenuAction_BACK, MenuAction_SELECT))
continue;
dialogEnd = true;
break;
}
break;
}
UiHandleEvents(&event);
}
UiClearScreen();
UiRenderItems(renderBehind);
UiRenderListItems();
UiRenderItems(items);
DrawMouse();
UiFadeIn();
} while (!dialogEnd);
}
void UiOkDialog(string_view caption, string_view text, bool error, const std::vector<std::unique_ptr<UiItemBase>> &renderBehind)
{
static bool inDialog = false;
if (!caption.empty()) {
LogError("{}\n{}", caption, text);
} else {
LogError("{}", text);
}
if (!gbActive || inDialog) {
if (!HeadlessMode) {
if (SDL_ShowCursor(SDL_ENABLE) <= -1)
LogError("{}", SDL_GetError());
std::string captionStr = std::string(caption);
std::string textStr = std::string(text);
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr) <= -1) {
LogError("{}", SDL_GetError());
}
}
return;
}
if (IsHardwareCursor()) {
if (SDL_ShowCursor(SDL_ENABLE) <= -1)
LogError("{}", SDL_GetError());
}
if (!Init(caption, text, error, !renderBehind.empty())) {
LogError("{}\n{}", caption, text);
std::string captionStr = std::string(caption);
std::string textStr = std::string(text);
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr) <= -1) {
LogError("{}", SDL_GetError());
}
}
inDialog = true;
SDL_SetClipRect(DiabloUiSurface(), nullptr);
DialogLoop(vecOkDialog, renderBehind);
Deinit();
inDialog = false;
}
} // namespace
void UiErrorOkDialog(string_view caption, string_view text, const std::vector<std::unique_ptr<UiItemBase>> &renderBehind)
{
UiOkDialog(caption, text, /*error=*/true, renderBehind);
}
void UiErrorOkDialog(string_view caption, string_view text, bool error)
{
UiOkDialog(caption, text, error, vecNULL);
}
void UiErrorOkDialog(string_view text, const std::vector<std::unique_ptr<UiItemBase>> &renderBehind)
{
UiErrorOkDialog({}, text, renderBehind);
}
} // namespace devilution