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
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::ColorDialogYellow)); |
|
|
|
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
|
|
|