From 92e9a75ffa9b7275acd9ee791be020540814d338 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Thu, 21 Dec 2023 00:08:14 +0100 Subject: [PATCH] Platform: Add MessageBox --- include/Nazara/Platform.hpp | 1 + include/Nazara/Platform/Enums.hpp | 39 +++++++++++ include/Nazara/Platform/MessageBox.hpp | 79 +++++++++++++++++++++ include/Nazara/Platform/MessageBox.inl | 70 +++++++++++++++++++ include/Nazara/Platform/Window.hpp | 1 + src/Nazara/Platform/MessageBox.cpp | 97 ++++++++++++++++++++++++++ 6 files changed, 287 insertions(+) create mode 100644 include/Nazara/Platform/MessageBox.hpp create mode 100644 include/Nazara/Platform/MessageBox.inl create mode 100644 src/Nazara/Platform/MessageBox.cpp diff --git a/include/Nazara/Platform.hpp b/include/Nazara/Platform.hpp index 70e5b29db..b76bb2152 100644 --- a/include/Nazara/Platform.hpp +++ b/include/Nazara/Platform.hpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Platform/Enums.hpp b/include/Nazara/Platform/Enums.hpp index 9e9e41225..25670a3d7 100644 --- a/include/Nazara/Platform/Enums.hpp +++ b/include/Nazara/Platform/Enums.hpp @@ -20,6 +20,45 @@ namespace Nz Max = Text }; + enum class MessageBoxButtonRole + { + Accept, + None, + Reject, + + Max = Reject + }; + + enum class MessageBoxType + { + Info, + Error, + Warning, + + Max = Warning + }; + + enum class MessageBoxStandardButton + { + Abort, + Apply, + Cancel, + Close, + Discard, + Ignore, + No, + NoToAll, + Ok, + Reset, + Retry, + Save, + SaveAll, + Yes, + YesToAll, + + Max = YesToAll + }; + enum class SystemCursor { Crosshair, diff --git a/include/Nazara/Platform/MessageBox.hpp b/include/Nazara/Platform/MessageBox.hpp new file mode 100644 index 000000000..955ed7551 --- /dev/null +++ b/include/Nazara/Platform/MessageBox.hpp @@ -0,0 +1,79 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PLATFORM_MESSAGEBOX_HPP +#define NAZARA_PLATFORM_MESSAGEBOX_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class Window; + + class NAZARA_PLATFORM_API MessageBox + { + public: + struct ColorScheme; + + inline MessageBox(MessageBoxType type, std::string title, std::string message); + MessageBox(const MessageBox&) = delete; + MessageBox(MessageBox&&) = delete; + ~MessageBox() = default; + + inline void AddButton(int id, std::string text, MessageBoxButtonRole role = MessageBoxButtonRole::None); + void AddButton(int id, MessageBoxStandardButton standardButton); + + inline const ColorScheme* GetColorSchemeOverride() const; + inline const std::string& GetMessage() const; + inline const std::string& GetTitle() const; + + inline void OverrideColorScheme(const ColorScheme& colorScheme); + + inline void ResetColorScheme(); + + Result Show(Window* parent = nullptr) const; + + inline void UpdateMessage(std::string message); + inline void UpdateTitle(std::string title); + inline void UpdateType(MessageBoxType type); + + MessageBox& operator=(const MessageBox&) = delete; + MessageBox& operator=(MessageBox&&) = delete; + + struct ColorScheme + { + Color backgroundColor = Color::White(); + Color textColor = Color::Black(); + Color buttonBackgroundColor = Color::Gray(); + Color buttonBorderColor = Color::Black(); + Color buttonSelectedColor = Color::Blue(); + }; + + private: + struct ButtonData + { + MessageBoxButtonRole role; + std::string text; + int buttonId; + }; + + std::optional m_colorSchemeOverride; + std::string m_message; + std::string m_title; + std::vector m_buttons; + MessageBoxType m_type; + }; +} + +#include + +#endif // NAZARA_PLATFORM_MESSAGEBOX_HPP diff --git a/include/Nazara/Platform/MessageBox.inl b/include/Nazara/Platform/MessageBox.inl new file mode 100644 index 000000000..43a23da92 --- /dev/null +++ b/include/Nazara/Platform/MessageBox.inl @@ -0,0 +1,70 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline MessageBox::MessageBox(MessageBoxType type, std::string title, std::string message) : + m_message(std::move(message)), + m_title(std::move(title)), + m_type(type) + { + } + + inline void MessageBox::AddButton(int id, std::string text, MessageBoxButtonRole role) + { + m_buttons.push_back({ + .role = role, + .text = std::move(text), + .buttonId = id + }); + } + + inline auto MessageBox::GetColorSchemeOverride() const -> const ColorScheme* + { + if (!m_colorSchemeOverride) + return nullptr; + + return &m_colorSchemeOverride.value(); + } + + inline const std::string& MessageBox::GetMessage() const + { + return m_message; + } + + inline const std::string& Nz::MessageBox::GetTitle() const + { + return m_title; + } + + inline void MessageBox::OverrideColorScheme(const ColorScheme& colorScheme) + { + m_colorSchemeOverride = colorScheme; + } + + inline void MessageBox::ResetColorScheme() + { + m_colorSchemeOverride = std::nullopt; + } + + inline void MessageBox::UpdateMessage(std::string message) + { + m_message = std::move(message); + } + + inline void MessageBox::UpdateTitle(std::string title) + { + m_title = std::move(title); + } + + inline void MessageBox::UpdateType(MessageBoxType type) + { + m_type = type; + } +} + +#include diff --git a/include/Nazara/Platform/Window.hpp b/include/Nazara/Platform/Window.hpp index 16d509cb3..73d44024e 100644 --- a/include/Nazara/Platform/Window.hpp +++ b/include/Nazara/Platform/Window.hpp @@ -32,6 +32,7 @@ namespace Nz { friend WindowImpl; friend class InputImpl; + friend class MessageBox; friend class Mouse; friend class Platform; diff --git a/src/Nazara/Platform/MessageBox.cpp b/src/Nazara/Platform/MessageBox.cpp new file mode 100644 index 000000000..8df1474bc --- /dev/null +++ b/src/Nazara/Platform/MessageBox.cpp @@ -0,0 +1,97 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + void MessageBox::AddButton(int id, MessageBoxStandardButton standardButton) + { + struct StandardButtonData + { + std::string_view text; + MessageBoxButtonRole role; + }; + + constexpr EnumArray s_buttonTexts = { + StandardButtonData { "Abort", MessageBoxButtonRole::Reject }, // Abort + StandardButtonData { "Apply", MessageBoxButtonRole::Accept }, // Apply + StandardButtonData { "Cancel", MessageBoxButtonRole::Reject }, // Cancel + StandardButtonData { "Close", MessageBoxButtonRole::Reject }, // Close + StandardButtonData { "Discard", MessageBoxButtonRole::Reject }, // Discard + StandardButtonData { "Ignore", MessageBoxButtonRole::Reject }, // Ignore + StandardButtonData { "No", MessageBoxButtonRole::Reject }, // No + StandardButtonData { "No to all", MessageBoxButtonRole::Reject }, // NoToAll + StandardButtonData { "Ok", MessageBoxButtonRole::Accept }, // Ok + StandardButtonData { "Reset", MessageBoxButtonRole::Reject }, // Reset + StandardButtonData { "Retry", MessageBoxButtonRole::Accept }, // Retry + StandardButtonData { "Save", MessageBoxButtonRole::Accept }, // Save + StandardButtonData { "Save all", MessageBoxButtonRole::Accept }, // SaveAll + StandardButtonData { "Yes", MessageBoxButtonRole::Accept }, // Yes + StandardButtonData { "Yes to all", MessageBoxButtonRole::Accept }, // YesToAll + }; + + return AddButton(id, std::string(s_buttonTexts[standardButton].text), s_buttonTexts[standardButton].role); + } + + Result MessageBox::Show(Window* parent) const + { + constexpr EnumArray s_flags = { + SDL_MESSAGEBOX_INFORMATION, // Info + SDL_MESSAGEBOX_ERROR, // Error + SDL_MESSAGEBOX_WARNING // Warning + }; + + constexpr EnumArray s_buttonFlags = { + SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, // Accept + 0, // None + SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, // Reject + }; + + StackArray buttons = NazaraStackArrayNoInit(SDL_MessageBoxButtonData, m_buttons.size()); + + SDL_MessageBoxButtonData* buttonPtr = buttons.data(); + for (const ButtonData& buttonData : m_buttons) + { + buttonPtr->buttonid = buttonData.buttonId; + buttonPtr->flags = s_buttonFlags[buttonData.role]; + buttonPtr->text = buttonData.text.c_str(); + + buttonPtr++; + } + + SDL_MessageBoxColorScheme colorScheme; + if (m_colorSchemeOverride) + { + Color::ToRGB8(m_colorSchemeOverride->backgroundColor, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BACKGROUND].r, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BACKGROUND].g, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BACKGROUND].b); + Color::ToRGB8(m_colorSchemeOverride->buttonBackgroundColor, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].r, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].g, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].b); + Color::ToRGB8(m_colorSchemeOverride->buttonBorderColor, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].r, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].g, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].b); + Color::ToRGB8(m_colorSchemeOverride->buttonSelectedColor, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED].r, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED].g, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED].b); + Color::ToRGB8(m_colorSchemeOverride->textColor, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_TEXT].r, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_TEXT].g, &colorScheme.colors[SDL_MESSAGEBOX_COLOR_TEXT].b); + } + + SDL_Window* window = (parent) ? static_cast(parent->GetImpl())->GetHandle() : nullptr; + + SDL_MessageBoxData messageBoxData = { + .flags = s_flags[m_type], + .window = window, + .title = m_title.c_str(), + .message = m_message.c_str(), + .numbuttons = SafeCast(m_buttons.size()), + .buttons = buttons.data(), + .colorScheme = (m_colorSchemeOverride) ? &colorScheme : nullptr + }; + + int buttonId; + if (SDL_ShowMessageBox(&messageBoxData, &buttonId) != 0) + return Err(SDL_GetError()); + + return Ok(buttonId); + } +}