#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 #include #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