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.
356 lines
6.5 KiB
356 lines
6.5 KiB
#pragma once |
|
|
|
#include <cstdint> |
|
#include <cstddef> |
|
#include <string> |
|
#include <vector> |
|
|
|
#include "devilution.h" |
|
#include "stubs.h" |
|
|
|
#include "DiabloUI/art.h" |
|
#include "DiabloUI/text_draw.h" |
|
|
|
namespace dvl { |
|
|
|
enum UiType { |
|
UI_TEXT, |
|
UI_ART_TEXT, |
|
UI_ART_TEXT_BUTTON, |
|
UI_IMAGE, |
|
UI_BUTTON, |
|
UI_LIST, |
|
UI_SCROLLBAR, |
|
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_DISABLED = 1 << 9, |
|
UIS_HIDDEN = 1 << 10, |
|
}; |
|
|
|
struct UiItemBase { |
|
constexpr UiItemBase(SDL_Rect rect, int flags) |
|
: rect(rect) |
|
, flags(flags) |
|
{ |
|
} |
|
|
|
bool has_flag(UiFlags flag) const |
|
{ |
|
return flags & flag; |
|
} |
|
|
|
bool has_any_flag(int flags) const |
|
{ |
|
return (this->flags & flags) != 0; |
|
} |
|
|
|
void add_flag(UiFlags flag) |
|
{ |
|
flags |= flag; |
|
} |
|
|
|
void remove_flag(UiFlags flag) |
|
{ |
|
flags &= ~flag; |
|
} |
|
|
|
SDL_Rect rect; |
|
int flags; |
|
}; |
|
|
|
struct UiImage : public UiItemBase { |
|
constexpr UiImage(Art *art, bool animated, int frame, SDL_Rect rect, int flags = 0) |
|
: UiItemBase(rect, flags) |
|
, art(art) |
|
, animated(animated) |
|
, frame(frame) |
|
{ |
|
} |
|
|
|
constexpr UiImage(Art *art, int frame, SDL_Rect rect, int flags = 0) |
|
: UiImage(art, /*animated=*/false, frame, rect, flags) |
|
{ |
|
} |
|
|
|
constexpr UiImage(Art *art, SDL_Rect rect, int flags = 0) |
|
: UiImage(art, /*frame=*/0, rect, flags) |
|
{ |
|
} |
|
|
|
Art *art; |
|
bool animated; |
|
int frame; |
|
}; |
|
|
|
// Plain text (TTF). |
|
struct UiText : public UiItemBase { |
|
constexpr UiText(const char *text, SDL_Color color, SDL_Rect rect, int flags = 0) |
|
: UiItemBase(rect, flags) |
|
, color(color) |
|
, shadow_color{ 0, 0, 0, 0 } |
|
, text(text) |
|
, render_cache(nullptr) |
|
{ |
|
} |
|
|
|
constexpr UiText(const char *text, SDL_Rect rect, int flags = 0) |
|
: UiText(text, SDL_Color{ 243, 243, 243, 0 }, rect, flags) |
|
{ |
|
} |
|
|
|
SDL_Color color; |
|
SDL_Color shadow_color; |
|
const char *text; |
|
|
|
// State: |
|
TtfSurfaceCache *render_cache; |
|
|
|
void FreeCache() |
|
{ |
|
delete render_cache; |
|
render_cache = nullptr; |
|
} |
|
}; |
|
|
|
// Text drawn with Diablo sprites. |
|
struct UiArtText : public UiItemBase { |
|
constexpr UiArtText(const char *text, SDL_Rect rect, int flags = 0) |
|
: UiItemBase(rect, flags) |
|
, text(text) |
|
{ |
|
} |
|
|
|
const char *text; |
|
}; |
|
|
|
// Clickable Diablo sprites text. |
|
struct UiArtTextButton : public UiItemBase { |
|
constexpr UiArtTextButton(const char *text, void (*action)(), SDL_Rect rect, int flags = 0) |
|
: UiItemBase(rect, flags) |
|
, text(text) |
|
, action(action) |
|
{ |
|
} |
|
|
|
const char *text; |
|
void (*action)(); |
|
}; |
|
|
|
// A button (uses Diablo sprites). |
|
struct UiButton : public UiItemBase { |
|
enum FrameKey { |
|
DEFAULT = 0, |
|
PRESSED, |
|
DISABLED |
|
}; |
|
using FrameMap = int[3]; |
|
|
|
constexpr UiButton(Art *art, const FrameMap &frame_map, const char *text, void (*action)(), SDL_Rect rect, int flags = 0) |
|
: UiItemBase(rect, flags) |
|
, art(art) |
|
, frame_map{ frame_map[0], frame_map[1], frame_map[2] } |
|
, text(text) |
|
, action(action) |
|
, pressed(false) |
|
, render_cache(nullptr) |
|
{ |
|
} |
|
|
|
Art *art; |
|
const FrameMap frame_map; |
|
|
|
const char *text; |
|
void (*action)(); |
|
|
|
// State |
|
bool pressed; |
|
TtfSurfaceCache *render_cache; |
|
|
|
void FreeCache() |
|
{ |
|
delete render_cache; |
|
render_cache = nullptr; |
|
} |
|
}; |
|
|
|
struct UiListItem { |
|
constexpr UiListItem(const char *text = "", int value = 0) |
|
: text(text) |
|
, value(value) |
|
{ |
|
} |
|
const 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 UiScrollBar : public UiItemBase { |
|
constexpr UiScrollBar(Art *bg, Art *thumb, Art *arrow, SDL_Rect rect, int flags = 0) |
|
: UiItemBase(rect, flags) |
|
, bg(bg) |
|
, thumb(thumb) |
|
, arrow(arrow) |
|
{ |
|
} |
|
|
|
Art *bg; |
|
Art *thumb; |
|
Art *arrow; |
|
}; |
|
|
|
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(UiArtText text) |
|
: type(UI_ART_TEXT) |
|
, art_text(text) |
|
{ |
|
} |
|
|
|
constexpr UiItem(UiArtTextButton art_text_button) |
|
: type(UI_ART_TEXT_BUTTON) |
|
, art_text_button(art_text_button) |
|
{ |
|
} |
|
|
|
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(UiScrollBar scrollbar) |
|
: type(UI_SCROLLBAR) |
|
, scrollbar(scrollbar) |
|
{ |
|
} |
|
|
|
constexpr UiItem(UiEdit edit) |
|
: type(UI_EDIT) |
|
, edit(edit) |
|
{ |
|
} |
|
|
|
UiType type; |
|
union { |
|
UiText text; |
|
UiArtText art_text; |
|
UiImage image; |
|
UiArtTextButton art_text_button; |
|
UiButton button; |
|
UiList list; |
|
UiScrollBar scrollbar; |
|
UiEdit edit; |
|
UiItemBase common; |
|
}; |
|
|
|
bool has_flag(UiFlags flag) const |
|
{ |
|
return common.has_flag(flag); |
|
} |
|
|
|
bool has_any_flag(int flags) const |
|
{ |
|
return common.has_any_flag(flags); |
|
} |
|
|
|
const SDL_Rect &rect() const |
|
{ |
|
return common.rect; |
|
} |
|
|
|
void FreeCache() |
|
{ |
|
switch (type) { |
|
case UI_BUTTON: |
|
button.FreeCache(); |
|
break; |
|
case UI_TEXT: |
|
text.FreeCache(); |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
}; |
|
|
|
} // namespace dvl
|
|
|