Browse Source

DiabloUI: Refactor UI_Item to tagged unions

Makes the code easier to understand.
Also makes building lists easier.

Also fixes focus indicator in SELLOAD_DIALOG (this type of bug is
impossible with the new structs).
pull/300/head
Gleb Mazovetskiy 7 years ago committed by Anders Jenbo
parent
commit
37936c6d15
  1. 3
      .editorconfig
  2. 1
      CMakeLists.txt
  3. 1
      SourceX/.clang-format
  4. 43
      SourceX/DiabloUI/art.cpp
  5. 32
      SourceX/DiabloUI/art.h
  6. 315
      SourceX/DiabloUI/diabloui.cpp
  7. 72
      SourceX/DiabloUI/diabloui.h
  8. 56
      SourceX/DiabloUI/dialogs.cpp
  9. 21
      SourceX/DiabloUI/mainmenu.cpp
  10. 43
      SourceX/DiabloUI/selconn.cpp
  11. 109
      SourceX/DiabloUI/selgame.cpp
  12. 107
      SourceX/DiabloUI/selhero.cpp
  13. 19
      SourceX/DiabloUI/selyesno.cpp
  14. 6
      SourceX/DiabloUI/title.cpp
  15. 202
      SourceX/DiabloUI/ui_item.h

3
.editorconfig

@ -13,3 +13,6 @@ end_of_line = lf
[*.sh]
end_of_line = lf
[.clang-format]
end_of_line = lf

1
CMakeLists.txt

@ -197,6 +197,7 @@ add_executable(devilutionx MACOSX_BUNDLE
SourceX/dvlnet/tcp_client.cpp
SourceX/dvlnet/tcp_server.cpp
SourceX/dvlnet/udp_p2p.cpp
SourceX/DiabloUI/art.cpp
SourceX/DiabloUI/credits.cpp
SourceX/DiabloUI/diabloui.cpp
SourceX/DiabloUI/dialogs.cpp

1
SourceX/.clang-format

@ -7,4 +7,5 @@
TabWidth: 4,
UseTab: ForIndentation,
SortIncludes: false,
NamespaceIndentation: None,
}

43
SourceX/DiabloUI/art.cpp

@ -0,0 +1,43 @@
#include "DiabloUI/art.h"
namespace dvl {
void LoadArt(char *pszFile, Art *art, int frames, PALETTEENTRY *pPalette)
{
if (art == NULL || art->surface != NULL)
return;
DWORD width, height, bpp;
if (!SBmpLoadImage(pszFile, 0, 0, 0, &width, &height, &bpp))
return;
Uint32 format;
switch (bpp) {
case 8:
format = SDL_PIXELFORMAT_INDEX8;
break;
case 24:
format = SDL_PIXELFORMAT_RGB888;
break;
case 32:
format = SDL_PIXELFORMAT_RGBA8888;
break;
default:
format = 0;
break;
}
SDL_Surface *art_surface = SDL_CreateRGBSurfaceWithFormat(SDL_SWSURFACE, width, height, bpp, format);
if (!SBmpLoadImage(pszFile, pPalette, static_cast<BYTE *>(art_surface->pixels),
art_surface->pitch * art_surface->format->BytesPerPixel * height, 0, 0, 0)) {
SDL_Log("Failed to load image");
SDL_FreeSurface(art_surface);
return;
}
art->surface = art_surface;
art->frames = frames;
art->frame_height = height / frames;
}
} // namespace dvl

32
SourceX/DiabloUI/art.h

@ -0,0 +1,32 @@
#pragma once
#include "devilution.h"
namespace dvl {
struct Art {
SDL_Surface *surface = NULL;
int frames = 1;
int frame_height = 0;
unsigned int palette_version = 0;
int w() const
{
return surface->w;
}
int h() const
{
return frame_height;
}
void Unload()
{
SDL_FreeSurface(surface);
surface = NULL;
}
};
void LoadArt(char *pszFile, Art *art, int frames = 1, PALETTEENTRY *pPalette = NULL);
}

315
SourceX/DiabloUI/diabloui.cpp

@ -9,7 +9,7 @@
namespace dvl {
TTF_Font *font;
TTF_Font *font = nullptr;
int SelectedItemMin = 1;
int SelectedItemMax = 1;
BYTE *FontTables[4];
@ -25,7 +25,7 @@ void (*gfnListFocus)(int value);
void (*gfnListSelect)(int value);
void (*gfnListEsc)();
bool (*gfnListYesNo)();
UI_Item *gUiItems;
UiItem *gUiItems;
int gUiItemCnt;
bool UiItemsWraps;
char *UiTextInput;
@ -140,7 +140,7 @@ void UiDestroy()
font = NULL;
}
void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), UI_Item *items, int itemCnt, bool itemsWraps, bool (*fnYesNo)())
void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), UiItem *items, int itemCnt, bool itemsWraps, bool (*fnYesNo)())
{
SelectedItem = min;
SelectedItemMin = min;
@ -159,8 +159,8 @@ void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(i
for (int i = 0; i < itemCnt; i++) {
if (items[i].type == UI_EDIT) {
SDL_StartTextInput();
UiTextInput = items[i].caption;
UiTextInputLen = items[i].value;
UiTextInput = items[i].edit.value;
UiTextInputLen = items[i].edit.max_length;
}
}
}
@ -367,48 +367,10 @@ void UiFocusNavigationYesNo()
UiPlaySelectSound();
}
bool IsInsideRect(const SDL_Event *event, const SDL_Rect *rect)
bool IsInsideRect(const SDL_Event &event, const SDL_Rect &rect)
{
const SDL_Point point = { event->button.x, event->button.y };
return SDL_PointInRect(&point, rect);
}
void LoadArt(char *pszFile, Art *art, int frames, PALETTEENTRY *pPalette)
{
if (art == NULL || art->surface != NULL)
return;
DWORD width, height, bpp;
if (!SBmpLoadImage(pszFile, 0, 0, 0, &width, &height, &bpp))
return;
Uint32 format;
switch (bpp) {
case 8:
format = SDL_PIXELFORMAT_INDEX8;
break;
case 24:
format = SDL_PIXELFORMAT_RGB888;
break;
case 32:
format = SDL_PIXELFORMAT_RGBA8888;
break;
default:
format = 0;
break;
}
SDL_Surface *art_surface = SDL_CreateRGBSurfaceWithFormat(SDL_SWSURFACE, width, height, bpp, format);
if (!SBmpLoadImage(pszFile, pPalette, static_cast<BYTE *>(art_surface->pixels),
art_surface->pitch * art_surface->format->BytesPerPixel * height, 0, 0, 0)) {
SDL_Log("Failed to load image");
SDL_FreeSurface(art_surface);
return;
}
art->surface = art_surface;
art->frames = frames;
art->frame_height = height / frames;
const SDL_Point point = { event.button.x, event.button.y };
return SDL_PointInRect(&point, &rect);
}
void LoadMaskedArtFont(char *pszFile, Art *art, int frames, int mask)
@ -604,10 +566,19 @@ void DrawArt(int screenX, int screenY, Art *art, int nFrame, DWORD drawW)
if (screenY >= SCREEN_Y + SCREEN_HEIGHT || screenX >= SCREEN_X + SCREEN_WIDTH)
return;
SDL_Rect src_rect = { 0, nFrame * art->h(), art->w(), art->h() };
SDL_Rect src_rect = {
0,
static_cast<decltype(SDL_Rect().y)>(nFrame * art->h()),
static_cast<decltype(SDL_Rect().w)>(art->w()),
static_cast<decltype(SDL_Rect().h)>(art->h())
};
if (drawW && static_cast<int>(drawW) < src_rect.w)
src_rect.w = drawW;
SDL_Rect dst_rect = { screenX + SCREEN_X, screenY + SCREEN_Y, src_rect.w, src_rect.h };
SDL_Rect dst_rect = {
static_cast<decltype(SDL_Rect().x)>(screenX + SCREEN_X),
static_cast<decltype(SDL_Rect().y)>(screenY + SCREEN_Y),
src_rect.w, src_rect.h
};
if (art->surface->format->BitsPerPixel == 8 && art->palette_version != pal_surface_palette_version) {
#ifdef USE_SDL1
@ -634,11 +605,11 @@ int GetCenterOffset(int w, int bw)
return (bw - w) / 2;
}
int GetStrWidth(char *str, int size)
int GetStrWidth(const char *str, int size)
{
int strWidth = 0;
for (size_t i = 0; i < strlen((char *)str); i++) {
for (size_t i = 0, n = strlen(str); i < n; i++) {
BYTE w = FontTables[size][*(BYTE *)&str[i] + 2];
if (w)
strWidth += w;
@ -649,43 +620,43 @@ int GetStrWidth(char *str, int size)
return strWidth;
}
int TextAlignment(UI_Item *item, TXT_JUST align, _artFontTables size)
int TextAlignment(const char *text, int rect_w, TXT_JUST align, _artFontTables size)
{
if (align != JustLeft) {
int w = GetStrWidth(item->caption, size);
int w = GetStrWidth(text, size);
if (align == JustCentre) {
return GetCenterOffset(w, item->rect.w);
return GetCenterOffset(w, rect_w);
} else if (align == JustRight) {
return item->rect.w - w;
return rect_w - w;
}
}
return 0;
}
void WordWrap(UI_Item *item)
void WordWrap(UiText *item)
{
int lineStart = 0;
int len = strlen((char *)item->caption);
int len = strlen((char *)item->text);
for (int i = 0; i <= len; i++) {
if (item->caption[i] == '\n') {
if (item->text[i] == '\n') {
lineStart = i + 1;
continue;
} else if (item->caption[i] != ' ' && i != len) {
} else if (item->text[i] != ' ' && i != len) {
continue;
}
if (i != len)
item->caption[i] = '\0';
if (GetStrWidth(&item->caption[lineStart], AFT_SMALL) <= item->rect.w) {
item->text[i] = '\0';
if (GetStrWidth(&item->text[lineStart], AFT_SMALL) <= item->rect.w) {
if (i != len)
item->caption[i] = ' ';
item->text[i] = ' ';
continue;
}
int j;
for (j = i; j >= lineStart; j--) {
if (item->caption[j] == ' ') {
if (item->text[j] == ' ') {
break; // Scan for previous space
}
}
@ -697,49 +668,48 @@ void WordWrap(UI_Item *item)
}
if (i != len)
item->caption[i] = ' ';
item->caption[j] = '\n';
item->text[i] = ' ';
item->text[j] = '\n';
lineStart = j + 1;
}
};
void DrawArtStr(UI_Item *item)
void DrawArtStr(const char *text, const SDL_Rect &rect, int flags, bool drawTextCursor = false)
{
_artFontTables size = AFT_SMALL;
_artFontColors color = item->flags & UIS_GOLD ? AFC_GOLD : AFC_SILVER;
_artFontColors color = flags & UIS_GOLD ? AFC_GOLD : AFC_SILVER;
TXT_JUST align = JustLeft;
if (item->flags & UIS_MED)
if (flags & UIS_MED)
size = AFT_MED;
else if (item->flags & UIS_BIG)
else if (flags & UIS_BIG)
size = AFT_BIG;
else if (item->flags & UIS_HUGE)
else if (flags & UIS_HUGE)
size = AFT_HUGE;
if (item->flags & UIS_CENTER)
if (flags & UIS_CENTER)
align = JustCentre;
else if (item->flags & UIS_RIGHT)
else if (flags & UIS_RIGHT)
align = JustRight;
int x = item->rect.x + TextAlignment(item, align, size);
int x = rect.x + TextAlignment(text, rect.w, align, size);
int sx = x;
int sy = item->rect.y;
if (item->flags & UIS_VCENTER)
sy += (item->rect.h - ArtFonts[size][color].h()) / 2;
int sy = rect.y;
if (flags & UIS_VCENTER)
sy += (rect.h - ArtFonts[size][color].h()) / 2;
for (size_t i = 0; i < strlen((char *)item->caption); i++) {
if (item->caption[i] == '\n') {
for (size_t i = 0, n = strlen(text); i < n; i++) {
if (text[i] == '\n') {
sx = x;
sy += ArtFonts[size][color].h();
continue;
}
BYTE w = FontTables[size][*(BYTE *)&item->caption[i] + 2] ? FontTables[size][*(BYTE *)&item->caption[i] + 2] : FontTables[size][0];
DrawArt(sx, sy, &ArtFonts[size][color], *(BYTE *)&item->caption[i], w);
BYTE w = FontTables[size][*(BYTE *)&text[i] + 2] ? FontTables[size][*(BYTE *)&text[i] + 2] : FontTables[size][0];
DrawArt(sx, sy, &ArtFonts[size][color], *(BYTE *)&text[i], w);
sx += w;
}
if (item->type == UI_EDIT && GetAnimationFrame(2, 500)) {
if (drawTextCursor && GetAnimationFrame(2, 500)) {
DrawArt(sx, sy, &ArtFonts[size][color], '|');
}
}
@ -783,38 +753,20 @@ void UiFadeIn(int steps)
SetFadeLevel(fadeValue);
}
void UiRenderItemDebug(UI_Item item)
{
item.rect.x += 64; // pal_surface is shifted?
item.rect.y += SCREEN_Y;
if (SDL_FillRect(pal_surface, &item.rect, random(0, 255)) <= -1) {
SDL_Log(SDL_GetError());
}
}
void DrawSelector(UI_Item *item = 0)
void DrawSelector(const SDL_Rect &rect)
{
int size = FOCUS_SMALL;
if (item->rect.h >= 42)
if (rect.h >= 42)
size = FOCUS_BIG;
else if (item->rect.h >= 30)
else if (rect.h >= 30)
size = FOCUS_MED;
Art *art = &ArtFocus[size];
int frame = GetAnimationFrame(art->frames);
int y = item->rect.y + (item->rect.h - art->h()) / 2; // TODO FOCUS_MED appares higher then the box
int y = rect.y + (rect.h - art->h()) / 2; // TODO FOCUS_MED appares higher then the box
DrawArt(item->rect.x, y, art, frame);
DrawArt(item->rect.x + item->rect.w - art->w(), y, art, frame);
}
void DrawEditBox(UI_Item item)
{
DrawSelector(&item);
item.rect.x += 43;
item.rect.y += 1;
item.rect.w -= 86;
DrawArtStr(&item);
DrawArt(rect.x, y, art, frame);
DrawArt(rect.x + rect.w - art->w(), y, art, frame);
}
void UiRender()
@ -829,73 +781,120 @@ void UiRender()
UiFadeIn();
}
void UiRenderItems(UI_Item *items, int size)
namespace {
void Render(const UiText &ui_text)
{
for (int i = 0; i < size; i++) {
if (items[i].flags & UIS_HIDDEN)
continue;
DrawArtStr(ui_text.text, ui_text.rect, ui_text.flags);
}
switch (items[i].type) {
case UI_EDIT:
DrawEditBox(items[i]);
break;
case UI_LIST:
if (items[i].caption == NULL)
continue;
if (SelectedItem == items[i].value)
DrawSelector(&items[i]);
DrawArtStr(&items[i]);
break;
case UI_BUTTON:
case UI_TEXT:
DrawArtStr(&items[i]);
break;
case UI_IMAGE:
DrawArt(items[i].rect.x, items[i].rect.y, (Art *)items[i].context, items[i].value, items[i].rect.w);
break;
default:
UiRenderItemDebug(items[i]);
break;
}
}
void Render(const UiImage &ui_image)
{
DrawArt(ui_image.rect.x, ui_image.rect.y, ui_image.art, ui_image.frame, ui_image.rect.w);
}
bool UiItemMouseEvents(SDL_Event *event, UI_Item *items, int size)
void Render(const UiButton &ui_button)
{
if (event->type != SDL_MOUSEBUTTONDOWN || event->button.button != SDL_BUTTON_LEFT) {
return false;
DrawArtStr(ui_button.text, ui_button.rect, ui_button.flags);
}
void Render(const UiList &ui_list)
{
for (std::size_t i = 0; i < ui_list.length; ++i) {
SDL_Rect rect = ui_list.itemRect(i);
const auto &item = ui_list.items[i];
if (item.value == SelectedItem)
DrawSelector(rect);
DrawArtStr(item.text, rect, ui_list.flags);
}
}
for (int i = 0; i < size; i++) {
if (!IsInsideRect(event, &items[i].rect)) {
continue;
}
void Render(const UiEdit &ui_edit)
{
DrawSelector(ui_edit.rect);
SDL_Rect rect = ui_edit.rect;
rect.x += 43;
rect.y += 1;
rect.w -= 86;
DrawArtStr(ui_edit.value, rect, ui_edit.flags, /*drawTextCursor=*/true);
}
if (items[i].type != UI_BUTTON && items[i].type != UI_LIST) {
continue;
}
void RenderItem(const UiItem &item)
{
if (item.flags() & UIS_HIDDEN)
return;
switch (item.type) {
case UI_TEXT:
Render(item.text);
break;
case UI_IMAGE:
Render(item.image);
break;
case UI_BUTTON:
Render(item.button);
break;
case UI_LIST:
Render(item.list);
break;
case UI_EDIT:
Render(item.edit);
break;
}
}
if (items[i].type == UI_LIST) {
if (items[i].caption != NULL && *items[i].caption != '\0') {
if (gfnListFocus != NULL && SelectedItem != items[i].value) {
UiFocus(items[i].value);
bool HandleMouseEventButton(const SDL_Event &event, const UiButton &ui_button)
{
ui_button.action();
return true;
}
bool HandleMouseEventList(const SDL_Event &event, const UiList &ui_list)
{
const UiListItem *list_item = ui_list.itemAt(event.button.y);
if (gfnListFocus != NULL && SelectedItem != list_item->value) {
UiFocus(list_item->value);
#ifdef USE_SDL1
} else if (gfnListFocus == NULL) {
} else if (gfnListFocus == NULL) {
#else
} else if (gfnListFocus == NULL || event->button.clicks >= 2) {
} else if (gfnListFocus == NULL || event.button.clicks >= 2) {
#endif
SelectedItem = items[i].value;
UiFocusNavigationSelect();
}
}
SelectedItem = list_item->value;
UiFocusNavigationSelect();
}
return true;
}
return true;
}
bool HandleMouseEvent(const SDL_Event &event, const UiItem &item)
{
if (!IsInsideRect(event, item.rect()))
return false;
switch (item.type) {
case UI_BUTTON:
return HandleMouseEventButton(event, item.button);
case UI_LIST:
return HandleMouseEventList(event, item.list);
default:
return false;
}
}
if (items[i].context) {
((void (*)(int value))items[i].context)(items[i].value);
}
return true;
} // namespace
void UiRenderItems(UiItem *items, int size)
{
for (int i = 0; i < size; i++)
RenderItem(items[i]);
}
bool UiItemMouseEvents(SDL_Event *event, UiItem *items, int size)
{
if (event->type != SDL_MOUSEBUTTONDOWN || event->button.button != SDL_BUTTON_LEFT) {
return false;
}
for (int i = 0; i < size; i++) {
if (HandleMouseEvent(*event, items[i]))
return true;
}
return false;

72
SourceX/DiabloUI/diabloui.h

@ -1,8 +1,12 @@
#pragma once
#include <cstddef>
#include <SDL.h>
#include <SDL_ttf.h>
#include "art.h"
#include "ui_item.h"
namespace dvl {
typedef enum _artFocus {
@ -29,63 +33,6 @@ typedef enum _artFontColors {
AFC_GOLD,
} _artFontColors;
typedef enum UiTypes {
UI_TEXT,
UI_IMAGE,
UI_BUTTON,
UI_LIST,
UI_EDIT,
} UiTypes;
typedef enum UiFlags {
UIS_SMALL = 1 << 0,
UIS_MED = 1 << 1,
UIS_BIG = 1 << 2,
UIS_HUGE = 1 << 3,
UIS_CENTER = 1 << 4,
UIS_RIGHT = 1 << 5,
UIS_VCENTER = 1 << 6,
UIS_SILVER = 1 << 7,
UIS_GOLD = 1 << 8,
UIS_SML1 = 1 << 9,
UIS_SML2 = 1 << 10,
UIS_LIST = 1 << 11,
UIS_DISABLED = 1 << 12,
UIS_HIDDEN = 1 << 13,
} UiFlags;
struct Art {
SDL_Surface *surface = NULL;
int frames = 1;
int frame_height = 0;
unsigned int palette_version = 0;
int w() const
{
return surface->w;
}
int h() const
{
return frame_height;
}
void Unload()
{
SDL_FreeSurface(surface);
surface = NULL;
}
};
typedef struct UI_Item {
SDL_Rect rect;
UiTypes type;
int flags;
int value;
char *caption;
const void *context;
} UI_Item;
extern TTF_Font *font;
extern BYTE *FontTables[4];
@ -110,26 +57,25 @@ constexpr size_t size(T (&)[N])
extern void (*gfnSoundFunction)(char *file);
bool IsInsideRect(const SDL_Event *event, const SDL_Rect *rect);
bool IsInsideRect(const SDL_Event &event, const SDL_Rect &rect);
void UiFadeIn(int steps = 16);
bool UiFocusNavigation(SDL_Event *event);
bool UiItemMouseEvents(SDL_Event *event, UI_Item *items, int size);
bool UiItemMouseEvents(SDL_Event *event, UiItem *items, int size);
int GetAnimationFrame(int frames, int fps = 60);
int GetCenterOffset(int w, int bw = 0);
void DrawArt(int screenX, int screenY, Art *art, int nFrame = 0, DWORD drawW = 0);
void DrawLogo(int t = 0, int size = LOGO_MED);
void DrawMouse();
void LoadArt(char *pszFile, Art *art, int frames = 1, PALETTEENTRY *pPalette = NULL);
void LoadBackgroundArt(char *pszFile);
void LoadMaskedArtFont(char *pszFile, Art *art, int frames, int mask = 250);
void SetMenu(int MenuId);
void UiFocusNavigationSelect();
void UiFocusNavigationEsc();
void UiFocusNavigationYesNo();
void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), UI_Item *items, int size, bool wraps = false, bool (*fnYesNo)() = NULL);
void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), UiItem *items, int size, bool wraps = false, bool (*fnYesNo)() = NULL);
void UiRender();
void UiRenderItems(UI_Item *items, int size);
void WordWrap(UI_Item *item);
void UiRenderItems(UiItem *items, int size);
void WordWrap(UiText *item);
void DvlIntSetting(const char *valuename, int *value);
void DvlStringSetting(const char *valuename, char *string, int len);

56
SourceX/DiabloUI/dialogs.cpp

@ -3,34 +3,50 @@
namespace dvl {
UI_Item OKCANCEL_DIALOG[] = {
{ { 180, 168, 280, 144 }, UI_IMAGE, 0, 0, "ui_art\\spopup.pcx" },
{ { 200, 180, 240, 80 }, UI_TEXT, UIS_CENTER }, // message
{ { 200, 265, 110, 28 }, UI_BUTTON, UIS_SML1, 0, "OK" },
{ { 330, 265, 110, 28 }, UI_BUTTON, UIS_SML2, 0, "Cancel" },
Art dialogArt; // "ui_art\\spopup.pcx"
char dialogMessage[256];
Art progressArt; // "ui_art\\prog_bg.pcx"
void DialogActionOK()
{
}
void DialogActionCancel()
{
}
UiItem OKCANCEL_DIALOG[] = {
UiImage(&dialogArt, { 180, 168, 280, 144 }),
UiText(dialogMessage, { 200, 180, 240, 80 }, UIS_CENTER),
UiButton("OK", &DialogActionOK, { 200, 265, 110, 28 }, UIS_SML1),
UiButton("Cancel", &DialogActionCancel, { 330, 265, 110, 28 }, UIS_SML2),
};
UI_Item OK_DIALOG[] = {
{ { 180, 168, 280, 144 }, UI_IMAGE, 0, 0, "ui_art\\spopup.pcx" },
{ { 200, 180, 240, 80 }, UI_TEXT, UIS_CENTER }, // message
{ { 265, 265, 110, 28 }, UI_BUTTON, UIS_SML1, 0, "OK" },
UiItem OK_DIALOG[] = {
UiImage(&dialogArt, { 180, 168, 280, 144 }),
UiText(dialogMessage, { 200, 180, 240, 80 }, UIS_CENTER),
UiButton("OK", &DialogActionOK, { 200, 265, 110, 28 }, UIS_SML1),
};
UI_Item PROGRESS_DIALOG[] = {
{ { 180, 168, 280, 144 }, UI_IMAGE, 0, 0, "ui_art\\spopup.pcx" },
{ { 180, 177, 280, 43 }, UI_TEXT, UIS_CENTER }, // Message
{ { 205, 220, 228, 38 }, UI_IMAGE, 0, 0, "ui_art\\prog_bg.pcx" },
{ { 265, 267, 110, 28 }, UI_BUTTON, UIS_SML1, 0, "Cancel" },
UiItem PROGRESS_DIALOG[] = {
UiImage(&dialogArt, { 180, 168, 280, 144 }),
UiText(dialogMessage, { 180, 177, 280, 43 }, UIS_CENTER),
UiImage(&progressArt, { 205, 220, 228, 38 }),
UiButton("Cancel", &DialogActionCancel, { 265, 267, 110, 28 }, UIS_SML1),
};
UI_Item SELOK_DIALOG[] = {
{ { 140, 210, 400, 168 } }, // Message
{ { 230, 390, 180, 35 }, UI_LIST, UIS_CENTER, 0, "OK" },
UiListItem SELOK_DIALOG_ITEMS[] = {
{ "OK", 0 }
};
UiItem SELOK_DIALOG[] = {
UiText(dialogMessage, { 140, 210, 400, 168 }, UIS_CENTER),
UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER),
};
UI_Item SPAWNERR_DIALOG[] = {
{ { 140, 199, 400, 177 }, UI_TEXT, 0, 0, "The Rogue and Sorcerer are only available in the full retail version of Diablo. For ordering information call (800) 953-SNOW." },
{ { 230, 407, 180, 43 }, UI_BUTTON, 0, 0, "OK" },
UiItem SPAWNERR_DIALOG[] = {
UiText("The Rogue and Sorcerer are only available in the full retail version of Diablo. For ordering information call (800) 953-SNOW.", { 140, 199, 400, 177 }),
UiButton("OK", &DialogActionOK, { 230, 407, 180, 43 }),
};
}

21
SourceX/DiabloUI/mainmenu.cpp

@ -7,14 +7,17 @@ int mainmenu_attract_time_out; //seconds
DWORD dwAttractTicks;
int MainMenuResult;
UI_Item MAINMENU_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 64, 192, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_SINGLE_PLAYER, "Single Player" },
{ { 64, 235, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_MULTIPLAYER, "Multi Player" },
{ { 64, 277, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_REPLAY_INTRO, "Replay Intro" },
{ { 64, 320, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_SHOW_CREDITS, "Show Credits" },
{ { 64, 363, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_EXIT_DIABLO, "Exit Diablo" },
{ { 17, 444, 605, 21 }, UI_TEXT, UIS_SMALL },
UiListItem MAINMENU_DIALOG_ITEMS[] = {
{"Single Player", MAINMENU_SINGLE_PLAYER},
{"Multi Player", MAINMENU_MULTIPLAYER},
{"Replay Intro", MAINMENU_REPLAY_INTRO},
{"Show Credits", MAINMENU_SHOW_CREDITS},
{"Exit Diablo", MAINMENU_EXIT_DIABLO}
};
UiItem MAINMENU_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiList(MAINMENU_DIALOG_ITEMS, 64, 192, 510, 43, UIS_HUGE | UIS_GOLD | UIS_CENTER),
UiText(nullptr, { 17, 444, 605, 21 }, UIS_SMALL)
};
void UiMainMenuSelect(int value)
@ -35,7 +38,7 @@ void mainmenu_restart_repintro()
void mainmenu_Load(char *name, void (*fnSound)(char *file))
{
gfnSoundFunction = fnSound;
MAINMENU_DIALOG[6].caption = name;
MAINMENU_DIALOG[size(MAINMENU_DIALOG) - 1].text.text = name;
MainMenuResult = 0;

43
SourceX/DiabloUI/selconn.cpp

@ -17,24 +17,25 @@ _SNETVERSIONDATA *selconn_FileInfo;
DWORD provider;
UI_Item SELCONNECT_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Multi Player Game" },
{ { 35, 218, 205, 21 }, UI_TEXT, 0, 0, selconn_MaxPlayers }, // Max players
{ { 35, 256, 205, 21 }, UI_TEXT, 0, 0, "Requirements:" },
{ { 35, 275, 205, 66 }, UI_TEXT, 0, 0, selconn_Description }, //Description
{ { 30, 356, 220, 31 }, UI_TEXT, UIS_CENTER | UIS_MED, 0, "no gateway needed" },
{ { 35, 393, 205, 21 }, UI_TEXT, UIS_CENTER, 0, selconn_Gateway }, // Gateway
{ { 16, 427, 250, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD | UIS_HIDDEN, 0, "Change Gateway" },
{ { 300, 211, 295, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Connection" },
{ { 305, 256, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD, 0, "Client-Server (TCP)" },
{ { 305, 282, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD, 1, "Peer-to-Peer (UDP)" },
{ { 305, 308, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD, 2, "Loopback" },
{ { 305, 334, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD },
{ { 305, 360, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD },
{ { 305, 386, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD },
{ { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 454, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiText SELCONNECT_DIALOG_DESCRIPTION(selconn_Description, { 35, 275, 205, 66 });
UiListItem SELCONN_DIALOG_ITEMS[] = {
{ "Client-Server (TCP)", 0 },
{ "Peer-to-Peer (UDP)", 1 },
{ "Loopback", 2 },
};
UiItem SELCONNECT_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText("Multi Player Game", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiText(selconn_MaxPlayers, { 35, 218, 205, 21 }),
UiText("Requirements:", { 35, 256, 205, 21 }),
SELCONNECT_DIALOG_DESCRIPTION,
UiText("no gateway needed", { 30, 356, 220, 31 }, UIS_CENTER | UIS_MED),
UiText(selconn_Gateway, { 35, 393, 205, 21 }, UIS_CENTER),
UiText("Select Connection", { 300, 211, 295, 33 }, UIS_CENTER | UIS_BIG),
UiButton("Change Gateway", nullptr, { 16, 427, 250, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD | UIS_HIDDEN),
UiList(SELCONN_DIALOG_ITEMS, 305, 256, 285, 26, UIS_CENTER | UIS_VCENTER | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD),
UiButton("Cancel", &UiFocusNavigationEsc, { 454, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)
};
void selconn_Load()
@ -73,11 +74,7 @@ void selconn_Focus(int value)
}
sprintf(selconn_MaxPlayers, "Players Supported: %d", players);
for (auto &item : SELCONNECT_DIALOG) {
if (item.caption != NULL && !(item.flags & (UIS_VCENTER | UIS_CENTER)))
WordWrap(&item);
}
WordWrap(&SELCONNECT_DIALOG_DESCRIPTION);
}
void selconn_Select(int value)

109
SourceX/DiabloUI/selgame.cpp

@ -5,7 +5,7 @@
namespace dvl {
char selgame_Lable[32];
char selgame_Label[32];
char selgame_Ip[129] = "";
char selgame_Password[16] = "";
char selgame_Description[256];
@ -18,55 +18,58 @@ int gbDifficulty;
static _SNETPROGRAMDATA *m_client_info;
extern DWORD provider;
UI_Item SELUDPGAME_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Join TCP/UDP Games" },
{ { 35, 211, 205, 33 }, UI_TEXT, UIS_MED, 0, "Description:" },
{ { 35, 256, 205, 192 }, UI_TEXT, 0, 0, selgame_Description }, // Description
{ { 300, 211, 295, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Action" },
{ { 305, 255, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 0, "Create Game" },
{ { 305, 281, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 1, "Enter IP" },
{ { 305, 307, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD },
{ { 305, 333, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD },
{ { 305, 359, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD },
{ { 305, 385, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD },
{ { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 449, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiText SELGAME_DESCRIPTION(selgame_Description, { 35, 256, 205, 192 });
UiListItem SELUDPGAME_DIALOG_ITEMS[] = {
{ "Create Game", 0 },
{ "Enter IP", 1 },
};
UiItem SELUDPGAME_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText("Join TCP/UDP Games", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiText("Description:", { 35, 256, 205, 192 }, UIS_MED),
SELGAME_DESCRIPTION,
UiText("Select Action", { 300, 211, 295, 33 }, UIS_CENTER | UIS_BIG),
UiList(SELUDPGAME_DIALOG_ITEMS, 305, 255, 285, 26, UIS_CENTER | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD),
UiButton("CANCEL", &UiFocusNavigationEsc, { 449, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)
};
UI_Item SELDIFF_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Create Game" },
{ { 34, 211, 205, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, selgame_Lable }, // DIFF
{ { 35, 256, 205, 192 }, UI_TEXT, 0, 0, selgame_Description }, // Description
{ { 299, 211, 295, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Difficulty" },
{ { 300, 282, 295, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, DIFF_NORMAL, "Normal" },
{ { 300, 308, 295, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, DIFF_NIGHTMARE, "Nightmare" },
{ { 300, 334, 295, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, DIFF_HELL, "Hell" },
{ { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 449, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiListItem SELDIFF_DIALOG_ITEMS[] = {
{ "Normal", DIFF_NORMAL },
{ "Nightmare", DIFF_NIGHTMARE },
{ "Hell", DIFF_HELL }
};
UiItem SELDIFF_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText("Create Game", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiText(selgame_Label, { 34, 211, 205, 33 }, UIS_CENTER | UIS_BIG), // DIFF
SELGAME_DESCRIPTION,
UiText("Select Difficulty", { 299, 211, 295, 35 }, UIS_CENTER | UIS_BIG),
UiList(SELDIFF_DIALOG_ITEMS, 300, 282, 295, 26, UIS_CENTER | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD),
UiButton("CANCEL", &UiFocusNavigationEsc, { 449, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)
};
UI_Item ENTERIP_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Join TCP/UDP Games" },
{ { 35, 211, 205, 33 }, UI_TEXT, UIS_MED, 0, "Description:" },
{ { 35, 256, 205, 192 }, UI_TEXT, 0, 0, selgame_Description }, // Description
{ { 305, 211, 285, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Enter IP" },
{ { 305, 314, 285, 33 }, UI_EDIT, UIS_LIST | UIS_MED | UIS_GOLD, 128, selgame_Ip },
{ { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 449, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiItem ENTERIP_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText("Join TCP/UDP Games", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiText("Description:", { 35, 211, 205, 33 }, UIS_MED),
SELGAME_DESCRIPTION,
UiText("Enter IP", { 305, 211, 285, 33 }, UIS_CENTER | UIS_BIG),
UiEdit(selgame_Ip, 128, { 305, 314, 285, 33 }, UIS_LIST | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD),
UiButton("CANCEL", &UiFocusNavigationEsc, { 449, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)
};
UI_Item ENTERPASSWORD_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Join TCP/UDP Games" },
{ { 35, 211, 205, 33 }, UI_TEXT, UIS_MED, 0, "Description:" },
{ { 35, 256, 205, 192 }, UI_TEXT, 0, 0, selgame_Description }, // Description
{ { 305, 211, 285, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Enter Password" },
{ { 305, 314, 285, 33 }, UI_EDIT, UIS_LIST | UIS_MED | UIS_GOLD, 15, selgame_Password },
{ { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 449, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiItem ENTERPASSWORD_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText("Join TCP/UDP Games", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiText("Description:", { 35, 211, 205, 33 }, UIS_MED),
SELGAME_DESCRIPTION,
UiText("Enter Password", { 305, 211, 285, 33 }, UIS_CENTER | UIS_BIG),
UiEdit(selgame_Password, 15, { 305, 314, 285, 33 }, UIS_LIST | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD),
UiButton("CANCEL", &UiFocusNavigationEsc, { 449, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)
};
void selgame_Free()
@ -99,11 +102,7 @@ void selgame_GameSelection_Focus(int value)
sprintf(selgame_Description, "Enter an IP and join a game already in progress at that address.");
break;
}
for (auto &item : SELUDPGAME_DIALOG) {
if (item.caption != NULL && !(item.flags & (UIS_VCENTER | UIS_CENTER)))
WordWrap(&item);
}
WordWrap(&SELGAME_DESCRIPTION);
}
void selgame_GameSelection_Select(int value)
@ -132,23 +131,19 @@ void selgame_Diff_Focus(int value)
{
switch (value) {
case DIFF_NORMAL:
sprintf(selgame_Lable, "Normal");
sprintf(selgame_Label, "Normal");
sprintf(selgame_Description, "Normal Difficulty\nThis is where a starting character should begin the quest to defeat Diablo.");
break;
case DIFF_NIGHTMARE:
sprintf(selgame_Lable, "Nightmare");
sprintf(selgame_Label, "Nightmare");
sprintf(selgame_Description, "Nightmare Difficulty\nThe denizens of the Labyrinth have been bolstered and will prove to be a greater challenge. This is recommended for experienced characters only.");
break;
case DIFF_HELL:
sprintf(selgame_Lable, "Hell");
sprintf(selgame_Label, "Hell");
sprintf(selgame_Description, "Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm.");
break;
}
for (auto &item : SELDIFF_DIALOG) {
if (item.caption != NULL && !(item.flags & (UIS_VCENTER | UIS_CENTER)))
WordWrap(&item);
}
WordWrap(&SELGAME_DESCRIPTION);
}
void selgame_Diff_Select(int value)

107
SourceX/DiabloUI/selhero.cpp

@ -27,57 +27,68 @@ BOOL(*gfnHeroCreate)
BOOL(*gfnHeroDelete)
(_uiheroinfo *);
UI_Item SELHERO_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, title },
{ { 30, 211, 180, 76 }, UI_IMAGE, 0, UI_NUM_CLASSES, NULL, &ArtHero },
{ { 39, 323, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Level:" },
{ { 159, 323, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[0] },
{ { 39, 358, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Strength:" },
{ { 159, 358, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[1] },
{ { 39, 380, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Magic:" },
{ { 159, 380, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[2] },
{ { 39, 401, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Dexterity:" },
{ { 159, 401, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[3] },
{ { 39, 422, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Vitality:" },
{ { 159, 422, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[4] },
UiItem SELHERO_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText(title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiImage(&ArtHero, UI_NUM_CLASSES, { 30, 211, 180, 76 }),
UiText("Level:", { 39, 323, 110, 21 }, UIS_RIGHT),
UiText(textStats[0], { 159, 323, 40, 21 }, UIS_CENTER),
UiText("Strength:", { 39, 358, 110, 21 }, UIS_RIGHT),
UiText(textStats[1], { 159, 358, 40, 21 }, UIS_CENTER),
UiText("Magic:", { 39, 380, 110, 21 }, UIS_RIGHT),
UiText(textStats[2], { 159, 380, 40, 21 }, UIS_CENTER),
UiText("Dexterity:", { 39, 401, 110, 21 }, UIS_RIGHT),
UiText(textStats[3], { 159, 401, 40, 21 }, UIS_CENTER),
UiText("Vitality:", { 39, 422, 110, 21 }, UIS_RIGHT),
UiText(textStats[4], { 159, 422, 40, 21 }, UIS_CENTER),
};
UI_Item SELLIST_DIALOG[] = {
{ { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Hero" },
{ { 265, 256, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 0, listItems[0] },
{ { 265, 282, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 1, listItems[1] },
{ { 265, 308, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 2, listItems[2] },
{ { 265, 334, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 3, listItems[3] },
{ { 265, 360, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 4, listItems[4] },
{ { 265, 386, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 5, listItems[5] },
{ { 239, 429, 120, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 364, 429, 120, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_DISABLED, 0, "Delete", (void *)selhero_UiFocusNavigationYesNo },
{ { 489, 429, 120, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiImage *SELHERO_DIALOG_HERO_IMG = &SELHERO_DIALOG[2].image;
UiListItem SELLIST_DIALOG_ITEMS[] = {
{ listItems[0], 0 },
{ listItems[1], 1 },
{ listItems[2], 2 },
{ listItems[3], 3 },
{ listItems[4], 4 },
{ listItems[5], 5 },
};
UiItem SELLIST_DIALOG[] = {
UiText("Select Hero", { 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG),
UiList(SELLIST_DIALOG_ITEMS, 265, 256, 320, 26, UIS_CENTER | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 239, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD),
UiButton("Delete", &selhero_UiFocusNavigationYesNo, { 364, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_DISABLED),
UiButton("Cancel", &UiFocusNavigationEsc, { 489, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD)
};
UiButton *SELLIST_DIALOG_DELETE_BUTTON = &SELLIST_DIALOG[3].button;
UI_Item SELCLASS_DIALOG[] = {
{ { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Choose Class" },
{ { 264, 285, 320, 33 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, UI_WARRIOR, "Warrior" },
{ { 264, 318, 320, 33 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, UI_ROGUE, "Rogue" },
{ { 264, 352, 320, 33 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, UI_SORCERER, "Sorcerer" },
{ { 279, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 429, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiListItem SELCLAS_DIALOG_ITEMS[] = {
{"Warrior", UI_WARRIOR},
{"Rogue", UI_ROGUE},
{"Sorcerer", UI_SORCERER}
};
UiItem SELCLASS_DIALOG[] = {
UiText("Choose Class", { 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG),
UiList(SELCLAS_DIALOG_ITEMS, 264, 285, 320, 33, UIS_CENTER | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 279, 429, 140, 35 },UIS_CENTER | UIS_BIG | UIS_GOLD),
UiButton("Cancel", &UiFocusNavigationEsc, { 429, 429, 140, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD)
};
UI_Item ENTERNAME_DIALOG[] = {
{ { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Enter Name" },
{ { 265, 317, 320, 33 }, UI_EDIT, UIS_LIST | UIS_MED | UIS_GOLD, 15, selhero_heroInfo.name },
{ { 279, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 429, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiItem ENTERNAME_DIALOG[] = {
UiText("Enter Name", { 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG),
UiEdit(selhero_heroInfo.name, 15, { 265, 317, 320, 33 }, UIS_LIST | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 279, 429, 140, 35 },UIS_CENTER | UIS_BIG | UIS_GOLD),
UiButton("Cancel", &UiFocusNavigationEsc, { 429, 429, 140, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD)
};
UI_Item SELLOAD_DIALOG[] = {
{ { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Save File Exists" },
{ { 265, 285, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 0, "Load Game" },
{ { 265, 318, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 1, "New Game" },
{ { 279, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", (void *)UiFocusNavigationSelect },
{ { 429, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", (void *)UiFocusNavigationEsc },
UiListItem SELLOAD_DIALOG_ITEMS[] = {
{"Load Game", 0},
{"New Game", 1}
};
UiItem SELLOAD_DIALOG[] = {
UiText("Save File Exists", { 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG),
UiList(SELLOAD_DIALOG_ITEMS, 265, 285, 320, 33, UIS_CENTER | UIS_MED | UIS_GOLD),
UiButton("OK", &UiFocusNavigationSelect, { 279, 427, 140, 35 },UIS_CENTER | UIS_VCENTER |UIS_BIG | UIS_GOLD),
UiButton("Cancel", &UiFocusNavigationEsc, { 429, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER |UIS_BIG | UIS_GOLD)
};
void selhero_UiFocusNavigationYesNo()
@ -94,7 +105,7 @@ void selhero_Free()
void selhero_SetStats()
{
SELHERO_DIALOG[2].value = selhero_heroInfo.heroclass;
SELHERO_DIALOG_HERO_IMG->frame = selhero_heroInfo.heroclass;
sprintf(textStats[0], "%d", selhero_heroInfo.level);
sprintf(textStats[1], "%d", selhero_heroInfo.strength);
sprintf(textStats[2], "%d", selhero_heroInfo.magic);
@ -124,18 +135,18 @@ void selhero_List_Focus(int value)
if (selhero_SaveCount && value < selhero_SaveCount) {
memcpy(&selhero_heroInfo, &selhero_heros[value], sizeof(selhero_heroInfo));
selhero_SetStats();
SELLIST_DIALOG[8].flags = baseFlags | UIS_GOLD;
SELLIST_DIALOG_DELETE_BUTTON->flags = baseFlags | UIS_GOLD;
selhero_deleteEnabled = true;
return;
}
SELHERO_DIALOG[2].value = UI_NUM_CLASSES;
SELHERO_DIALOG_HERO_IMG->frame = UI_NUM_CLASSES;
sprintf(textStats[0], "--");
sprintf(textStats[1], "--");
sprintf(textStats[2], "--");
sprintf(textStats[3], "--");
sprintf(textStats[4], "--");
SELLIST_DIALOG[8].flags = baseFlags | UIS_DISABLED;
SELLIST_DIALOG_DELETE_BUTTON->flags = baseFlags | UIS_DISABLED;
selhero_deleteEnabled = false;
}

19
SourceX/DiabloUI/selyesno.cpp

@ -12,14 +12,19 @@ BOOL(*selyesno_gfnRemove)
char selyesno_confirmationMessage[256];
char selyesno_title[32];
UI_Item SELYESNO_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, selyesno_title },
{ { 120, 236, 280, 168 }, UI_TEXT, UIS_MED, 0, selyesno_confirmationMessage },
{ { 230, 390, 180, 35 }, UI_LIST, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Yes" },
{ { 230, 426, 180, 35 }, UI_LIST, UIS_CENTER | UIS_BIG | UIS_GOLD, 1, "No" },
UiListItem SELYESNO_DIALOG_ITEMS[] = {
{ "Yes", 0 },
{ "No", 1 }
};
UiItem SELYESNO_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText(selyesno_title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiText(selyesno_confirmationMessage, { 120, 236, 280, 168 }, UIS_MED),
UiList(SELYESNO_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD)
};
UiText *SELYESNO_DIALOG_CONFIRMATION_MESSAGE = &SELYESNO_DIALOG[2].text;
void selyesno_Free()
{
ArtBackground.Unload();
@ -54,7 +59,7 @@ BOOL UiSelHeroDelYesNoDialog(
}
sprintf(selyesno_confirmationMessage, "Are you sure you want to delete the character \"%s\"?", selyesno_heroInfo.name);
WordWrap(&SELYESNO_DIALOG[2]);
WordWrap(SELYESNO_DIALOG_CONFIRMATION_MESSAGE);
UiInitList(0, 1, NULL, selyesno_Select, selyesno_Esc, SELYESNO_DIALOG, size(SELYESNO_DIALOG), false, NULL);

6
SourceX/DiabloUI/title.cpp

@ -17,9 +17,9 @@ void title_Free()
BOOL UiTitleDialog(int a1)
{
UI_Item TITLESCREEN_DIALOG[] = {
{ { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground },
{ { 49, 410, 550, 26 }, UI_TEXT, UIS_MED | UIS_CENTER, 0, "Copyright \xA9 1996-2001 Blizzard Entertainment" },
UiItem TITLESCREEN_DIALOG[] = {
UiImage(&ArtBackground, { 0, 0, 640, 480 }),
UiText("Copyright \xA9 1996-2001 Blizzard Entertainment", { 49, 410, 550, 26 }, UIS_MED | UIS_CENTER)
};
title_Load();

202
SourceX/DiabloUI/ui_item.h

@ -0,0 +1,202 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include "devilution.h"
#include "art.h"
#include "stubs.h"
namespace dvl {
enum UiType {
UI_TEXT,
UI_IMAGE,
UI_BUTTON,
UI_LIST,
UI_EDIT,
};
enum UiFlags {
UIS_SMALL = 1 << 0,
UIS_MED = 1 << 1,
UIS_BIG = 1 << 2,
UIS_HUGE = 1 << 3,
UIS_CENTER = 1 << 4,
UIS_RIGHT = 1 << 5,
UIS_VCENTER = 1 << 6,
UIS_SILVER = 1 << 7,
UIS_GOLD = 1 << 8,
UIS_SML1 = 1 << 9,
UIS_SML2 = 1 << 10,
UIS_LIST = 1 << 11,
UIS_DISABLED = 1 << 12,
UIS_HIDDEN = 1 << 13,
};
struct UiItemBase {
constexpr UiItemBase(SDL_Rect rect, int flags)
: rect(rect)
, flags(flags)
{
}
SDL_Rect rect;
int flags;
};
struct UiImage : public UiItemBase {
constexpr UiImage(Art *art, SDL_Rect rect, int flags = 0)
: UiImage(art, /*frame=*/0, rect, flags)
{
}
constexpr UiImage(Art *art, int frame, SDL_Rect rect, int flags = 0)
: UiItemBase(rect, flags)
, art(art)
, frame(frame)
{
}
Art *art;
int frame;
};
struct UiText : public UiItemBase {
constexpr UiText(char *text, SDL_Rect rect, int flags = 0)
: UiItemBase(rect, flags)
, text(text)
{
}
char *text;
};
struct UiButton : public UiItemBase {
constexpr UiButton(char *text, void (*action)(), SDL_Rect rect, int flags = 0)
: UiItemBase(rect, flags)
, text(text)
, action(action)
{
}
char *text;
void (*action)();
};
struct UiListItem {
constexpr UiListItem(char *text = "", int value = 0)
: text(text)
, value(value)
{
}
char *text;
int value;
};
struct UiList : public UiItemBase {
template <std::size_t N>
constexpr UiList(
UiListItem (&items)[N],
decltype(SDL_Rect().x) x,
decltype(SDL_Rect().y) y,
decltype(SDL_Rect().w) item_width,
decltype(SDL_Rect().h) item_height,
int flags)
: UiItemBase({ x, y, item_width, static_cast<decltype(SDL_Rect().h)>(item_height * N) }, flags)
, x(x)
, y(y)
, item_width(item_width)
, item_height(item_height)
, items(items)
, length(N)
{
}
decltype(SDL_Rect().x) x;
decltype(SDL_Rect().y) y;
decltype(SDL_Rect().w) item_width;
decltype(SDL_Rect().h) item_height;
UiListItem *items;
std::size_t length;
SDL_Rect itemRect(std::size_t i) const
{
return { x, static_cast<decltype(SDL_Rect().y)>(y + item_height * i), item_width, item_height };
}
UiListItem *itemAt(decltype(SDL_Rect().y) y) const
{
ASSERT(y >= rect.y);
const std::size_t index = (y - rect.y) / item_height;
ASSERT(index < length);
return &items[index];
}
};
struct UiEdit : public UiItemBase {
constexpr UiEdit(char *value, std::size_t max_length, SDL_Rect rect, int flags)
: UiItemBase(rect, flags)
, value(value)
, max_length(max_length)
{
}
char *value;
std::size_t max_length;
};
struct UiItem {
constexpr UiItem(UiText text)
: type(UI_TEXT)
, text(text)
{
}
constexpr UiItem(UiImage image)
: type(UI_IMAGE)
, image(image)
{
}
constexpr UiItem(UiButton button)
: type(UI_BUTTON)
, button(button)
{
}
constexpr UiItem(UiList list)
: type(UI_LIST)
, list(list)
{
}
constexpr UiItem(UiEdit edit)
: type(UI_EDIT)
, edit(edit)
{
}
UiType type;
union {
UiText text;
UiImage image;
UiButton button;
UiList list;
UiEdit edit;
UiItemBase common;
};
int flags() const
{
return common.flags;
}
const SDL_Rect &rect() const
{
return common.rect;
}
};
} // namespace dvl
Loading…
Cancel
Save