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

#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