Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
OptionsUI.cpp
Go to the documentation of this file.
1#include "OptionsUI.hpp"
2
3#include <algorithm>
4#include <array>
5
7{
8 std::size_t quickHelpPageLineCount(std::size_t totalLines,
9 std::size_t firstLine, int lineHeight, bool initialPage) noexcept
10 {
11 if (firstLine >= totalLines || lineHeight <= 0) return 0;
12 const int availableHeight = 450 - lineHeight;
13 if (availableHeight <= 0) return 0;
14 // PrintString's strict y < max_height test draws the row whose top is
15 // inside the area. The initial page has no GetStringHeight preflight.
16 const auto capacity = static_cast<std::size_t>((availableHeight - 1) / lineHeight + 1);
17 const auto probeRows = std::min(totalLines - firstLine, capacity);
18 if (!initialPage && probeRows * static_cast<std::size_t>(lineHeight) >
19 static_cast<std::size_t>(availableHeight))
20 {
21 // UDOpts Previous/Next reserve another line after an overflowing
22 // probe. This applies to Previous returning to page zero as well.
23 return std::min(totalLines - firstLine, capacity - 1);
24 }
25 return probeRows;
26 }
27
28 namespace
29 {
30 inline constexpr std::array<int, 5> FileButtonY{
31 114, 180, 247, 314, 401};
32 inline constexpr std::array<int, 3> HelpButtonY{180, 288, 401};
33 inline constexpr int FileButtonX = 291;
34 inline constexpr int FileButtonWidth = 220;
35 inline constexpr int FileButtonHeight = 62;
36 inline constexpr std::array<int, 4> MenuButtonX{31, 180, 478, 615};
37 inline constexpr std::array<int, 4> MenuButtonY{494, 493, 490, 490};
38 inline constexpr std::array<int, 4> MenuButtonWidth{170, 159, 164, 175};
39 inline constexpr std::array<int, 4> MenuButtonHeight{59, 60, 63, 62};
40 inline constexpr int OptionOkayX = 350;
41 inline constexpr int OptionOkayY = 450;
42 inline constexpr int OptionOkayWidth = 127;
43 inline constexpr int OptionOkayHeight = 36;
44 inline constexpr int ToggleButtonWidth = 59;
45 inline constexpr int ToggleButtonHeight = 33;
46 inline constexpr std::array<int, 7> ToggleY{135, 175, 215, 255, 295, 335, 375};
47 }
48
50 {
51 const auto index = static_cast<std::size_t>(button);
52 if (index >= MenuButtonX.size())
53 return {};
57 }
58
59 std::optional<MenuButton> menuButtonHit(int x, int y) noexcept
60 {
61 for (std::size_t index = 0; index < MenuButtonX.size(); ++index)
62 {
63 const auto button = static_cast<MenuButton>(index);
65 return button;
66 }
67 return std::nullopt;
68 }
69
76
78 {
79 const auto index = static_cast<std::size_t>(toggle);
80 if (index >= static_cast<std::size_t>(OptionToggle::Count))
81 return {};
83 const int columnX = soundColumn ? 25 : 457;
84 const std::size_t yIndex = soundColumn ? index : index - 3U;
85 if (yIndex >= ToggleY.size()) return {};
86 const int left = columnX + (onSide ? 0 : ToggleButtonWidth);
87 const int top = ToggleY[yIndex];
89 }
90
91 bool optionToggleSupported(OptionToggle toggle) noexcept
92 {
93 return std::find(SupportedOptionToggles.begin(),
94 SupportedOptionToggles.end(), toggle) != SupportedOptionToggles.end();
95 }
96
98 {
99 const auto index = static_cast<std::size_t>(button);
100 if (index >= FileButtonY.size())
101 return {};
102 const int top = FileButtonY[index];
103 return {FileButtonX, top,
106 }
107
108 std::optional<FileButton> fileButtonHit(int x, int y) noexcept
109 {
110 for (std::size_t index = 0; index < FileButtonY.size(); ++index)
111 {
112 const auto button = static_cast<FileButton>(index);
114 return button;
115 }
116 return std::nullopt;
117 }
118
120 {
121 const auto index = static_cast<std::size_t>(button);
122 if (index >= HelpButtonY.size()) return {};
123 const int top = HelpButtonY[index];
125 }
126
127 std::optional<HelpButton> helpButtonHit(int x, int y) noexcept
128 {
129 for (std::size_t index = 0; index < HelpButtonY.size(); ++index)
130 {
131 const auto button = static_cast<HelpButton>(index);
132 if (helpButtonRect(button).contains(x, y)) return button;
133 }
134 return std::nullopt;
135 }
136
138 State& state,
139 display::Screen2D previousView) noexcept
140 {
141 if (!display::isIBarVisible(previousView))
142 return false;
143 state.currentScreen = Screen::File;
144 state.previousView = previousView;
145 state.optionSnapshotLoaded = false;
146 state.active = true;
147 return true;
148 }
149
151 bool tokenVoicesOn, bool hostCommentsOn,
152 bool musicOn, std::uint8_t musicTuneIndex,
154 bool lightingOn, bool board3DOn,
155 bool filteringOn) noexcept
156 {
157 state.optionOn[static_cast<std::size_t>(OptionToggle::TokenVoices)] = tokenVoicesOn;
158 state.optionOn[static_cast<std::size_t>(OptionToggle::HostComments)] = hostCommentsOn;
159 state.optionOn[static_cast<std::size_t>(OptionToggle::Music)] = musicOn;
160 state.musicTuneIndex = std::min<std::uint8_t>(musicTuneIndex, MusicTuneCount - 1);
161 state.originalMusicTuneIndex = state.musicTuneIndex;
162 state.optionOn[static_cast<std::size_t>(OptionToggle::TokenAnimations)] = tokenAnimationsOn;
163 state.optionOn[static_cast<std::size_t>(OptionToggle::Camera)] = cameraMovementOn;
164 state.optionOn[static_cast<std::size_t>(OptionToggle::Lighting)] = lightingOn;
165 state.optionOn[static_cast<std::size_t>(OptionToggle::Board3D)] = board3DOn;
166 state.optionOn[static_cast<std::size_t>(OptionToggle::Filtering)] = filteringOn;
167 state.optionSnapshotLoaded = true;
168 }
169
170 bool selectMusicTune(State& state, std::uint8_t tuneIndex) noexcept
171 {
172 if (!state.optionSnapshotLoaded || tuneIndex >= MusicTuneCount)
173 return false;
174 state.musicTuneIndex = tuneIndex;
175 return true;
176 }
177
179 State& state,
181 const uimsg::Message& message) noexcept
182 {
183 InputResult result{};
185 {
186 state.active = false;
187 state.optionSnapshotLoaded = false;
188 return result;
189 }
190 if (!state.active || message.type != uimsg::Type::MouseLeftDown)
191 return result;
192
193 const auto menu = menuButtonHit(
194 static_cast<int>(message.numberA),
195 static_cast<int>(message.numberB));
196 if (menu)
197 {
198 result.pressedMenuButton = menu;
199 state.quickHelpVisible = false;
200 state.musicChoiceRects = {};
201 state.currentScreen = static_cast<Screen>(static_cast<std::uint8_t>(*menu));
202 state.optionSnapshotLoaded = false;
203 return result;
204 }
205
206 if (state.currentScreen == Screen::Option)
207 {
208 const auto x = static_cast<int>(message.numberA);
209 const auto y = static_cast<int>(message.numberB);
210 if (optionOkayRect().contains(x, y))
211 {
212 result.pressedOptionOkay = true;
213 result.requestedBackdrop = state.previousView;
214 state.active = false;
215 return result;
216 }
217 if (!state.optionSnapshotLoaded) return result;
218 for (std::uint8_t index = 0; index < MusicTuneCount; ++index)
219 {
220 if (state.musicChoiceRects[index].contains(x, y))
221 {
222 state.musicTuneIndex = index;
223 result.pressedMusicTune = index;
224 return result;
225 }
226 }
227 for (const auto toggle : SupportedOptionToggles)
228 {
229 if (optionToggleRect(toggle, true).contains(x, y) ||
230 optionToggleRect(toggle, false).contains(x, y))
231 {
232 result.pressedOptionToggle = toggle;
233 const auto index = static_cast<std::size_t>(toggle);
234 state.optionOn[index] = !state.optionOn[index];
235 return result;
236 }
237 }
238 return result;
239 }
240
241 if (state.currentScreen == Screen::Credits && message.numberB >= 0 && message.numberB < 486)
242 {
243 state.active = false;
244 result.requestedBackdrop = state.previousView;
245 return result;
246 }
247
248 if (state.currentScreen == Screen::Help)
249 {
250 if (state.quickHelpVisible)
251 {
252 for (std::size_t index = 0; index < 3; ++index)
253 {
254 if (!state.quickHelpButtonRects[index].contains(
255 static_cast<int>(message.numberA), static_cast<int>(message.numberB))) continue;
256 if (index == 0 && state.quickHelpPageIndex > 0)
257 {
258 --state.quickHelpPageIndex;
259 state.quickHelpFirstLine = state.quickHelpPageOffsets[state.quickHelpPageIndex];
260 state.quickHelpInitialPage = false;
261 }
262 else if (index == 1 && state.quickHelpLinesPerPage > 0 &&
263 state.quickHelpFirstLine + state.quickHelpLinesPerPage < state.quickHelpLines.size() &&
264 state.quickHelpPageIndex + 1 < state.quickHelpPageOffsets.size())
265 {
266 state.quickHelpFirstLine += state.quickHelpLinesPerPage;
267 ++state.quickHelpPageIndex;
268 // The renderer reserves this slot before enabling Next;
269 // UI dispatch stays allocation-free/noexcept.
270 state.quickHelpPageOffsets[state.quickHelpPageIndex] = state.quickHelpFirstLine;
271 state.quickHelpInitialPage = false;
272 }
273 else if (index == 2) state.quickHelpVisible = false;
274 return result;
275 }
276 return result;
277 }
278 const auto button = helpButtonHit(
279 static_cast<int>(message.numberA),
280 static_cast<int>(message.numberB));
281 if (!button) return result;
282 result.pressedHelpButton = button;
284 {
285 result.requestedBackdrop = state.previousView;
286 state.active = false;
287 }
288 return result;
289 }
290
291 if (state.currentScreen != Screen::File)
292 return result;
293
294 const auto button = fileButtonHit(
295 static_cast<int>(message.numberA),
296 static_cast<int>(message.numberB));
297 if (!button)
298 return result;
299
300 result.pressedFileButton = button;
302 {
303 result.requestedBackdrop = state.previousView;
304 state.active = false;
305 }
306 return result;
307 }
308
309 void reset(State& state) noexcept
310 {
311 state = State{};
312 }
313}
std::atomic< float > left
int top
unsigned state
unsigned index
Button button
constexpr bool isIBarVisible(Screen2D screen) noexcept
Definition Display.hpp:49
Rect optionToggleRect(OptionToggle toggle, bool onSide) noexcept
Definition OptionsUI.cpp:77
bool selectMusicTune(State &state, std::uint8_t tuneIndex) noexcept
constexpr std::uint8_t MusicTuneCount
Definition OptionsUI.hpp:66
bool beginFromIBar(State &state, display::Screen2D previousView) noexcept
bool optionToggleSupported(OptionToggle toggle) noexcept
Definition OptionsUI.cpp:91
void reset(State &state) noexcept
InputResult processInput(State &state, display::Screen2D desiredView, const uimsg::Message &message) noexcept
Rect menuButtonRect(MenuButton button) noexcept
Definition OptionsUI.cpp:49
std::size_t quickHelpPageLineCount(std::size_t totalLines, std::size_t firstLine, int lineHeight, bool initialPage) noexcept
Definition OptionsUI.cpp:8
void loadSupportedOptionValues(State &state, bool tokenVoicesOn, bool hostCommentsOn, bool musicOn, std::uint8_t musicTuneIndex, bool tokenAnimationsOn, bool cameraMovementOn, bool lightingOn, bool board3DOn, bool filteringOn) noexcept
Rect optionOkayRect() noexcept
Definition OptionsUI.cpp:70
std::optional< HelpButton > helpButtonHit(int x, int y) noexcept
std::optional< FileButton > fileButtonHit(int x, int y) noexcept
constexpr std::array< OptionToggle, 8 > SupportedOptionToggles
Definition OptionsUI.hpp:68
std::optional< MenuButton > menuButtonHit(int x, int y) noexcept
Definition OptionsUI.cpp:59
Rect fileButtonRect(FileButton button) noexcept
Definition OptionsUI.cpp:97
Rect helpButtonRect(HelpButton button) noexcept
bool contains(int x, int y) const noexcept
Definition OptionsUI.hpp:80