From 30b4364c772114303d9045677186a53855ea5343 Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Thu, 6 Feb 2025 16:28:39 +0100 Subject: implement in-game popups --- lib/nes/app/ui/CMakeLists.txt | 6 +++- lib/nes/app/ui/screen-confirm-quit.cc | 68 +++++++++++++++++++++++++++++++++++ lib/nes/app/ui/screen-confirm-quit.hh | 24 +++++++++++++ lib/nes/app/ui/screen-error.cc | 7 ++-- lib/nes/app/ui/screen-error.hh | 7 ++-- lib/nes/app/ui/screen-freeze.cc | 33 +++++++++++++++++ lib/nes/app/ui/screen-freeze.hh | 25 +++++++++++++ 7 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 lib/nes/app/ui/screen-confirm-quit.cc create mode 100644 lib/nes/app/ui/screen-confirm-quit.hh create mode 100644 lib/nes/app/ui/screen-freeze.cc create mode 100644 lib/nes/app/ui/screen-freeze.hh (limited to 'lib/nes/app/ui') diff --git a/lib/nes/app/ui/CMakeLists.txt b/lib/nes/app/ui/CMakeLists.txt index de42744..37720c1 100644 --- a/lib/nes/app/ui/CMakeLists.txt +++ b/lib/nes/app/ui/CMakeLists.txt @@ -7,5 +7,9 @@ target_sources( screen-title.cc screen-browser.hh screen-browser.cc + screen-freeze.hh + screen-freeze.cc screen-error.hh - screen-error.cc) \ No newline at end of file + screen-error.cc + screen-confirm-quit.hh + screen-confirm-quit.cc) \ No newline at end of file diff --git a/lib/nes/app/ui/screen-confirm-quit.cc b/lib/nes/app/ui/screen-confirm-quit.cc new file mode 100644 index 0000000..3c7a337 --- /dev/null +++ b/lib/nes/app/ui/screen-confirm-quit.cc @@ -0,0 +1,68 @@ +#include "nes/app/ui/screen-confirm-quit.hh" +#include "nes/app/graphics/renderer.hh" +#include "nes/app/graphics/color.hh" +#include "nes/app/input/input-device-keyboard.hh" + +namespace nes::app +{ + screen_confirm_quit::screen_confirm_quit(input_device_keyboard& keyboard) + : keyboard_{ keyboard } + { + } + + auto screen_confirm_quit::render(renderer& renderer) -> void + { + renderer.render_rect(2, 8, 28, 10, color::background_secondary); + renderer.render_border(2, 8, 28, 10, color::foreground_primary); + + auto const attrs = text_attributes{} + .set_alignment(text_alignment::center) + .set_ellipsize_mode(ellipsize_mode::end) + .set_max_width(26); + renderer.render_text(16, 10, "Are you sure?", color::foreground_primary, attrs); + renderer.render_text(16, 12, "All progress is lost.", color::foreground_primary, attrs); + if (confirm_) + { + renderer.render_text(10, 15, "Cancel", color::foreground_secondary); + renderer.render_text(18, 15, "> OK <", color::accent_primary); + } + else + { + renderer.render_text(8, 15, "> Cancel <", color::accent_primary); + renderer.render_text(20, 15, "OK", color::foreground_secondary); + } + } + + auto screen_confirm_quit::process_events() -> action + { + while (auto const event = keyboard_.poll_event()) + { + // Use key-up so the enter key is not immediately captured by the game. + if (event == input_event::key_up(key::enter)) + { + if (confirm_) + { + return action::confirm_quit(); + } + else + { + return action::cancel_quit(); + } + } + else if (event == input_event::key_down(key::space)) + { + confirm_ = !confirm_; + } + else if (event == input_event::key_down(key::arrow_left)) + { + confirm_ = false; + } + else if (event == input_event::key_down(key::arrow_right)) + { + confirm_ = true; + } + } + + return action{}; + } +} // namespace nes::app \ No newline at end of file diff --git a/lib/nes/app/ui/screen-confirm-quit.hh b/lib/nes/app/ui/screen-confirm-quit.hh new file mode 100644 index 0000000..c176f4b --- /dev/null +++ b/lib/nes/app/ui/screen-confirm-quit.hh @@ -0,0 +1,24 @@ +#pragma once + +#include "nes/app/ui/screen.hh" + +namespace nes::app +{ + class input_device_keyboard; + + /// A popup asking the user if they really want to quit the game. + class screen_confirm_quit final : public screen + { + input_device_keyboard& keyboard_; + bool confirm_{ false }; + + public: + explicit screen_confirm_quit(input_device_keyboard&); + + auto get_confirm() const -> bool { return confirm_; } + auto set_confirm(bool const v) -> void { confirm_ = v; } + + auto render(renderer&) -> void override; + auto process_events() -> action override; + }; +} // namespace nes::app \ No newline at end of file diff --git a/lib/nes/app/ui/screen-error.cc b/lib/nes/app/ui/screen-error.cc index 67a3244..9375012 100644 --- a/lib/nes/app/ui/screen-error.cc +++ b/lib/nes/app/ui/screen-error.cc @@ -12,8 +12,8 @@ namespace nes::app auto screen_error::render(renderer& renderer) -> void { - // TODO: Nicer box - renderer.render_rect(2, 9, 28, 5, color::background_secondary); + renderer.render_rect(2, 8, 28, 10, color::background_secondary); + renderer.render_border(2, 8, 28, 10, color::foreground_primary); auto const attrs = text_attributes{} .set_alignment(text_alignment::center) @@ -21,6 +21,7 @@ namespace nes::app .set_max_width(26); renderer.render_text_format(16, 10, color::foreground_primary, attrs, "{}:", message_); renderer.render_text(16, 12, to_string(error_), color::foreground_primary, attrs); + renderer.render_text(16, 15, "> OK <", color::accent_primary, attrs); } auto screen_error::process_events() -> action @@ -29,7 +30,7 @@ namespace nes::app { if (event == input_event::key_down(key::enter)) { - return action::close_popup(); + return action_; } } diff --git a/lib/nes/app/ui/screen-error.hh b/lib/nes/app/ui/screen-error.hh index ec877e1..4559942 100644 --- a/lib/nes/app/ui/screen-error.hh +++ b/lib/nes/app/ui/screen-error.hh @@ -12,14 +12,17 @@ namespace nes::app input_device_keyboard& keyboard_; std::string_view message_; status error_{ status::success }; + action action_{}; public: explicit screen_error(input_device_keyboard&); auto get_message() const -> std::string_view { return message_; } auto get_error() const -> status { return error_; } - auto set_message(std::string_view const v) { message_ = v; } - auto set_error(status const v) { error_ = v; } + auto get_action() const -> action { return action_; } + auto set_message(std::string_view const v) -> void { message_ = v; } + auto set_error(status const v) -> void { error_ = v; } + auto set_action(action const& v) -> void { action_ = v; } auto render(renderer&) -> void override; auto process_events() -> action override; diff --git a/lib/nes/app/ui/screen-freeze.cc b/lib/nes/app/ui/screen-freeze.cc new file mode 100644 index 0000000..60410dd --- /dev/null +++ b/lib/nes/app/ui/screen-freeze.cc @@ -0,0 +1,33 @@ +#include "nes/app/ui/screen-freeze.hh" +#include "nes/app/graphics/renderer.hh" + +namespace nes::app +{ + auto screen_freeze::freeze(display const& disp) -> void + { + for (auto y = u32{ 0 }; y < display::height; ++y) + { + for (auto x = u32{ 0 }; x < display::width; ++x) + { + frozen_data_[y * display::width + x] = disp.get(x, y); + } + } + } + + auto screen_freeze::render(renderer& renderer) -> void + { + auto& disp = renderer.get_display(); + for (auto y = u32{ 0 }; y < display::height; ++y) + { + for (auto x = u32{ 0 }; x < display::width; ++x) + { + disp.set(x, y, frozen_data_[y * display::width + x]); + } + } + } + + auto screen_freeze::process_events() -> action + { + return action{}; + } +} // namespace nes::app \ No newline at end of file diff --git a/lib/nes/app/ui/screen-freeze.hh b/lib/nes/app/ui/screen-freeze.hh new file mode 100644 index 0000000..fe67aad --- /dev/null +++ b/lib/nes/app/ui/screen-freeze.hh @@ -0,0 +1,25 @@ +#pragma once + +#include "nes/app/ui/screen.hh" +#include "nes/common/rgb.hh" +#include "nes/common/display.hh" + +namespace nes::app +{ + /// Freeze screen which preserves the display buffer at a certain state. + /// + /// This is usually used to preserve the image from the console when the game should not continue. + class screen_freeze final : public screen + { + rgb frozen_data_[display::width * display::height]{}; + + public: + explicit screen_freeze() = default; + + auto render(renderer&) -> void override; + auto process_events() -> action override; + + /// Update the image shown to the back buffer of the given display. + auto freeze(display const&) -> void; + }; +} // namespace nes::app \ No newline at end of file -- cgit v1.3.1