Skip to main content

MenuDisplaySystem.ixx File

System for controlling menu visibility based on game state. More...

Included Headers

Namespaces Index

namespacehelios
namespaceengine

Main engine module aggregating core infrastructure and game systems. More...

namespacemodules

Domain-specific components and systems. More...

namespaceui

User interface components and systems for game entities. More...

namespacewidgets

UI widget components and systems. More...

namespacesystems

UI widget processing systems. More...

Classes Index

classMenuDisplaySystem<StateLft, StateRgt>

Controls menu visibility based on game and match state. More...

Description

System for controlling menu visibility based on game state.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file MenuDisplaySystem.ixx
3 * @brief System for controlling menu visibility based on game state.
4 */
5module;
6
7#include <iostream>
8#include <algorithm>
9#include <vector>
10#include <cassert>
11#include <helios/helios_config.h>
12
13
14export module helios.engine.modules.ui.widgets.systems.MenuDisplaySystem;
15
16import helios.engine.ecs;
17import helios.engine.runtime.world;
18import helios.engine.modules.ui.widgets.types.MenuId;
19
20import helios.engine.modules.ui.widgets.components.UiFocusComponent;
21
22import helios.engine.modules.ui.widgets.components.MenuComponent;
23
24import helios.engine.state.CombinedStateToIdMapPair;
25
26import helios.engine.mechanics.gamestate.types;
27import helios.engine.mechanics.match.types;
28
29import helios.engine.modules.rendering.model.components.ModelAabbComponent;
30import helios.math;
31
33using namespace helios::engine::state;
36using namespace helios::engine::ecs;
39
40import helios.engine.common.tags.SystemRole;
41
43
44 /**
45 * @brief Controls menu visibility based on game and match state.
46 *
47 * @details Uses a CombinedStateToIdMapPair to determine which menus
48 * should be active for the current state combination. Automatically
49 * shows/hides menus and manages focus when states change.
50 *
51 * ## Behavior
52 *
53 * - Menus not associated with the current state are hidden
54 * - Menus associated with the current state are shown
55 * - When no item has focus, the first menu's default item is focused
56 * - Inactive focused items have their UiFocusComponent removed
57 *
58 * @see CombinedStateToIdMapPair
59 * @see MenuComponent
60 * @see MenuNavigationSystem
61 */
62 template<typename StateLft, typename StateRgt>
64
65
66 /**
67 * @brief Previously active menu IDs for change detection.
68 */
69 std::vector<MenuId> prevMenuIds_;
70
71 /**
72 * @brief Policy mapping states to menu IDs.
73 */
75
76 /**
77 * @brief Cache for inactive focused items to be cleaned up.
78 */
79 std::vector<GameObject> inactiveItems_;
80
81 /**
82 * @brief Shows or hides a menu by ID.
83 *
84 * @param menuId The menu to show/hide.
85 * @param show True to show, false to hide.
86 * @param components View of all MenuComponent entities.
87 */
88 void showMenu(const MenuId menuId, const bool show, View<MenuComponent>& components) {
89 for (auto [entity, mc] : components) {
90 if (mc->menuId() == menuId) {
91 entity.setActive(show);
92 }
93 }
94 }
95
96 protected:
97 /**
98 * @brief Focuses the first item of a menu.
99 *
100 * @param menuId The menu to focus.
101 * @param components View of all MenuComponent entities.
102 */
104 for (auto [entity, mc] : components) {
105 if (mc->menuId() == menuId) {
106 mc->selectDefaultIndex();
107
108 if (mc->menuItems().size() > mc->selectedIndex()) {
109 auto menuItem = updateContext.find(mc->menuItems()[mc->selectedIndex()]);
110 menuItem->getOrAdd<UiFocusComponent>();
111 }
112 break;
113 }
114 }
115 }
116
117
118 public:
119
121
122
123 /**
124 * @brief Constructs the system with a state-to-menu policy.
125 *
126 * @param stateToMenuMap Policy mapping game/match states to menu IDs.
127 */
129 : stateToMenuMap_(std::move(stateToMenuMap)) {
130
131 inactiveItems_.reserve(INACTIVE_FOCUSED_ITEMS_CACHE_CAPACITY);
132 }
133
134 /**
135 * @brief Updates menu visibility based on current state.
136 *
137 * @details Queries the current game and match state, then:
138 * 1 Hides menus that are no longer active
139 * 2 Shows menus for the current state
140 * 3 Ensures at least one menu item has focus
141 *
142 * @param updateContext The current frame's update context.
143 */
145
146
147 auto& session = updateContext.session();
148
149 auto gameState = session.state<StateLft>();
150 auto matchState = session.state<StateRgt>();
151
152 auto menuIds = stateToMenuMap_.ids(gameState, matchState);
153
154 if (menuIds.empty() && prevMenuIds_.empty()) {
155 return;
156 }
157
158 View<MenuComponent> components = updateContext.view<MenuComponent>().whereEnabled();
159
160
161 for (auto& prevMenuId : prevMenuIds_) {
162 if (std::ranges::find(menuIds, prevMenuId) == menuIds.end()) {
163 showMenu(prevMenuId, false, components);
164 }
165 }
166
167 prevMenuIds_.assign(menuIds.begin(), menuIds.end());
168 for (auto& menuId : menuIds) {
169 showMenu(menuId, true,components);
170 }
171
172 if (menuIds.empty()) {
173 return;
174 }
175
176
177 bool hasFocus = false;
178 inactiveItems_.clear();
179
180 for (auto [entity, fc] : updateContext.view<UiFocusComponent>().whereEnabled()) {
181
182 /**
183 * @todo Check if item is child element of menu?
184 */
185 if (entity.isActive()) {
186 hasFocus = true;
187 break;
188 }
189
190 /**
191 * @todo guaranteee that the UiFocusComponent is exclusive,
192 * break here if first comp with focus was found.
193 */
194 inactiveItems_.push_back(entity);
195 }
196
197 for (auto& item : inactiveItems_) {
198 item.remove<UiFocusComponent>();
199 }
200
201 // focus an item from the first menu
202 if (!hasFocus) {
203 focusMenu(updateContext, menuIds[0], components);
204 }
205
206 }
207
208 };
209
210}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.