From 44cdf1646aa604e58e70ff6b585350ffd11eeca2 Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Sat, 2 Aug 2025 13:55:01 -0500 Subject: [PATCH] New dialog presents a yes/no choice with alternate non-exclusive actions --- proj/vs2013/Common/Common.vcxproj | 4 +- proj/vs2013/Common/Common.vcxproj.filters | 8 +- proj/vs2017/Common/Common.vcxproj | 4 +- proj/vs2017/Common/Common.vcxproj.filters | 8 +- rsrc/dialogs/tiny-button-panel.xml | 16 ++++ src/dialogxml/dialogs/btnpanel.cpp | 111 ++++++++++++++++++++++ src/dialogxml/dialogs/btnpanel.hpp | 47 +++++++++ 7 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 rsrc/dialogs/tiny-button-panel.xml create mode 100644 src/dialogxml/dialogs/btnpanel.cpp create mode 100644 src/dialogxml/dialogs/btnpanel.hpp diff --git a/proj/vs2013/Common/Common.vcxproj b/proj/vs2013/Common/Common.vcxproj index 3db02b12..b9be0f8f 100644 --- a/proj/vs2013/Common/Common.vcxproj +++ b/proj/vs2013/Common/Common.vcxproj @@ -192,6 +192,7 @@ + @@ -287,6 +288,7 @@ + @@ -565,4 +567,4 @@ - + \ No newline at end of file diff --git a/proj/vs2013/Common/Common.vcxproj.filters b/proj/vs2013/Common/Common.vcxproj.filters index c435cdb1..c3281092 100644 --- a/proj/vs2013/Common/Common.vcxproj.filters +++ b/proj/vs2013/Common/Common.vcxproj.filters @@ -831,6 +831,9 @@ Scenario + + DialogXML\Dialogs + @@ -1093,8 +1096,11 @@ Tools + + DialogXML\Dialogs + - + \ No newline at end of file diff --git a/proj/vs2017/Common/Common.vcxproj b/proj/vs2017/Common/Common.vcxproj index 082b7c0b..3341613c 100644 --- a/proj/vs2017/Common/Common.vcxproj +++ b/proj/vs2017/Common/Common.vcxproj @@ -344,6 +344,7 @@ + @@ -441,6 +442,7 @@ + @@ -618,4 +620,4 @@ - + \ No newline at end of file diff --git a/proj/vs2017/Common/Common.vcxproj.filters b/proj/vs2017/Common/Common.vcxproj.filters index 30cb6bea..c55922d1 100644 --- a/proj/vs2017/Common/Common.vcxproj.filters +++ b/proj/vs2017/Common/Common.vcxproj.filters @@ -824,6 +824,9 @@ Scenario + + DialogXML\Dialogs + @@ -1079,5 +1082,8 @@ Tools + + DialogXML\Dialogs + - + \ No newline at end of file diff --git a/rsrc/dialogs/tiny-button-panel.xml b/rsrc/dialogs/tiny-button-panel.xml new file mode 100644 index 00000000..246eed58 --- /dev/null +++ b/rsrc/dialogs/tiny-button-panel.xml @@ -0,0 +1,16 @@ + + + + + Select: + + + + diff --git a/src/dialogxml/dialogs/btnpanel.cpp b/src/dialogxml/dialogs/btnpanel.cpp new file mode 100644 index 00000000..086398cb --- /dev/null +++ b/src/dialogxml/dialogs/btnpanel.cpp @@ -0,0 +1,111 @@ +#include "btnpanel.hpp" + +#include +#include + +#include +#include + +#include "dialogxml/widgets/field.hpp" +#include "dialogxml/dialogs/strdlog.hpp" +#include "fileio/resmgr/res_dialog.hpp" +#include "sounds.hpp" +#include "gfx/render_shapes.hpp" +#include "tools/cursors.hpp" + +cButtonPanel::cButtonPanel(cDialog* parent) + : dlg(*ResMgr::dialogs.get("tiny-button-panel"), parent) +{} + +cButtonPanel::cButtonPanel(const std::vector& strs, std::vector> click_handlers, std::string title, std::string ok_str, cDialog* parent) + : cButtonPanel(parent) +{ + setTitle(title); + if(!ok_str.empty()){ + dlg["done"].setText(ok_str); + } + strings = strs; + this->click_handlers = click_handlers; + attachHandlers(); +} + +void cButtonPanel::attachHandlers() { + using namespace std::placeholders; + dlg["left"].attachClickHandler(std::bind(&cButtonPanel::onLeft,this)); + dlg["right"].attachClickHandler(std::bind(&cButtonPanel::onRight,this)); + dlg["done"].attachClickHandler(std::bind(&cButtonPanel::onOkay,this,_1)); + dlg["cancel"].attachClickHandler(std::bind(&cButtonPanel::onCancel,this,_1)); + if(strings.size() <= per_page) { + dlg["left"].hide(); + dlg["right"].hide(); + } + // Attach click handler to the tiny buttons + for(int i = 0; i < per_page; ++i){ + short string_idx = page * per_page + i; + std::ostringstream sout; + sout << "button" << i + 1; + dlg[sout.str()].attachClickHandler([i, this](cDialog&,std::string,eKeyMod) -> bool { + click_handlers[i](*this); + return true; + }); + } +} + +cDialog* cButtonPanel::operator->() { + return &dlg; +} + +bool cButtonPanel::show() { + page = 0; + dlg.run(std::bind(&cButtonPanel::fillPage, this)); + return dlg.getResult(); +} + +void cButtonPanel::fillPage(){ + for(unsigned int i = 0; i < per_page; i++){ + short string_idx = page * per_page + i; + std::ostringstream sout; + sout << "button" << i + 1; + if(string_idx < strings.size()){ + dlg[sout.str()].setText(strings[string_idx]); + dlg[sout.str()].recalcRect(); + dlg[sout.str()].show(); + }else{ + dlg[sout.str()].hide(); + } + } +} + +bool cButtonPanel::onLeft(){ + if(page == 0) page = lastPage(); + else page--; + fillPage(); + return true; +} + +bool cButtonPanel::onRight(){ + if(page == lastPage()) page = 0; + else page++; + fillPage(); + return true; +} + +bool cButtonPanel::onCancel(cDialog& me){ + dlg.setResult(false); + me.toast(false); + return true; +} + +bool cButtonPanel::onOkay(cDialog& me){ + dlg.setResult(true); + me.toast(true); + return true; +} + +void cButtonPanel::setTitle(const std::string &title) { + if(!title.empty()) dlg["title"].setText(title); +} + +size_t cButtonPanel::lastPage() const { + return (strings.size() - 1) / per_page; +} \ No newline at end of file diff --git a/src/dialogxml/dialogs/btnpanel.hpp b/src/dialogxml/dialogs/btnpanel.hpp new file mode 100644 index 00000000..90317296 --- /dev/null +++ b/src/dialogxml/dialogs/btnpanel.hpp @@ -0,0 +1,47 @@ +#ifndef DIALOG_BTNPANEL_H +#define DIALOG_BTNPANEL_H + +#include +#include +#include +#include +#include "dialog.hpp" +#include "dialogxml/widgets/ledgroup.hpp" + +/// A dialog that presents a list of labeled tiny buttons, plus an OK and Cancel button. +/// The list may span several pages. +class cButtonPanel { + const size_t per_page = 5; + cDialog dlg; + bool onLeft(); + bool onRight(); + bool onCancel(cDialog& me); + bool onOkay(cDialog& me); + void attachHandlers(); + void fillPage(); + size_t lastPage() const; + std::vector strings; + std::vector> click_handlers; + size_t page, cur; + cButtonPanel(cDialog* parent); +public: + /// Initializes a dialog from a list of strings. + /// @param strs A list of all strings in the dialog. + /// @param click_handlers A list of click handlers for the strings + /// @param title The title to show in the dialog. + /// @param parent Optionally, a parent dialog. + explicit cButtonPanel(const std::vector& strs, std::vector> click_handlers, std::string title, std::string ok_str = "", cDialog* parent = nullptr); + /// Reference the cDialog powering this choice dialog, perhaps to customize details of it. + /// @return A pointer to the dialog. + cDialog* operator->(); + /// Show the dialog. + /// @return True if OK was pressed, false if Cancel pressed + bool show(); + /// Set the dialog's title. + /// @param title The new title. + void setTitle(const std::string& title); + /// Get the list of strings. + std::vector getStrings() const { return strings; } +}; + +#endif