aboutsummaryrefslogtreecommitdiff
path: root/src/client/window/window.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/window/window.cc')
-rw-r--r--src/client/window/window.cc318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/client/window/window.cc b/src/client/window/window.cc
new file mode 100644
index 0000000..648997f
--- /dev/null
+++ b/src/client/window/window.cc
@@ -0,0 +1,318 @@
+#include "window.hh"
+
+namespace client {
+namespace window {
+
+// TODO
+
+// Sliders are for numerical values of some type T.
+// TODO
+/*
+template <typename T>
+class slider_window : public basic_window {
+protected:
+ std::string name;
+ T min;
+ T cur;
+ T max;
+ T& var;
+
+private:
+ void handle_mousebuttondown(const SDL_Event& event) noexcept {}
+ void handle_mousebuttonup(const SDL_Event& event) noexcept {}
+
+public:
+ template <typename... Args>
+ slider_window(const std::string_view name, const T& min, const T& cur,
+ const T& max, T& var, Args&&... args) noexcept
+ : basic_window(std::forward<Args>(args)...), name(name), min(min),
+ cur(cur), max(max), var(var) {}
+
+ // slider_window(
+ virtual bool maybe_handle_event(const SDL_Event& event) noexcept
+override { switch (event.type) { case SDL_MOUSEBUTTONDOWN:
+ this->handle_mousebuttondown(event);
+ return true;
+ case SDL_MOUSEBUTTONUP:
+ this->handle_mousebuttonup(event);
+ return true;
+ }
+ return basic_window::maybe_handle_event(event);
+ }
+ virtual void draw() noexcept override { basic_window::draw(); }
+};
+*/
+
+static void handle_event(const SDL_Event& event) noexcept; // ignore
+
+static hud_window& get_hud_window() noexcept {
+ static hud_window ret = []() {
+ const auto& window = client::render::get_window_size();
+ const float size = std::min(static_cast<float>(window.x) / 2.0f,
+ static_cast<float>(window.y) / 2.0f);
+ client::window::hud_window ret{size};
+ return ret;
+ }();
+ return ret;
+}
+
+// All dynamic windows go in this list!
+using layer = std::forward_list<std::unique_ptr<basic_window>>;
+using layers = std::forward_list<layer>;
+static layers& get_layers() noexcept {
+ // We callbacks for our window manager are initialised here too.
+ static layers ret = []() -> layers {
+ client::input::register_event_handler(&handle_event);
+ client::input::set_text_input(false);
+ client::input::set_mouse_relative(true);
+ return {};
+ }();
+ return ret;
+}
+
+void pop_window() noexcept {
+ if (!get_layers().empty()) {
+ get_layers().pop_front();
+ }
+ // Our windows might be empty here, so set our mouse mode accordingly.
+ if (!client::window::is_open()) {
+ client::input::set_mouse_relative(true);
+ }
+}
+
+// Constants used for uniform ui sizes.
+constexpr glm::vec2 lsize_extent{0.4, 0.075};
+constexpr glm::vec2 ssize_extent{0.15, 0.075};
+
+static void center_mouse_position() noexcept {
+ const glm::vec2& window = client::render::get_window_size();
+ client::input::set_mouse_position({window.x / 2.0f, window.y / 2.0f});
+}
+
+template <typename T, typename... Args>
+void push_window(Args&&... args) noexcept {
+ get_layers().front().push_front(
+ std::make_unique<T>(std::forward<Args>(args)...));
+}
+
+constexpr glm::vec2 center_extent(const glm::vec2 pos,
+ const glm::vec2 size) noexcept {
+ return {pos.x, pos.y - size.y / 2.0f};
+}
+
+static void make_options_menu() noexcept {
+ get_layers().push_front({});
+
+ /*
+ push_window<::slider_window<float>>(
+ "Field of Vision", 0.0f,
+ settings::get(std::make_pair("gameplay", "fov"), 100.0f), 145.0f,
+ pop_window,
+ client::draw::relative_arg{.extent =
+ center_extent({0.3, 0.7},
+ lsize_extent)}, client::draw::relative_arg{.extent = lsize_extent});
+ */
+
+ push_window<button_window>(
+ "Back", pop_window,
+ client::render::relative_arg{
+ .extent = center_extent({0.3, 0.3}, ssize_extent)},
+ client::render::relative_arg{.extent = ssize_extent});
+}
+
+static void make_main_menu() noexcept {
+ get_layers().push_front({});
+
+ push_window<button_window>(
+ "Return to Game", pop_window,
+ client::render::relative_arg{
+ .extent = center_extent({0.3, 0.7}, lsize_extent)},
+ client::render::relative_arg{.extent = lsize_extent});
+
+ push_window<button_window>(
+ "Options", make_options_menu,
+ client::render::relative_arg{
+ .extent = center_extent({0.55, 0.6}, ssize_extent)},
+ client::render::relative_arg{.extent = ssize_extent});
+
+ push_window<button_window>(
+ "?", pop_window,
+ client::render::relative_arg{
+ .extent = center_extent({0.55, 0.5}, ssize_extent)},
+ client::render::relative_arg{.extent = ssize_extent});
+
+ push_window<button_window>(
+ "?", pop_window,
+ client::render::relative_arg{
+ .extent = center_extent({0.55, 0.4}, ssize_extent)},
+ client::render::relative_arg{.extent = ssize_extent});
+
+ push_window<button_window>(
+ "Exit Game", [] { shared::should_exit = true; },
+ client::render::relative_arg{
+ .extent = center_extent({0.3, 0.3}, lsize_extent)},
+ client::render::relative_arg{.extent = lsize_extent});
+
+ client::input::set_mouse_relative(false);
+ center_mouse_position();
+}
+
+static void make_chat_window() noexcept {
+ get_layers().push_front({});
+
+ push_window<text_input_window>(
+ client::render::relative_arg{
+ .extent = center_extent({0.3, 0.3}, lsize_extent)},
+ client::render::relative_arg{.extent = lsize_extent});
+
+ client::input::set_mouse_relative(false);
+ center_mouse_position();
+}
+
+static void make_inventory_window() noexcept {
+ get_layers().push_front({});
+
+ const glm::vec2& window = client::render::get_window_size();
+
+ const float size = std::min(window.x / 2.0f, window.y / 2.0f);
+ const glm::vec2 pos{(window - size) / 2.0f};
+
+ push_window<inventory_window>(
+ client::render::relative_arg{.offset = pos},
+ client::render::relative_arg{.offset = glm::vec2{size, size}});
+ client::input::set_mouse_relative(false);
+ center_mouse_position();
+}
+
+static void handle_meta_return() noexcept {
+ if (!is_open()) {
+ make_chat_window();
+ return;
+ }
+}
+
+static void handle_meta_escape() noexcept {
+ if (!is_open()) {
+ make_main_menu();
+ return;
+ }
+
+ pop_window();
+}
+
+static void handle_meta_e() noexcept {
+ if (!is_open()) {
+ make_inventory_window();
+ return;
+ }
+
+ // The inventory window must be open.
+ if (!dynamic_cast<inventory_window*>(&*get_layers().front().front())) {
+ return;
+ }
+
+ pop_window();
+}
+
+static void handle_meta_keydown(const SDL_Event& event) noexcept {
+ if (event.key.repeat) { // only handle keypresses
+ return;
+ }
+
+ switch (event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ handle_meta_escape();
+ break;
+ case SDLK_RETURN:
+ handle_meta_return();
+ break;
+ case SDLK_e:
+ handle_meta_e();
+ break;
+ case SDLK_0:
+ case SDLK_1:
+ case SDLK_2:
+ case SDLK_3:
+ case SDLK_4:
+ case SDLK_5:
+ case SDLK_6:
+ case SDLK_7:
+ case SDLK_8:
+ case SDLK_9:
+ get_hud_window().maybe_handle_event(event);
+ default:
+ break;
+ }
+}
+
+static void handle_meta_mousemotion(const SDL_Event& event) noexcept {
+ // We convert SDL's weird coordinates into useful ones (0,0 = bottom
+ // left).
+ client::input::state.mouse_pos = {
+ event.motion.x,
+ static_cast<int>(client::render::get_window_size().y) - event.motion.y};
+}
+
+static void handle_meta_windowevent(const SDL_Event& event) noexcept {
+ if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
+ if (!is_open()) {
+ make_main_menu();
+ return;
+ }
+ }
+}
+
+static void handle_meta_event(const SDL_Event& event) noexcept {
+ switch (event.type) {
+ case SDL_KEYDOWN:
+ handle_meta_keydown(event);
+ break;
+ case SDL_MOUSEMOTION:
+ handle_meta_mousemotion(event);
+ break;
+ case SDL_WINDOWEVENT:
+ handle_meta_windowevent(event);
+ break;
+ }
+}
+
+static void handle_event(const SDL_Event& event) noexcept {
+ // We ALWAYS update our mouse position.
+ if (event.type == SDL_MOUSEMOTION) {
+ handle_meta_mousemotion(event);
+ }
+
+ // Either a window consumes our event, or no window does - so we send
+ // the event to our "meta handler" which does things like closing
+ // windows etc.
+ if (is_open()) {
+ for (const auto& window : get_layers().front()) {
+ if (window->maybe_handle_event(event)) {
+ return;
+ }
+ }
+ }
+
+ handle_meta_event(event);
+}
+
+void draw() noexcept {
+ if (!is_open()) {
+
+ if (!client::input::is_key_toggled(SDLK_F1)) {
+ get_hud_window().draw();
+ }
+
+ return;
+ }
+
+ client::render::draw_colour({0.0f, 0.0f, 0.0f, 0.10f}); // very light shade
+ for (const auto& window : get_layers().front()) {
+ window->draw();
+ }
+}
+
+bool is_open() noexcept { return !get_layers().empty(); }
+
+} // namespace window
+} // namespace client