Files
sacred_k/src/mods/screen.h
T
khallaandClaude Opus 5.5 0ef3cf4bbd Shared chest, menu after a game, dialogs over 16:9 screens
- Shared chest: emptied and not saved from the moment a save game is read
  until it reloads; a hero saved inside a load wrote the new world's
  objects (stale ids) as the chest's items.
- Main menu after a game: shown 16:9 screens are tracked on the menu thread
  only and expire after 2 frames; a destroyed in-game window kept the menu
  unframed (old pictures, frame at the left).
- Dialogs over a 16:9 screen in the main menu are centred, their dimming
  covers the screen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 00:41:12 +02:00

118 lines
4.4 KiB
C++

#pragma once
// 16:9 menu screens (request of 2026-10-20, docs/screens.md): a screen of our
// own replaces a full-screen window of the game's (its render and mouse
// handling), laid out on a 1365x768 canvas (1920x1080 in UI units), centred in
// the render width; wider screens only get more background at the sides. The
// look is the game's: its frames and buttons on a dark background of ours.
//
// A screen hooks its window's render and event methods and calls Render /
// Handle with a body that draws / handles in canvas coordinates with the
// helpers below.
#include <cstdint>
#include <string>
#include "game/ui/text.h"
#include "mods/hud.h"
namespace mods::screen {
using game::UiRect;
constexpr int kWidth = hud::kCanvasWidth;
constexpr int kHeight = hud::kCanvasHeight;
// Spacing: the game's frames reach about 0x20 beyond their rects, buttons
// about 0x21 (measured on the options window).
constexpr int kFrameOrnament = 0x20;
// The frames are made of pieces of 64: other sizes leave gaps (the game's
// frames are 384x128, 384x64; screenshot 2026-10-20).
constexpr int kFrameStep = 64;
constexpr int kButtonOrnament = 0x21;
constexpr int kMargin = kFrameOrnament + 16; // canvas edge to a panel's rect
constexpr int kPanelGap = 96; // between two panels' rects, as the options window's columns
constexpr int kPanelPadding = 16; // panel rect to its content
// The logo in the background's top left corner (render target coordinates;
// screens may overlap it).
constexpr int kLogoMargin = 48;
constexpr int kLogoHeight = 124;
constexpr int kLogoWidth = kLogoHeight * 74 / 100; // the emblem's aspect (screen.cpp)
constexpr uint16_t kFont = 1;
constexpr uint32_t kTextColour = 0xffe6d6aa; // as the options' texts
constexpr uint32_t kHeadingColour = 0xfff0c060; // as the options' headings
constexpr uint32_t kDimColour = 0xff8c8474;
constexpr uint32_t kRowColour = 0x40302418;
constexpr uint32_t kRowHoverColour = 0x80403020;
constexpr uint32_t kRowSelectedColour = 0xc0604818;
// The background of the menu screens across the whole render target (also
// beside the main menu's centred frame and full-screen windows in a game).
void DrawBackground(void* device);
// Called once per main menu frame (menu thread): whether a screen is shown
// (the main menu then does not draw centred).
bool BeginMenuFrame();
// Draws the screen of `window`: the background across the whole render
// target, then body(context) in canvas coordinates.
int Render(void* window, void* device, int (*body)(void* context), void* context);
// Runs body(context) with the event's mouse position in canvas coordinates.
int Handle(void* event, int (*body)(void* context), void* context);
void Fill(void* device, const UiRect& rect, uint32_t colour);
// One line of text in `rect`, centred vertically (game::kTextCenter /
// kTextRight for horizontal alignment).
void Text(void* device, const UiRect& rect, const std::wstring& text, uint32_t colour, uint32_t flags = 0);
UiRect Inset(const UiRect& rect, int by);
// A panel: a dark backdrop with the game's frame around `rect` (made anew when
// the rect changes) and an optional heading at its top.
class Panel {
public:
explicit Panel(const char* name) : name_(name) {}
// The content area below the heading.
UiRect Draw(void* device, const UiRect& rect, const std::wstring& heading = {});
private:
const char* name_;
UiRect rect_ = {};
uint8_t* frame_ = nullptr;
};
// A button of the game's (look and sounds of `model`, a button of the
// window), made on first use.
class Button {
public:
Button(const char* name, std::wstring caption) : name_(name), caption_(std::move(caption)) {}
void Draw(void* device, const uint8_t* model, const UiRect& rect);
// Passes the event to the button (pressed look, sound); true for a left
// click on it. Only for buttons drawn this frame.
bool Clicked(void* event);
void SetCaption(const std::wstring& caption);
private:
const char* name_;
std::wstring caption_;
uint32_t captionId_ = 0;
uint8_t* control_ = nullptr;
UiRect rect_ = {};
unsigned drawnFrame_ = 0;
};
// Height of the model's buttons (as the window made them).
int16_t ButtonHeight(const uint8_t* model);
// Two clicks on the same thing within the system's double-click time.
class DoubleClick {
public:
bool Click(int target);
private:
int last_ = -1;
unsigned long at_ = 0;
};
} // namespace mods::screen