From c4d7fc6b99e9c56ce88c26c8a5c6c391a576da72 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sat, 7 Jan 2023 01:21:42 -0500 Subject: [PATCH] Make dialogs iterable --- src/dialogxml/dialogs/dialog.cpp | 35 ++++++++++++++++++++++++++++++++ src/dialogxml/dialogs/dialog.hpp | 22 ++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/dialogxml/dialogs/dialog.cpp b/src/dialogxml/dialogs/dialog.cpp index 56cd061c..d5e3f881 100644 --- a/src/dialogxml/dialogs/dialog.cpp +++ b/src/dialogxml/dialogs/dialog.cpp @@ -1080,3 +1080,38 @@ bool cDialog::hasControl(std::string id) { } const char*const xBadVal::CONTENT = ""; + +cDialogIterator::cDialogIterator() : parent(nullptr) {} + +cDialogIterator::cDialogIterator(cDialog* parent) : parent(parent), current(parent->controls.begin()) {} + +std::pair& cDialogIterator::dereference() const { + // Ugly fugly... especially the reinterpret_cast... + using value_type = std::pair; + if(children.empty()) return *reinterpret_cast(&*current); + return const_cast(children.front()); +} + +bool cDialogIterator::equal(const cDialogIterator& other) const { + if(parent == nullptr) return other.parent == nullptr; + return parent == other.parent && current == other.current && std::equal(children.begin(), children.end(), other.children.begin()); +} + +void cDialogIterator::increment() { + if(children.empty()) { + if(current->second->isContainer()) { + cContainer& box = dynamic_cast(*current->second); + std::vector> newChildren; + box.forEach([&newChildren](std::string id, cControl& ctrl) { + newChildren.emplace_back(id, &ctrl); + }); + children.insert(children.begin(), newChildren.begin(), newChildren.end()); + } + ++current; + } else { + children.pop_front(); + } + if(children.empty() && current == parent->controls.end()) { + parent = nullptr; + } +} diff --git a/src/dialogxml/dialogs/dialog.hpp b/src/dialogxml/dialogs/dialog.hpp index 758df396..04905d69 100644 --- a/src/dialogxml/dialogs/dialog.hpp +++ b/src/dialogxml/dialogs/dialog.hpp @@ -25,6 +25,7 @@ #include "dialogxml/dialogs/dlogevt.hpp" #include "location.hpp" #include +#include class cControl; class cTextField; @@ -34,8 +35,23 @@ enum eLabelPos { LABEL_LEFT, LABEL_ABOVE, LABEL_RIGHT, LABEL_BELOW, }; +class cDialogIterator : public boost::iterator_facade, std::forward_iterator_tag> { + friend class boost::iterator_core_access; + cDialog* parent; + std::map::iterator current; + std::deque> children; +public: + cDialogIterator(); + cDialogIterator(cDialog* parent); +protected: + std::pair& dereference() const; + bool equal(const cDialogIterator& other) const; + void increment(); +}; + /// Defines a fancy dialog box with various controls. class cDialog { + friend class cDialogIterator; typedef std::map::iterator ctrlIter; std::map controls; short bg; @@ -213,6 +229,12 @@ public: } return p; } + cDialogIterator begin() { + return cDialogIterator(this); + } + cDialogIterator end() { + return cDialogIterator(); + } cDialog& operator=(cDialog& other) = delete; cDialog(cDialog& other) = delete; private: