VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
MenuModel.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4#include <memory>
5#include <optional>
6#include <string>
7#include <string_view>
8#include <vector>
9
10namespace VoltMod
11{
12
13/** Returns the number of pages needed for @p items, with at least one page. */
14constexpr int PageCount(int items, int perPage)
15{
16 return items <= 0 ? 1 : (items + perPage - 1) / perPage;
17}
18
19/** Wraps @p value into `[0, count)`, including when @p value is negative. */
20constexpr int WrapIndex(int value, int count)
21{
22 return count <= 0 ? 0 : ((value % count) + count) % count;
23}
24
25/** Row type used by renderers. */
26enum class MenuRowKind
27{
28 Text, ///< Not selectable; a caption or a summary line.
29 Button, ///< Runs something.
30 Submenu, ///< Opens another menu.
31 Toggle, ///< Carries an on/off value.
32 Choice, ///< Carries one of several values, stepped left and right.
33 Input ///< Carries a value the player types in chat.
34};
35
36/** Current display state of a menu row. Text is unescaped. */
37struct MenuRow
38{
39 std::string Label;
40 /** Empty when the row has no value. */
41 std::string Value;
43 /** Disabled rows are drawn greyed out, skipped by the cursor, and refuse activation. */
44 bool Enabled = true;
45 /** Whether the cursor may land on the row. */
46 bool Selectable = true;
47 /** Whether A/D or a row stepper changes the value instead of paging. */
48 bool Steppable = false;
49 /** Toggle state, used to render a switch or supply the default value text. */
50 std::optional<bool> State;
51 /** An icon name for a surface that draws icons; center HTML ignores it. Empty for none. */
52 std::string Icon;
53
54 /** Set by the menu service, not by @ref MenuItem::Describe. */
55 bool Pending = false;
56 bool Changed = false;
57};
58
59/** Options for a menu session. Submenus inherit them. */
61{
62 /** Whether the server-wide movement freeze (@ref MenuFreeze::Enable) applies. False mid-round. */
63 bool FreezeMovement = true;
64
65 /** Whether the root menu shows the layout's home markup instead of its rows. Only its owner asks. */
66 bool HomePage = false;
67};
68
69struct Menu;
70
71/** The surface a menu is drawn on, and what a row callback may ask of it. */
73{
74public:
75 virtual ~MenuSurface() = default;
76
77 MenuSurface(const MenuSurface&) = delete;
79
80 /** Opens a session for @p slot showing @p menu, closing any the player has open here. What a
81 * command calls. False when this surface cannot draw for @p slot; nothing is left open then. */
82 virtual bool OpenSession(int slot, std::shared_ptr<Menu> menu, MenuOptions options) = 0;
83
84 /** Pushes @p menu onto @p slot's session and shows it, starting one with default options when
85 * none is open. What a row calls. */
86 virtual void Open(int slot, std::shared_ptr<Menu> menu) = 0;
87
88 virtual bool IsOpen(int slot) const = 0;
89
90 /** Pops the top menu, returning to its parent when one exists. */
91 virtual void Close(int slot) = 0;
92
93 /** Clears the stack and removes the menu from the player's screen. */
94 virtual void CloseAll(int slot) = 0;
95
96 /** Translates and sends @p replyKey, then closes every menu. */
97 virtual void CloseAll(int slot, std::string_view replyKey) = 0;
98
99 /** Routes the next chat line to @p callback. Closing the menu cancels it. */
100 virtual void Prompt(int slot, std::string prompt,
101 std::function<bool(int slot, std::string_view text)> callback) = 0;
102
103 /** Translates @p key for @p slot, using @p fallback when missing. */
104 virtual std::string Translate(int slot, std::string_view key, std::string_view fallback) const = 0;
105
106protected:
107 MenuSurface() = default;
108};
109
110/** Row callbacks. Only @ref Describe is required. */
112{
113 /** Describes the row's current state. Called on every redraw. */
114 std::function<MenuRow(int slot)> Describe;
115
116 /** Runs on E or a click. */
117 std::function<void(int slot, MenuSurface& surface)> Activate;
118
119 /** Runs on A/D or a stepper. Return true to consume the input. */
120 std::function<bool(int slot, int direction)> Step;
121
122 /** Applies a stepped value after input settles. */
123 std::function<void(int slot)> Commit;
124};
125
126/** True when @p item is one a player may act on right now: it describes itself as both enabled
127 * and selectable. A cursor lands only on these, and only these activate. */
128inline bool IsRowActionable(const MenuItem& item, int slot)
129{
130 if (!item.Describe)
131 {
132 return false;
133 }
134
135 const MenuRow row = item.Describe(slot);
136 return row.Enabled && row.Selectable;
137}
138
139/** A menu model. Build a separate instance for each player. */
140struct Menu
141{
142 std::string Title;
143 /** Optional plain-text detail shown with the title. */
144 std::string Subtitle;
145 std::vector<MenuItem> Items;
146};
147
148} // namespace VoltMod
virtual void CloseAll(int slot, std::string_view replyKey)=0
virtual void Close(int slot)=0
MenuSurface(const MenuSurface &)=delete
virtual ~MenuSurface()=default
virtual void Open(int slot, std::shared_ptr< Menu > menu)=0
virtual bool OpenSession(int slot, std::shared_ptr< Menu > menu, MenuOptions options)=0
virtual void Prompt(int slot, std::string prompt, std::function< bool(int slot, std::string_view text)> callback)=0
virtual std::string Translate(int slot, std::string_view key, std::string_view fallback) const =0
virtual bool IsOpen(int slot) const =0
MenuSurface & operator=(const MenuSurface &)=delete
virtual void CloseAll(int slot)=0
@ Input
Carries a value the player types in chat.
@ Submenu
Opens another menu.
@ Choice
Carries one of several values, stepped left and right.
@ Button
Runs something.
@ Text
Not selectable; a caption or a summary line.
@ Toggle
Carries an on/off value.
constexpr int WrapIndex(int value, int count)
Definition MenuModel.hpp:20
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
constexpr int PageCount(int items, int perPage)
Definition MenuModel.hpp:14
bool IsRowActionable(const MenuItem &item, int slot)
std::function< void(int slot, MenuSurface &surface)> Activate
std::function< void(int slot)> Commit
std::function< MenuRow(int slot)> Describe
std::function< bool(int slot, int direction)> Step
std::optional< bool > State
Definition MenuModel.hpp:50
std::string Icon
Definition MenuModel.hpp:52
std::string Value
Definition MenuModel.hpp:41
std::string Label
Definition MenuModel.hpp:39
MenuRowKind Kind
Definition MenuModel.hpp:42
std::string Subtitle
std::string Title
std::vector< MenuItem > Items