Antkeeper  0.0.1
menu-controls.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "game/controls.hpp"
21 #include "game/menu.hpp"
22 #include <engine/config.hpp>
23 
25 {
26  // Setup menu controls
27  ctx.menu_action_subscriptions.emplace_back
28  (
30  (
31  [&ctx](const auto& event)
32  {
33  --(*ctx.menu_item_index);
34  if (*ctx.menu_item_index < 0)
35  *ctx.menu_item_index = static_cast<int>(ctx.menu_item_texts.size()) - 1;
36 
37  ::menu::update_text_color(ctx);
38  }
39  )
40  );
41  ctx.menu_action_subscriptions.emplace_back
42  (
44  (
45  [&ctx](const auto& event)
46  {
47  ++(*ctx.menu_item_index);
48  if (*ctx.menu_item_index >= ctx.menu_item_texts.size())
49  *ctx.menu_item_index = 0;
50 
51  ::menu::update_text_color(ctx);
52  }
53  )
54  );
55  ctx.menu_action_subscriptions.emplace_back
56  (
58  (
59  [&ctx](const auto& event)
60  {
61  auto callback = ctx.menu_left_callbacks[*ctx.menu_item_index];
62  if (callback != nullptr)
63  callback();
64  }
65  )
66  );
67  ctx.menu_action_subscriptions.emplace_back
68  (
70  (
71  [&ctx](const auto& event)
72  {
73  auto callback = ctx.menu_right_callbacks[*ctx.menu_item_index];
74  if (callback != nullptr)
75  callback();
76  }
77  )
78  );
79  ctx.menu_action_subscriptions.emplace_back
80  (
82  (
83  [&ctx](const auto& event)
84  {
85  const auto& callback = ctx.menu_select_callbacks[*ctx.menu_item_index];
86  if (callback != nullptr)
87  callback();
88  }
89  )
90  );
91  ctx.menu_action_subscriptions.emplace_back
92  (
94  (
95  [&ctx](const auto& event)
96  {
97  if (ctx.menu_back_callback != nullptr)
98  ctx.menu_back_callback();
99  }
100  )
101  );
102 
103  // Set activation threshold for menu navigation controls to mitigate drifting gamepad axes
104  auto menu_action_threshold = [](float x) -> bool
105  {
106  return x > 0.5f;
107  };
108  ctx.menu_up_action.set_threshold_function(menu_action_threshold);
109  ctx.menu_down_action.set_threshold_function(menu_action_threshold);
110  ctx.menu_left_action.set_threshold_function(menu_action_threshold);
111  ctx.menu_right_action.set_threshold_function(menu_action_threshold);
112 }
113 
115 {
116  ctx.menu_action_map.enable();
117 
118  // Function to select menu item at mouse position
119  auto select_menu_item = [&ctx](const math::fvec2& mouse_position) -> bool
120  {
121  const float padding = config::menu_mouseover_padding * ctx.menu_font.get_font_metrics().size;
122 
123  for (std::size_t i = 0; i < ctx.menu_item_texts.size(); ++i)
124  {
125  auto [name, value] = ctx.menu_item_texts[i];
126 
127  const auto& name_bounds = name->get_bounds();
128  float min_x = name_bounds.min.x();
129  float min_y = name_bounds.min.y();
130  float max_x = name_bounds.max.x();
131  float max_y = name_bounds.max.y();
132 
133  if (value)
134  {
135  const auto& value_bounds = value->get_bounds();
136  min_x = std::min<float>(min_x, value_bounds.min.x());
137  min_y = std::min<float>(min_y, value_bounds.min.y());
138  max_x = std::max<float>(max_x, value_bounds.max.x());
139  max_y = std::max<float>(max_y, value_bounds.max.y());
140  }
141 
142  min_x -= padding;
143  min_y -= padding;
144  max_x += padding;
145  max_y += padding;
146 
147  const auto& viewport = ctx.window->get_viewport_size();
148  const float x = mouse_position.x();
149  const float y = static_cast<float>((viewport[1] - mouse_position.y() + 1));
150 
151  if (x >= min_x && x <= max_x)
152  {
153  if (y >= min_y && y <= max_y)
154  {
155  *ctx.menu_item_index = static_cast<int>(i);
157  return true;
158  }
159  }
160  }
161 
162  return false;
163  };
164 
165  // Enable menu mouse tracking
166  ctx.menu_mouse_subscriptions.clear();
167  ctx.menu_mouse_subscriptions.emplace_back
168  (
169  ctx.input_manager->get_event_dispatcher().subscribe<input::mouse_moved_event>
170  (
171  [&ctx, select_menu_item](const auto& event)
172  {
173  // Select menu item at mouse position (if any)
174  select_menu_item(math::fvec2(event.position));
175  }
176  )
177  );
178  ctx.menu_mouse_subscriptions.emplace_back
179  (
180  ctx.input_manager->get_event_dispatcher().subscribe<input::mouse_button_pressed_event>
181  (
182  [&ctx, select_menu_item](const auto& event)
183  {
184  // Select menu item at mouse position (if any)
185  if (select_menu_item(math::fvec2(event.position)))
186  {
187  // Determine appropriate menu item callback
188  auto callback = ctx.menu_select_callbacks[*ctx.menu_item_index];
189  if (event.button == input::mouse_button::left)
190  {
191  if (ctx.menu_left_callbacks[*ctx.menu_item_index])
192  {
193  callback = ctx.menu_left_callbacks[*ctx.menu_item_index];
194  }
195  }
196  else if (event.button == input::mouse_button::right)
197  {
198  if (ctx.menu_right_callbacks[*ctx.menu_item_index])
199  {
200  callback = ctx.menu_right_callbacks[*ctx.menu_item_index];
201  }
202  }
203 
204  // Invoke menu item callback
205  if (callback)
206  {
207  callback();
208  }
209  }
210  }
211  )
212  );
213 }
214 
216 {
217  ctx.menu_action_map.disable();
218  ctx.menu_up_action.reset();
219  ctx.menu_down_action.reset();
220  ctx.menu_left_action.reset();
221  ctx.menu_right_action.reset();
223  ctx.menu_back_action.reset();
225 
226  ctx.menu_mouse_subscriptions.clear();
227 }
Definition: game.hpp:121
std::vector< std::shared_ptr<::event::subscription > > menu_mouse_subscriptions
Definition: game.hpp:268
input::action menu_modifier_action
Definition: game.hpp:211
input::action menu_left_action
Definition: game.hpp:207
input::action menu_up_action
Definition: game.hpp:205
type::bitmap_font menu_font
Definition: game.hpp:188
input::action menu_back_action
Definition: game.hpp:210
input::action menu_select_action
Definition: game.hpp:209
std::vector< std::shared_ptr<::event::subscription > > menu_action_subscriptions
Definition: game.hpp:267
std::vector< std::tuple< scene::text *, scene::text * > > menu_item_texts
Definition: game.hpp:351
std::shared_ptr< app::window > window
Definition: game.hpp:166
input::action_map menu_action_map
Definition: game.hpp:204
input::action menu_down_action
Definition: game.hpp:206
input::action menu_right_action
Definition: game.hpp:208
std::unique_ptr< app::input_manager > input_manager
Definition: game.hpp:172
int * menu_item_index
Definition: game.hpp:353
void disable()
Disables the mapping of input events to actions.
Definition: action-map.cpp:41
void enable()
Enables the mapping of input events to actions.
Definition: action-map.cpp:28
void reset() noexcept
Resets the activation state of the action without publishing any events.
Definition: action.cpp:75
void set_threshold_function(const threshold_function_type &function) noexcept
Sets the threshold function.
Definition: action.hpp:50
::event::channel< action_activated_event > & get_activated_channel() noexcept
Returns the channel through which action activated events are published.
Definition: action.hpp:91
const font_metrics & get_font_metrics() const
Returns metrics describing the font.
Definition: font.hpp:109
void enable_menu_controls(::game &ctx)
void disable_menu_controls(::game &ctx)
void setup_menu_controls(::game &ctx)
Publish-subscribe messaging.
Definition: channel.hpp:32
void update_text_color(::game &ctx)
Definition: menu.cpp:59
Event generated when a mouse button has been pressed.
Event generated when a mouse has been moved.
n-dimensional vector.
Definition: vector.hpp:44
float size
Vertical size of the font.