Make dialogs iterable
This commit is contained in:
@@ -1080,3 +1080,38 @@ bool cDialog::hasControl(std::string id) {
|
||||
}
|
||||
|
||||
const char*const xBadVal::CONTENT = "<content>";
|
||||
|
||||
cDialogIterator::cDialogIterator() : parent(nullptr) {}
|
||||
|
||||
cDialogIterator::cDialogIterator(cDialog* parent) : parent(parent), current(parent->controls.begin()) {}
|
||||
|
||||
std::pair<std::string, cControl*>& cDialogIterator::dereference() const {
|
||||
// Ugly fugly... especially the reinterpret_cast...
|
||||
using value_type = std::pair<std::string, cControl*>;
|
||||
if(children.empty()) return *reinterpret_cast<value_type*>(&*current);
|
||||
return const_cast<value_type&>(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<cContainer&>(*current->second);
|
||||
std::vector<std::pair<std::string, cControl*>> 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;
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "dialogxml/dialogs/dlogevt.hpp"
|
||||
#include "location.hpp"
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
|
||||
class cControl;
|
||||
class cTextField;
|
||||
@@ -34,8 +35,23 @@ enum eLabelPos {
|
||||
LABEL_LEFT, LABEL_ABOVE, LABEL_RIGHT, LABEL_BELOW,
|
||||
};
|
||||
|
||||
class cDialogIterator : public boost::iterator_facade<cDialogIterator, std::pair<std::string, cControl*>, std::forward_iterator_tag> {
|
||||
friend class boost::iterator_core_access;
|
||||
cDialog* parent;
|
||||
std::map<std::string,cControl*>::iterator current;
|
||||
std::deque<std::pair<std::string, cControl*>> children;
|
||||
public:
|
||||
cDialogIterator();
|
||||
cDialogIterator(cDialog* parent);
|
||||
protected:
|
||||
std::pair<std::string, cControl*>& 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<std::string,cControl*>::iterator ctrlIter;
|
||||
std::map<std::string,cControl*> 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:
|
||||
|
Reference in New Issue
Block a user