From 83d23eb3f4b1653b80daf9410e732848fc492ad4 Mon Sep 17 00:00:00 2001 From: Redacted Date: Wed, 29 Jan 2025 01:41:21 -0500 Subject: [PATCH] RWindow::MessageBox --- include/ReWindow/types/Window.h | 5 ++- main.cpp | 4 +- src/platform/linux/Window.cpp | 65 ++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/include/ReWindow/types/Window.h b/include/ReWindow/types/Window.h index bef1272..a728d36 100644 --- a/include/ReWindow/types/Window.h +++ b/include/ReWindow/types/Window.h @@ -200,7 +200,10 @@ public: /// Closes the window immediately, potentially without allowing finalization to occur. void ForceClose(); void ForceCloseAndTerminateProgram(); - void MessageBox(); // TODO: Must be implemented from scratch as a Motif Window in x11 + + /// Displays a small window with some text and an "OK" button. + /// @note Execution of the parent window is stopped while the message box is up. + void MessageBox(const std::string& title, const std::string& message); /// Sets whether or not to make the window fullscreen. /// @note This is implemented per-OS, and as such, it simply requests the OS to do what we want. No guarantee about follow-through can be given. diff --git a/main.cpp b/main.cpp index e259245..375720e 100644 --- a/main.cpp +++ b/main.cpp @@ -75,7 +75,7 @@ int main() { window->SetVsyncEnabled(true); window->SetResizable(true); window->SetCursorVisible(false); - + window->MessageBox("MessageBox", "Generic message from a ReWindow MessageBox."); Logger::Debug(std::format("Window '{}' flags: IN_FOCUS={} FULLSCREEN={} RESIZEABLE={} VSYNC={} QUIT={}", @@ -89,7 +89,7 @@ int main() { while (!window->IsClosing()) { window->ManagedRefresh(); - window->Flash(); + //window->Flash(); } delete window; } \ No newline at end of file diff --git a/src/platform/linux/Window.cpp b/src/platform/linux/Window.cpp index 96d7c7b..c556d2d 100644 --- a/src/platform/linux/Window.cpp +++ b/src/platform/linux/Window.cpp @@ -58,6 +58,65 @@ void RWindow::Raise() { XRaiseWindow(platform->display, platform->window); } +void RWindow::MessageBox(const std::string& window_title, const std::string& message) { + int padding = 10; + + XFontStruct* font = XLoadQueryFont(platform->display, "6x13"); + int text_width = XTextWidth(font, message.c_str(), message.size()); + int button_text_width = XTextWidth(font, "OK", 2); + IPair button_size = {80, 30}; + IPair dimensions = { std::max(text_width + 2 * padding, button_size.x + 2 * padding), 82}; + IPair text_pos = {(dimensions.x - text_width) / 2, padding + font->ascent}; + IPair button_pos = { (dimensions.x - button_size.x) / 2, text_pos.y + font->ascent + padding }; + + Window window = XCreateSimpleWindow(platform->display, RootWindow(platform->display, platform->defaultScreen), + 100, 100, dimensions.x, dimensions.y, 1, + BlackPixel(platform->display, platform->defaultScreen), + WhitePixel(platform->display, platform->defaultScreen)); + + XStoreName(platform->display, window, window_title.c_str()); + XSelectInput(platform->display, window, ExposureMask | ButtonPressMask); + + // No resizing. + XSizeHints hints; + hints.flags = PMinSize | PMaxSize; + hints.min_width = hints.max_width = dimensions.x; + hints.min_height = hints.max_height = dimensions.y; + XSetWMNormalHints(platform->display, window, &hints); + + XMapWindow(platform->display, window); + GC gc = XCreateGC(platform->display, window, 0, nullptr); + XSetForeground(platform->display, gc, BlackPixel(platform->display, platform->defaultScreen)); + + + /* TODO positioning the window to be in the center of the parent window doesn't always work. + if (platform->window) { + XWindowAttributes parent_window_attributes; + XGetWindowAttributes(platform->display, platform->window, &parent_window_attributes); + XMoveWindow(platform->display, window, (parent_window_attributes.width - dimensions.x) / 2, (parent_window_attributes.height - dimensions.y) / 2); + } + */ + + XEvent event; + while (true) { + XNextEvent(platform->display, &event); + + if (event.type == Expose) { + XDrawString(platform->display, window, gc, text_pos.x, text_pos.y, message.c_str(), message.size()); + XDrawString(platform->display, window, gc, button_pos.x + (button_size.x - button_text_width) / 2, button_pos.y + 20, "OK", 2); + XDrawRectangle(platform->display, window, gc, button_pos.x, button_pos.y, button_size.x, button_size.y); + } + + else if (event.type == ButtonPress) + if (event.xbutton.x >= button_pos.x && event.xbutton.x <= button_pos.x + button_size.x + && event.xbutton.y >= button_pos.y && event.xbutton.y <= button_pos.y + button_size.y) + break; + } + + XFreeFont(platform->display, font); + XFreeGC(platform->display, gc); + XDestroyWindow(platform->display, window); +} void RWindow::Lower() { Logger::Debug(std::format("Lowering window '{}'", this->title)); @@ -98,18 +157,14 @@ void RWindow::SetCursorVisible(bool cursor_enable) { void RWindow::SetResizable(bool sizable) { XGetWindowAttributes(platform->display, platform->window, &platform->windowAttributes); - this->resizable = sizable; - if (!sizable) - { + if (!sizable) { Logger::Debug("Once you've done this you cannot make it resizable again."); platform->hints.flags = PMinSize | PMaxSize; platform->hints.min_width = platform->hints.max_width = platform->windowAttributes.width; platform->hints.min_height = platform->hints.max_height = platform->windowAttributes.height; XSetWMNormalHints(platform->display, platform->window, &platform->hints); } - //this->SetFlag(WindowFlag::RESIZABLE, resizable); - } void RWindow::SetFlag(WindowFlag flag, bool state) {