New dialog presents a yes/no choice with alternate non-exclusive actions

This commit is contained in:
2025-08-02 13:55:01 -05:00
parent 665ff2f272
commit 93fc55d031
7 changed files with 194 additions and 4 deletions

View File

@@ -0,0 +1,111 @@
#include "btnpanel.hpp"
#include <sstream>
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#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<std::string>& strs, std::vector<std::function<void(cButtonPanel&)>> 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<bool>();
}
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;
}

View File

@@ -0,0 +1,47 @@
#ifndef DIALOG_BTNPANEL_H
#define DIALOG_BTNPANEL_H
#include <string>
#include <vector>
#include <functional>
#include <boost/optional.hpp>
#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<std::string> strings;
std::vector<std::function<void(cButtonPanel&)>> 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<std::string>& strs, std::vector<std::function<void(cButtonPanel&)>> 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<std::string> getStrings() const { return strings; }
};
#endif