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.

157 lines
3.9 KiB

#include <SDL.h>
#include "DiabloUI/art_draw.h"
#include "DiabloUI/button.h"
#include "DiabloUI/diabloui.h"
#include "control.h"
#include "controls/input.h"
#include "controls/menu_controls.h"
#include "engine/dx.h"
#include "engine/load_pcx.hpp"
#include "engine/palette.h"
#include "engine/pcx_sprite.hpp"
#include "engine/render/pcx_render.hpp"
#include "hwcursor.hpp"
#include "utils/display.h"
#include "utils/language.h"
namespace devilution {
namespace {
std::optional<OwnedPcxSprite> ArtPopupSm;
std::optional<OwnedPcxSprite> ArtProgBG;
std::optional<OwnedPcxSprite> ProgFil;
std::vector<std::unique_ptr<UiItemBase>> vecProgress;
bool endMenu;
void DialogActionCancel()
{
endMenu = true;
}
void ProgressLoadBackground()
{
UiLoadBlackBackground();
ArtPopupSm = LoadPcxAsset("ui_art\\spopup.pcx");
ArtProgBG = LoadPcxAsset("ui_art\\prog_bg.pcx");
}
void ProgressLoadForeground()
{
LoadDialogButtonGraphics();
ProgFil = LoadPcxAsset("ui_art\\prog_fil.pcx");
const Point uiPosition = GetUIRectangle().position;
SDL_Rect rect3 = { (Sint16)(uiPosition.x + 265), (Sint16)(uiPosition.y + 267), DialogButtonWidth, DialogButtonHeight };
vecProgress.push_back(std::make_unique<UiButton>(_("Cancel"), &DialogActionCancel, rect3));
}
void ProgressFreeBackground()
{
ArtBackground = std::nullopt;
ArtPopupSm = std::nullopt;
ArtProgBG = std::nullopt;
}
void ProgressFreeForeground()
{
vecProgress.clear();
ProgFil = std::nullopt;
FreeDialogButtonGraphics();
}
Point GetPosition()
{
return { GetCenterOffset(280), GetCenterOffset(144, gnScreenHeight) };
}
void ProgressRenderBackground()
{
SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000);
const Surface &out = Surface(DiabloUiSurface());
const Point position = GetPosition();
RenderPcxSprite(out.subregion(position.x, position.y, 280, 140), PcxSprite { *ArtPopupSm }, { 0, 0 });
RenderPcxSprite(out.subregion(GetCenterOffset(227), 0, 227, out.h()), PcxSprite { *ArtProgBG }, { 0, position.y + 52 });
}
void ProgressRenderForeground(int progress)
{
const Surface &out = Surface(DiabloUiSurface());
const Point position = GetPosition();
if (progress != 0) {
const int x = GetCenterOffset(227);
const int w = 227 * progress / 100;
RenderPcxSprite(out.subregion(x, 0, w, out.h()), PcxSprite { *ProgFil }, { 0, position.y + 52 });
}
// Not rendering an actual button, only the top 2 rows of its graphics.
RenderPcxSprite(
out.subregion(GetCenterOffset(110), position.y + 99, DialogButtonWidth, 2),
ButtonSprite(/*pressed=*/false), { 0, 0 });
}
} // namespace
bool UiProgressDialog(int (*fnfunc)())
{
SetFadeLevel(256);
// Blit the background once and then free it.
ProgressLoadBackground();
ProgressRenderBackground();
if (RenderDirectlyToOutputSurface && IsDoubleBuffered()) {
// Blit twice for triple buffering.
for (unsigned i = 0; i < 2; ++i) {
UiFadeIn();
ProgressRenderBackground();
}
}
ProgressFreeBackground();
ProgressLoadForeground();
endMenu = false;
int progress = 0;
SDL_Event event;
while (!endMenu && progress < 100) {
progress = fnfunc();
ProgressRenderForeground(progress);
UiRenderItems(vecProgress);
DrawMouse();
UiFadeIn();
while (PollEvent(&event) != 0) {
switch (event.type) {
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
UiItemMouseEvents(&event, vecProgress);
break;
#ifndef USE_SDL1
case SDLK_KP_ENTER:
#endif
case SDLK_ESCAPE:
case SDLK_RETURN:
case SDLK_SPACE:
endMenu = true;
break;
default:
switch (GetMenuAction(event)) {
case MenuAction_BACK:
case MenuAction_SELECT:
endMenu = true;
break;
default:
break;
}
break;
}
UiHandleEvents(&event);
}
}
ProgressFreeForeground();
return progress == 100;
}
} // namespace devilution