From 442d2d75d71bbc057e667edc301a79fa1cc813be Mon Sep 17 00:00:00 2001 From: rtk0c Date: Sat, 27 Mar 2021 23:01:07 -0700 Subject: Initial setup --- core/src/Utils/Dialog/Dialog.cpp | 18 ++++++ core/src/Utils/Dialog/Dialog.hpp | 52 +++++++++++++++ core/src/Utils/Dialog/Dialog_linux.cpp | 83 ++++++++++++++++++++++++ core/src/Utils/Dialog/Dialog_macos.mm | 113 +++++++++++++++++++++++++++++++++ core/src/Utils/Dialog/Dialog_win32.cpp | 64 +++++++++++++++++++ core/src/Utils/Dialog/fwd.hpp | 1 + 6 files changed, 331 insertions(+) create mode 100644 core/src/Utils/Dialog/Dialog.cpp create mode 100644 core/src/Utils/Dialog/Dialog.hpp create mode 100644 core/src/Utils/Dialog/Dialog_linux.cpp create mode 100644 core/src/Utils/Dialog/Dialog_macos.mm create mode 100644 core/src/Utils/Dialog/Dialog_win32.cpp create mode 100644 core/src/Utils/Dialog/fwd.hpp (limited to 'core/src/Utils/Dialog') diff --git a/core/src/Utils/Dialog/Dialog.cpp b/core/src/Utils/Dialog/Dialog.cpp new file mode 100644 index 0000000..c4459c0 --- /dev/null +++ b/core/src/Utils/Dialog/Dialog.cpp @@ -0,0 +1,18 @@ +// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/include/boxer/boxer.h +#include "Dialog.hpp" + +namespace Dialog { + +Selection Show(const char* message, const char* title, Style style) { + return Show(message, title, style, kDefaultButtons); +} + +Selection Show(const char* message, const char* title, Buttons buttons) { + return Show(message, title, kDefaultStyle, buttons); +} + +Selection Show(const char* message, const char* title) { + return Show(message, title, kDefaultStyle, kDefaultButtons); +} + +} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog.hpp b/core/src/Utils/Dialog/Dialog.hpp new file mode 100644 index 0000000..e8989e3 --- /dev/null +++ b/core/src/Utils/Dialog/Dialog.hpp @@ -0,0 +1,52 @@ +// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/include/boxer/boxer.h +#pragma once + +namespace Dialog { + +/// Options for styles to apply to a message box. +enum class Style { + Info, + Warning, + Error, + Question, +}; + +/// Options for buttons to provide on a message box. +enum class Buttons { + OK, + OKCancel, + YesNo, + Quit, +}; + +/// Possible responses from a message box. 'None' signifies that no option was chosen, and 'Error' signifies that an +/// error was encountered while creating the message box. +enum class Selection { + OK, + Cancel, + Yes, + No, + Quit, + None, + Error, +}; + +/// The default style to apply to a message box. +constexpr Style kDefaultStyle = Style::Info; + +/// The default buttons to provide on a message box. +constexpr Buttons kDefaultButtons = Buttons::OK; + +/// Blocking call to create a modal message box with the given message, title, style, and buttons. +Selection Show(const char* message, const char* title, Style style, Buttons buttons); + +/// Convenience function to call show() with the default buttons. +Selection Show(const char* message, const char* title, Style style); + +/// Convenience function to call show() with the default style. +Selection Show(const char* message, const char* title, Buttons buttons); + +/// Convenience function to call show() with the default style and buttons. +Selection Show(const char* message, const char* title); + +} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog_linux.cpp b/core/src/Utils/Dialog/Dialog_linux.cpp new file mode 100644 index 0000000..11c3cee --- /dev/null +++ b/core/src/Utils/Dialog/Dialog_linux.cpp @@ -0,0 +1,83 @@ +// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/src/boxer_linux.cpp +#include "Dialog.hpp" + +#include + +namespace Dialog { +namespace { + + GtkMessageType GetMessageType(Style style) { + switch (style) { + case Style::Info: + return GTK_MESSAGE_INFO; + case Style::Warning: + return GTK_MESSAGE_WARNING; + case Style::Error: + return GTK_MESSAGE_ERROR; + case Style::Question: + return GTK_MESSAGE_QUESTION; + default: + return GTK_MESSAGE_INFO; + } + } + + GtkButtonsType GetButtonsType(Buttons buttons) { + switch (buttons) { + case Buttons::OK: + return GTK_BUTTONS_OK; + case Buttons::OKCancel: + return GTK_BUTTONS_OK_CANCEL; + case Buttons::YesNo: + return GTK_BUTTONS_YES_NO; + case Buttons::Quit: + return GTK_BUTTONS_CLOSE; + default: + return GTK_BUTTONS_OK; + } + } + + Selection getSelection(gint response) { + switch (response) { + case GTK_RESPONSE_OK: + return Selection::OK; + case GTK_RESPONSE_CANCEL: + return Selection::Cancel; + case GTK_RESPONSE_YES: + return Selection::Yes; + case GTK_RESPONSE_NO: + return Selection::No; + case GTK_RESPONSE_CLOSE: + return Selection::Quit; + default: + return Selection::None; + } + } + +} // namespace + +Selection Show(const char* message, const char* title, Style style, Buttons buttons) { + if (!gtk_init_check(0, nullptr)) { + return Selection::Error; + } + + // Create a parent window to stop gtk_dialog_run from complaining + GtkWidget* parent = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_MODAL, + GetMessageType(style), + GetButtonsType(buttons), + "%s", + message); + gtk_window_set_title(GTK_WINDOW(dialog), title); + Selection selection = getSelection(gtk_dialog_run(GTK_DIALOG(dialog))); + + gtk_widget_destroy(GTK_WIDGET(dialog)); + gtk_widget_destroy(GTK_WIDGET(parent)); + while (g_main_context_iteration(nullptr, false)) { + // Do nothing + } + + return selection; +} +} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog_macos.mm b/core/src/Utils/Dialog/Dialog_macos.mm new file mode 100644 index 0000000..c0164a0 --- /dev/null +++ b/core/src/Utils/Dialog/Dialog_macos.mm @@ -0,0 +1,113 @@ +// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/src/boxer_osx.mm +#include "Dialog.hpp" + +#import + +namespace Dialog { +namespace { + + NSString* const kOkStr = @"OK"; + NSString* const kCancelStr = @"Cancel"; + NSString* const kYesStr = @"Yes"; + NSString* const kNoStr = @"No"; + NSString* const kQuitStr = @"Quit"; + + NSAlertStyle GetAlertStyle(Style style) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 + switch (style) { + case Style::Info: + return NSAlertStyleInformational; + case Style::Warning: + return NSAlertStyleWarning; + case Style::Error: + return NSAlertStyleCritical; + case Style::Question: + return NSAlertStyleWarning; + default: + return NSAlertStyleInformational; + } +#else + switch (style) { + case Style::Info: + return NSInformationalAlertStyle; + case Style::Warning: + return NSWarningAlertStyle; + case Style::Error: + return NSCriticalAlertStyle; + case Style::Question: + return NSWarningAlertStyle; + default: + return NSInformationalAlertStyle; + } +#endif + } + + void SetButtons(NSAlert* alert, Buttons buttons) { + switch (buttons) { + case Buttons::OK: + [alert addButtonWithTitle:kOkStr]; + break; + case Buttons::OKCancel: + [alert addButtonWithTitle:kOkStr]; + [alert addButtonWithTitle:kCancelStr]; + break; + case Buttons::YesNo: + [alert addButtonWithTitle:kYesStr]; + [alert addButtonWithTitle:kNoStr]; + break; + case Buttons::Quit: + [alert addButtonWithTitle:kQuitStr]; + break; + default: + [alert addButtonWithTitle:kOkStr]; + } + } + + Selection GetSelection(int index, Buttons buttons) { + switch (buttons) { + case Buttons::OK: + return index == NSAlertFirstButtonReturn ? Selection::OK : Selection::None; + case Buttons::OKCancel: + if (index == NSAlertFirstButtonReturn) { + return Selection::OK; + } else if (index == NSAlertSecondButtonReturn) { + return Selection::Cancel; + } else { + return Selection::None; + } + case Buttons::YesNo: + if (index == NSAlertFirstButtonReturn) { + return Selection::Yes; + } else if (index == NSAlertSecondButtonReturn) { + return Selection::No; + } else { + return Selection::None; + } + case Buttons::Quit: + return index == NSAlertFirstButtonReturn ? Selection::Quit : Selection::None; + default: + return Selection::None; + } + } + +} // namespace + +Selection show(const char* message, const char* title, Style style, Buttons buttons) { + NSAlert* alert = [[NSAlert alloc] init]; + + [alert setMessageText:[NSString stringWithCString:title encoding:[NSString defaultCStringEncoding]]]; + [alert setInformativeText:[NSString stringWithCString:message encoding:[NSString defaultCStringEncoding]]]; + + [alert setAlertStyle:GetAlertStyle(style)]; + SetButtons(alert, buttons); + + // Force the alert to appear on top of any other windows + [[alert window] setLevel:NSModalPanelWindowLevel]; + + Selection selection = GetSelection([alert runModal], buttons); + [alert release]; + + return selection; +} + +} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog_win32.cpp b/core/src/Utils/Dialog/Dialog_win32.cpp new file mode 100644 index 0000000..b82f382 --- /dev/null +++ b/core/src/Utils/Dialog/Dialog_win32.cpp @@ -0,0 +1,64 @@ +// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/src/boxer_win.cpp +#include "Dialog.hpp" + +#define WIN32_LEAN_AND_MEAN +#include + +namespace Dialog { +namespace { + + UINT GetIcon(Style style) { + switch (style) { + case Style::Info: + return MB_ICONINFORMATION; + case Style::Warning: + return MB_ICONWARNING; + case Style::Error: + return MB_ICONERROR; + case Style::Question: + return MB_ICONQUESTION; + default: + return MB_ICONINFORMATION; + } + } + + UINT GetButtons(Buttons buttons) { + switch (buttons) { + case Buttons::OK: + case Buttons::Quit: // There is no 'Quit' button on Windows :( + return MB_OK; + case Buttons::OKCancel: + return MB_OKCANCEL; + case Buttons::YesNo: + return MB_YESNO; + default: + return MB_OK; + } + } + + Selection GetSelection(int response, Buttons buttons) { + switch (response) { + case IDOK: + return buttons == Buttons::Quit ? Selection::Quit : Selection::OK; + case IDCANCEL: + return Selection::Cancel; + case IDYES: + return Selection::Yes; + case IDNO: + return Selection::No; + default: + return Selection::None; + } + } + +} // namespace + +Selection Show(const char* message, const char* title, Style style, Buttons buttons) { + UINT flags = MB_TASKMODAL; + + flags |= GetIcon(style); + flags |= GetButtons(buttons); + + return GetSelection(MessageBox(nullptr, message, title, flags), buttons); +} +} // namespace Dialog diff --git a/core/src/Utils/Dialog/fwd.hpp b/core/src/Utils/Dialog/fwd.hpp new file mode 100644 index 0000000..50e9667 --- /dev/null +++ b/core/src/Utils/Dialog/fwd.hpp @@ -0,0 +1 @@ +#pragma once -- cgit v1.2.3-70-g09d2