diff --git a/src/data/action/value.cpp b/src/data/action/value.cpp index 3c2b4628..d28e6d2e 100644 --- a/src/data/action/value.cpp +++ b/src/data/action/value.cpp @@ -35,6 +35,7 @@ class SimpleValueAction : public ValueAction { virtual void perform(bool to_undo) { swap(static_cast(*valueP).*member, new_value); + valueP->onAction(*this, to_undo); // notify value } virtual bool merge(const Action& action) { @@ -54,9 +55,9 @@ class SimpleValueAction : public ValueAction { typename T::ValueType T::*member; }; -ValueAction* value_action(const ChoiceValueP& value, const Defaultable& new_value) { return new SimpleValueAction (value, new_value, &ChoiceValue::value); } +ValueAction* value_action(const ChoiceValueP& value, const Defaultable& new_value) { return new SimpleValueAction (value, new_value, &ChoiceValue::value); } ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable& new_value) { return new SimpleValueAction(value, new_value, &MultipleChoiceValue::value); } -ValueAction* value_action(const ColorValueP& value, const Defaultable& new_value) { return new SimpleValueAction (value, new_value, &ColorValue::value); } +ValueAction* value_action(const ColorValueP& value, const Defaultable& new_value) { return new SimpleValueAction (value, new_value, &ColorValue::value); } ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction(value, new_value, &ImageValue::filename); } ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction(value, new_value, &SymbolValue::filename); } @@ -76,6 +77,7 @@ void TextValueAction::perform(bool to_undo) { swap(value().value, new_value); value().last_update.update(); swap(selection_end, new_selection_end); + valueP->onAction(*this, to_undo); // notify value } bool TextValueAction::merge(const Action& action) { diff --git a/src/data/field.cpp b/src/data/field.cpp index 7f9ed3e5..df85e8cb 100644 --- a/src/data/field.cpp +++ b/src/data/field.cpp @@ -127,10 +127,13 @@ Value::~Value() {} IMPLEMENT_REFLECTION_NAMELESS(Value) { } +bool Value::equals(const Value* that) { + return this == that; +} + void init_object(const FieldP& field, ValueP& value) { if (!value) value = field->newValue(field); } template <> ValueP read_new(Reader&) { throw InternalError(_("IndexMap contains nullptr ValueP the application should have crashed already")); } - diff --git a/src/data/field.hpp b/src/data/field.hpp index 809b0218..2071b465 100644 --- a/src/data/field.hpp +++ b/src/data/field.hpp @@ -21,6 +21,7 @@ DECLARE_POINTER_TYPE(Style); DECLARE_POINTER_TYPE(Value); class Context; class Dependency; +class Action; // for DataViewer/editor class DataViewer; class DataEditor; @@ -134,6 +135,14 @@ class Value { virtual String toString() const = 0; /// Apply scripts to this value, return true if the value has changed virtual bool update(Context&) { last_script_update.update(); return false; } + /// This value has been updated by an action + /** Does nothing for most Values, only FakeValues can update underlying data */ + virtual void onAction(Action& a, bool undone) {} + /// Is this value the same as some other value (for the same field&card) + /** Has behaviour other than == for FakeTextValue. + * In that case, afterwards this becomes equal to that if they use the same underlying object. + */ + virtual bool equals(const Value* that); private: DECLARE_REFLECTION_VIRTUAL(); diff --git a/src/data/field/text.cpp b/src/data/field/text.cpp index e0b9e2f8..b5a10c56 100644 --- a/src/data/field/text.cpp +++ b/src/data/field/text.cpp @@ -105,3 +105,18 @@ bool TextValue::update(Context& ctx) { IMPLEMENT_REFLECTION_NAMELESS(TextValue) { if (fieldP->save_value || tag.scripting()) REFLECT_NAMELESS(value); } + +// ----------------------------------------------------------------------------- : FakeTextValue + +void FakeTextValue::onAction(Action& a, bool undone) { + *underlying = value; +} + +bool FakeTextValue::equals(const Value* that) { + if (this == that) return true; + const FakeTextValue* thatT = dynamic_cast(that); + if (!thatT || underlying != thatT->underlying) return false; + // update the value + value = *underlying; + return true; +} diff --git a/src/data/field/text.hpp b/src/data/field/text.hpp index 49047bbe..df1f585a 100644 --- a/src/data/field/text.hpp +++ b/src/data/field/text.hpp @@ -98,5 +98,22 @@ class TextValue : public Value { DECLARE_REFLECTION(); }; +// ----------------------------------------------------------------------------- : TextValue + +/// A 'fake' TextValue that is used to edit some other string +/** Used by TextCtrl */ +class FakeTextValue : public TextValue { + public: + inline FakeTextValue(const TextFieldP& field, String* underlying) + : TextValue(field), underlying(underlying) {} + + String* const underlying; ///< The underlying actual value + + /// Update underlying data + virtual void onAction(Action& a, bool undone); + /// Editing the same underlying value? + virtual bool equals(const Value* that); +}; + // ----------------------------------------------------------------------------- : EOF #endif diff --git a/src/data/game.hpp b/src/data/game.hpp index 4282846b..04f61e19 100644 --- a/src/data/game.hpp +++ b/src/data/game.hpp @@ -34,21 +34,21 @@ class Game : public Packaged { public: Game(); - OptionalScript init_script; ///< Script of variables available to other scripts in this game - vector set_fields; ///< Fields for set information - IndexMap default_set_style; ///< Default style for the set fields, because it is often the same - vector card_fields; ///< Fields on each card - vector statistics_dimensions; ///< (Additional) statistics dimensions - vector statistics_categories; ///< (Additional) statistics categories - + OptionalScript init_script; ///< Script of variables available to other scripts in this game + vector set_fields; ///< Fields for set information + IndexMap default_set_style; ///< Default style for the set fields, because it is often the same + vector card_fields; ///< Fields on each card + vector statistics_dimensions; ///< (Additional) statistics dimensions + vector statistics_categories; ///< (Additional) statistics categories + bool has_keywords; ///< Does this game use keywords? vector keyword_parameter_types;///< Types of keyword parameters vector keyword_modes; ///< Modes of keywords - vector keywords; ///< Keywords for use in text - - Dependencies dependent_scripts_cards; ///< scripts that depend on the card list - Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords - bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized? + vector keywords; ///< Keywords for use in text + + Dependencies dependent_scripts_cards; ///< scripts that depend on the card list + Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords + bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized? /// Loads the game with a particular name, for example "magic" static GameP byName(const String& name); diff --git a/src/data/keyword.hpp b/src/data/keyword.hpp index 1d2cba4e..f95f281c 100644 --- a/src/data/keyword.hpp +++ b/src/data/keyword.hpp @@ -59,6 +59,7 @@ class Keyword { * captures 2,4,... capture the parameters */ wxRegEx matchRe; + bool fixed; ///< Is this keyword uneditable? (true for game keywods, false for set keywords) /// Prepare the expansion: (re)generate matchRe and the list of parameters. /** Throws when there is an error in the input diff --git a/src/data/symbol_font.cpp b/src/data/symbol_font.cpp index ccb7f09c..ab3871ce 100644 --- a/src/data/symbol_font.cpp +++ b/src/data/symbol_font.cpp @@ -119,7 +119,7 @@ Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) { actual_size = wxSize(img.GetWidth(), img.GetHeight()); // scale to match expected size Image resampled_image((int) (actual_size.GetWidth() * size / img_size), - (int) (actual_size.GetHeight() * size / img_size), false); + (int) (actual_size.GetHeight() * size / img_size), false); if (!resampled_image.Ok()) return Bitmap(1,1); resample(img, resampled_image); // convert to bitmap, store for later use diff --git a/src/gui/control/keyword_list.cpp b/src/gui/control/keyword_list.cpp index ea86c50f..28bceded 100644 --- a/src/gui/control/keyword_list.cpp +++ b/src/gui/control/keyword_list.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include DECLARE_TYPEOF_COLLECTION(KeywordP); @@ -23,7 +25,7 @@ KeywordList::KeywordList(Window* parent, int id, long additional_style) : ItemList(parent, id, additional_style) { // Add columns - InsertColumn(0, _LABEL_("keyword"), wxLIST_FORMAT_LEFT, 100); + InsertColumn(0, _LABEL_("keyword"), wxLIST_FORMAT_LEFT, 0); InsertColumn(1, _LABEL_("match"), wxLIST_FORMAT_LEFT, 200); InsertColumn(2, _LABEL_("mode"), wxLIST_FORMAT_LEFT, 100); InsertColumn(3, _LABEL_("uses"), wxLIST_FORMAT_RIGHT, 80); @@ -51,11 +53,21 @@ void KeywordList::onAction(const Action& action, bool undone) { // ----------------------------------------------------------------------------- : KeywordListBase : for ItemList +String match_string(const Keyword& a) { + return untag(replace_all(replace_all( + a.match, + _(""), _("‹")), + _(""), _("›")) + ); +} + void KeywordList::getItems(vector& out) const { FOR_EACH(k, set->keywords) { + k->fixed = false; out.push_back(k); } FOR_EACH(k, set->game->keywords) { + k->fixed = true; out.push_back(k); } } @@ -83,7 +95,7 @@ String KeywordList::OnGetItemText (long pos, long col) const { const Keyword& kw = *getKeyword(pos); switch(col) { case 0: return kw.keyword; - case 1: return kw.match; + case 1: return match_string(kw); case 2: return kw.mode; case 3: return _("TODO"); case 4: return _("TODO"); @@ -93,3 +105,11 @@ String KeywordList::OnGetItemText (long pos, long col) const { int KeywordList::OnGetItemImage(long pos) const { return -1; } + +wxListItemAttr* KeywordList::OnGetItemAttr(long pos) const { + // black for set keywords, grey for game keywords (uneditable) + const Keyword& kw = *getKeyword(pos); + if (!kw.fixed) return nullptr; + item_attr.SetTextColour(lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),0.5)); + return &item_attr; +} diff --git a/src/gui/control/keyword_list.hpp b/src/gui/control/keyword_list.hpp index 096b1d58..09168d86 100644 --- a/src/gui/control/keyword_list.hpp +++ b/src/gui/control/keyword_list.hpp @@ -68,9 +68,13 @@ class KeywordList : public ItemList, public SetView { /// Get the image of an item, by default no image is used /** Overrides a function from wxListCtrl */ virtual int OnGetItemImage(long pos) const; + /// Get the color for an item + virtual wxListItemAttr* OnGetItemAttr(long pos) const; private: void storeColumns(); + + mutable wxListItemAttr item_attr; // for OnGetItemAttr }; // ----------------------------------------------------------------------------- : EOF diff --git a/src/gui/control/text_ctrl.cpp b/src/gui/control/text_ctrl.cpp index 9f8f63f5..92677599 100644 --- a/src/gui/control/text_ctrl.cpp +++ b/src/gui/control/text_ctrl.cpp @@ -37,7 +37,7 @@ void TextCtrl::setValue(String* value) { // create a field, style and value TextFieldP field(new TextField); TextStyleP style(new TextStyle(field)); - TextValueP value(new TextValue(field)); + TextValueP value(new FakeTextValue(field, this->value)); // set stuff field->index = 0; field->multi_line = true; @@ -57,6 +57,11 @@ void TextCtrl::setValue(String* value) { viewers.front()->getEditor()->determineSize(true); // We don't wan to change the window size //SetMinSize(RealSize(style->width + 6, style->height + 6)); + } else if (value) { + // create a new value, for a different underlying actual value + ValueViewer& viewer = *viewers.front(); + TextValueP new_value(new FakeTextValue(static_pointer_cast(viewer.getField()), this->value)); + viewer.setValue(new_value); } valueChanged(); } @@ -70,13 +75,15 @@ void TextCtrl::valueChanged() { } void TextCtrl::onAction(const Action& action, bool undone) { DataEditor::onAction(action, undone); + /* TYPE_CASE(action, TextValueAction) { - TextValue& tv = static_cast(*viewers.front()->getValue()); - if (&tv == action.valueP.get()) { + FakeTextValue& tv = static_cast(*viewers.front()->getValue()); + if (tv.equals(action.valueP.get())) { // the value has changed if (value) *value = tv.value(); } } + */ } void TextCtrl::onChangeSet() { DataEditor::onChangeSet(); diff --git a/src/gui/set/keywords_panel.cpp b/src/gui/set/keywords_panel.cpp index 5657c820..4b488fc3 100644 --- a/src/gui/set/keywords_panel.cpp +++ b/src/gui/set/keywords_panel.cpp @@ -8,8 +8,10 @@ #include #include +#include #include #include +#include // ----------------------------------------------------------------------------- : KeywordsPanel @@ -17,18 +19,44 @@ KeywordsPanel::KeywordsPanel(Window* parent, int id) : SetWindowPanel(parent, id) { // init controls - list = new KeywordList(this, wxID_ANY); + Panel* panel; + splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); + list = new KeywordList(splitter, wxID_ANY); + panel = new Panel(splitter, wxID_ANY); + keyword = new TextCtrl(panel, wxID_ANY); + match = new TextCtrl(panel, wxID_ANY); + reminder = new TextCtrl(panel, wxID_ANY); + rules = new TextCtrl(panel, wxID_ANY); + // init sizer for panel + wxSizer* sp = new wxBoxSizer(wxVERTICAL); + sp->Add(new wxStaticText(panel, wxID_ANY, _("Keyword:")), 0, wxALL, 6); + sp->Add(keyword, 0, wxEXPAND | wxALL & ~wxTOP, 6); + wxSizer* s2 = new wxStaticBoxSizer(wxVERTICAL, panel, _("Match")); + s2->Add(new wxStaticText(panel, wxID_ANY, _("Keyword format:")), 0, wxALL, 6); + s2->Add(match, 0, wxEXPAND | wxALL & ~wxTOP, 6); + s2->Add(new wxStaticText(panel, wxID_ANY, _("Parameters:")), 0, wxALL, 6); + sp->Add(s2, 0, wxEXPAND | wxALL, 6); + sp->Add(new wxStaticText(panel, wxID_ANY, _("Reminder:")), 0, wxALL, 6); + sp->Add(reminder, 0, wxEXPAND | wxALL & ~wxTOP, 6); + sp->Add(new wxStaticText(panel, wxID_ANY, _("Rules:")), 0, wxALL, 6); + sp->Add(rules, 0, wxEXPAND | wxALL & ~wxTOP, 6); + panel->SetSizer(sp); + // init splitter + splitter->SetMinimumPaneSize(100); + splitter->SetSashGravity(0.5); + splitter->SplitVertically(list, panel, -200); // init sizer wxSizer* s = new wxBoxSizer(wxHORIZONTAL); - s->Add(list, 1, wxEXPAND); + s->Add(splitter, 1, wxEXPAND); + s->SetSizeHints(this); + SetSizer(s); + //s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove /* wxSizer* s2 = new wxBoxSizer(wxVERTICAL); s2->Add(list_active, 1, wxEXPAND); s2->Add(list_inactive, 1, wxEXPAND);*/ - s->SetSizeHints(this); - SetSizer(s); } void KeywordsPanel::onChangeSet() { list->setSet(set); -} \ No newline at end of file +} diff --git a/src/gui/set/keywords_panel.hpp b/src/gui/set/keywords_panel.hpp index df43ff27..79145f9b 100644 --- a/src/gui/set/keywords_panel.hpp +++ b/src/gui/set/keywords_panel.hpp @@ -12,6 +12,7 @@ #include #include +class wxSplitterWindow; class KeywordList; class TextCtrl; @@ -25,8 +26,13 @@ class KeywordsPanel : public SetWindowPanel { virtual void onChangeSet(); private: - KeywordList* list; - TextCtrl* keyword; + // --------------------------------------------------- : Controls + wxSplitterWindow* splitter; + KeywordList* list; + TextCtrl* keyword; + TextCtrl* match; + TextCtrl* reminder; + TextCtrl* rules; }; // ----------------------------------------------------------------------------- : EOF diff --git a/src/render/card/viewer.cpp b/src/render/card/viewer.cpp index 5743da36..200cbf7f 100644 --- a/src/render/card/viewer.cpp +++ b/src/render/card/viewer.cpp @@ -125,7 +125,7 @@ void DataViewer::onAction(const Action& action, bool undone) { } TYPE_CASE(action, ValueAction) { FOR_EACH(v, viewers) { - if (v->getValue() == action.valueP) { + if (v->getValue()->equals( action.valueP.get() )) { // refresh the viewer v->onAction(action, undone); onChange(); diff --git a/src/render/value/viewer.hpp b/src/render/value/viewer.hpp index a418389d..b9c20962 100644 --- a/src/render/value/viewer.hpp +++ b/src/render/value/viewer.hpp @@ -79,16 +79,16 @@ class ValueViewer { // ----------------------------------------------------------------------------- : Utility -#define DECLARE_VALUE_VIEWER(Type) \ - protected: \ - inline Type##Style& style() const { return static_cast< Type##Style&>(*ValueViewer::styleP); } \ - inline const Type##Value& value() const { return static_cast(*ValueViewer::valueP); } \ - inline const Type##Field& field() const { return style().field(); } \ - inline Type##StyleP styleP() const { return static_pointer_cast(ValueViewer::styleP); } \ - inline Type##ValueP valueP() const { return static_pointer_cast(ValueViewer::valueP); } \ - inline Type##FieldP fieldP() const { return static_pointer_cast(style().fieldP); } \ - public: \ - Type##ValueViewer(DataViewer& parent, const Type ## StyleP& style) +#define DECLARE_VALUE_VIEWER(Type) \ + protected: \ + inline Type##Style& style() const { return static_cast< Type##Style&>(*ValueViewer::styleP); } \ + inline const Type##Value& value() const { return static_cast(*ValueViewer::valueP); } \ + inline const Type##Field& field() const { return style().field(); } \ + inline Type##StyleP styleP() const { return static_pointer_cast(ValueViewer::styleP); } \ + inline Type##ValueP valueP() const { return static_pointer_cast(ValueViewer::valueP); } \ + inline Type##FieldP fieldP() const { return static_pointer_cast(style().fieldP); } \ + public: \ + Type##ValueViewer(DataViewer& parent, const Type ## StyleP& style) // ----------------------------------------------------------------------------- : EOF diff --git a/src/util/for_each.hpp b/src/util/for_each.hpp index 9aba9d5a..ec235db0 100644 --- a/src/util/for_each.hpp +++ b/src/util/for_each.hpp @@ -51,42 +51,42 @@ #define TYPEOF_REF(Value) TypeOf::reference /// The type of a const reference #define TYPEOF_CREF(Value) TypeOf::const_reference - + /// Declare typeof magic for a specific type - #define DECLARE_TYPEOF(T) \ - template<> struct TypeOf { \ - typedef T type; \ - typedef T::iterator iterator; \ - typedef T::const_iterator const_iterator; \ - typedef T::reverse_iterator reverse_iterator; \ - typedef T::const_reverse_iterator const_reverse_iterator; \ - typedef T::reference reference; \ - typedef T::const_reference const_reference; \ - } + #define DECLARE_TYPEOF(T) \ + template<> struct TypeOf { \ + typedef T type; \ + typedef T::iterator iterator; \ + typedef T::const_iterator const_iterator; \ + typedef T::reverse_iterator reverse_iterator; \ + typedef T::const_reverse_iterator const_reverse_iterator; \ + typedef T::reference reference; \ + typedef T::const_reference const_reference; \ + } /// Declare typeof magic for a specific type that doesn't support reverse iterators - #define DECLARE_TYPEOF_NO_REV(T) \ - template<> struct TypeOf { \ - typedef T type; \ - typedef T::iterator iterator; \ - typedef T::const_iterator const_iterator; \ - typedef T::reference reference; \ - typedef T::const_reference const_reference; \ - } + #define DECLARE_TYPEOF_NO_REV(T) \ + template<> struct TypeOf { \ + typedef T type; \ + typedef T::iterator iterator; \ + typedef T::const_iterator const_iterator; \ + typedef T::reference reference; \ + typedef T::const_reference const_reference; \ + } /// Declare typeof magic for a specific type, using const iterators - #define DECLARE_TYPEOF_CONST(T) \ - template<> struct TypeOf { \ - typedef T type; \ - typedef T::const_iterator iterator; \ - typedef T::const_iterator const_iterator; \ - typedef T::const_reverse_iterator reverse_iterator; \ - typedef T::const_reverse_iterator const_reverse_iterator; \ - typedef T::const_reference reference; \ - typedef T::const_reference const_reference; \ - } + #define DECLARE_TYPEOF_CONST(T) \ + template<> struct TypeOf { \ + typedef T type; \ + typedef T::const_iterator iterator; \ + typedef T::const_iterator const_iterator; \ + typedef T::const_reverse_iterator reverse_iterator; \ + typedef T::const_reverse_iterator const_reverse_iterator; \ + typedef T::const_reference reference; \ + typedef T::const_reference const_reference; \ + } /// Declare typeof magic for a specific std::vector type - #define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector< T >); \ - DECLARE_TYPEOF_CONST(set< T >) + #define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector< T >); \ + DECLARE_TYPEOF_CONST(set< T >) #endif @@ -103,33 +103,33 @@ /// Iterate over a collection, using an iterator it of type Type /** Usage: FOR_EACH_IT_T(Type,it,collect) { body-of-loop } */ -#define FOR_EACH_IT_T(Type,Iterator,Collection) \ - for(Type Iterator = Collection.begin() ; \ - Iterator != Collection.end() ; \ - ++Iterator) +#define FOR_EACH_IT_T(Type,Iterator,Collection) \ + for(Type Iterator = Collection.begin() ; \ + Iterator != Collection.end() ; \ + ++Iterator) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Usage: FOR_EACH_IT(it,collect) { body-of-loop } */ -#define FOR_EACH_IT(Iterator,Collection) \ - FOR_EACH_IT_T(TYPEOF_IT(Collection), Iterator, Collection) +#define FOR_EACH_IT(Iterator,Collection) \ + FOR_EACH_IT_T(TYPEOF_IT(Collection), Iterator, Collection) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Uses a const_iterator * Usage: FOR_EACH_IT(it,collect) { body-of-loop } */ -#define FOR_EACH_CONST_IT(Iterator,Collection) \ - FOR_EACH_IT_T(TYPEOF_CIT(Collection), Iterator, Collection) +#define FOR_EACH_CONST_IT(Iterator,Collection) \ + FOR_EACH_IT_T(TYPEOF_CIT(Collection), Iterator, Collection) /// Iterate over a collection in whos type must be declared with DECLARE_TYPEOF /** Iterates using a reverse_iterator * Usage: FOR_EACH_REVERSE_IT(it,collect) { body-of-loop } */ -#define FOR_EACH_REVERSE_IT(Iterator,Collection) \ - for(TYPEOF_RIT(Collection) \ - Iterator = Collection.rbegin() ; \ - Iterator != Collection.rend() ; \ - ++Iterator) +#define FOR_EACH_REVERSE_IT(Iterator,Collection) \ + for(TYPEOF_RIT(Collection) \ + Iterator = Collection.rbegin() ; \ + Iterator != Collection.rend() ; \ + ++Iterator) // ----------------------------------------------------------------------------- : Looping macros @@ -140,40 +140,40 @@ * To do this we use a nested for loop that is only executed once, and which is optimized away. * To terminate this loop we need an extra bool, which we set to false after the first iteration. */ -#define FOR_EACH_T(TypeIt,TypeElem,Elem,Collection, begin, end) \ - for(std::pair Elem##_IT(Collection.begin(), true) ; \ - Elem##_IT.second && Elem##_IT.first != Collection.end() ; \ - ++Elem##_IT.first, Elem##_IT.second = !Elem##_IT.second) \ - for(TypeElem Elem = *Elem##_IT.first ; \ - Elem##_IT.second ; \ - Elem##_IT.second = false) +#define FOR_EACH_T(TypeIt,TypeElem,Elem,Collection, begin, end) \ + for(std::pair Elem##_IT(Collection.begin(), true) ; \ + Elem##_IT.second && Elem##_IT.first != Collection.end() ; \ + ++Elem##_IT.first, Elem##_IT.second = !Elem##_IT.second) \ + for(TypeElem Elem = *Elem##_IT.first ; \ + Elem##_IT.second ; \ + Elem##_IT.second = false) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Usage: FOR_EACH(e,collect) { body-of-loop } */ -#define FOR_EACH(Elem,Collection) \ - FOR_EACH_T(TYPEOF_IT(Collection), TYPEOF_REF(Collection), Elem, Collection, begin, end) +#define FOR_EACH(Elem,Collection) \ + FOR_EACH_T(TYPEOF_IT(Collection), TYPEOF_REF(Collection), Elem, Collection, begin, end) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Uses a const iterator * Usage: FOR_EACH_CONST(e,collect) { body-of-loop } */ -#define FOR_EACH_CONST(Elem,Collection) \ - FOR_EACH_T(TYPEOF_CIT(Collection), TYPEOF_CREF(Collection), Elem, Collection, begin, end) +#define FOR_EACH_CONST(Elem,Collection) \ + FOR_EACH_T(TYPEOF_CIT(Collection), TYPEOF_CREF(Collection), Elem, Collection, begin, end) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Iterates using a reverse_iterator * Usage: FOR_EACH_REVERSE(e,collect) { body-of-loop } */ -#define FOR_EACH_REVERSE(Elem,Collection) \ - FOR_EACH_T(TYPEOF_RIT(Collection), TYPEOF_REF(Collection), Elem, Collection, rbegin, rend) +#define FOR_EACH_REVERSE(Elem,Collection) \ + FOR_EACH_T(TYPEOF_RIT(Collection), TYPEOF_REF(Collection), Elem, Collection, rbegin, rend) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Iterates using a const_reverse_iterator * Usage: FOR_EACH_CONST_REVERSE(e,collect) { body-of-loop } */ -#define FOR_EACH_CONST_REVERSE(Elem,Collection) \ - FOR_EACH_T(TYPEOF_CRIT(Collection), TYPEOF_CREF(Collection), Elem, Collection, rbegin, rend) +#define FOR_EACH_CONST_REVERSE(Elem,Collection) \ + FOR_EACH_T(TYPEOF_CRIT(Collection), TYPEOF_CREF(Collection), Elem, Collection, rbegin, rend) /// Iterate over two collection in parallel /** Usage: FOR_EACH_2_T(TypeIt1,TypeElem1,e1,collect1,TypeIt2,TypeElem2,e2,collect2) { body-of-loop } @@ -181,33 +181,33 @@ * Note: This has got to be one of the craziest pieces of code I have ever written :) * It is just an extension of the idea of FOR_EACH_T. */ -#define FOR_EACH_2_T(TypeIt1,TypeElem1,Elem1,Coll1,TypeIt2,TypeElem2,Elem2,Coll2) \ - for(std::pair, bool> \ - Elem1##_IT(make_pair(Coll1.begin(), Coll2.begin()), true) ; \ - Elem1##_IT.first.first != Coll1.end() && \ - Elem1##_IT.first.second != Coll2.end() ; \ - ++Elem1##_IT.first.first, ++Elem1##_IT.first.second, \ - Elem1##_IT.second = true) \ - for(TypeElem1 Elem1 = *Elem1##_IT.first.first ; \ - Elem1##_IT.second ; \ - Elem1##_IT.second = false) \ - for(TypeElem2 Elem2 = *Elem1##_IT.first.second ; \ - Elem1##_IT.second ; \ - Elem1##_IT.second = false) +#define FOR_EACH_2_T(TypeIt1,TypeElem1,Elem1,Coll1,TypeIt2,TypeElem2,Elem2,Coll2) \ + for(std::pair, bool> \ + Elem1##_IT(make_pair(Coll1.begin(), Coll2.begin()), true) ; \ + Elem1##_IT.first.first != Coll1.end() && \ + Elem1##_IT.first.second != Coll2.end() ; \ + ++Elem1##_IT.first.first, ++Elem1##_IT.first.second, \ + Elem1##_IT.second = true) \ + for(TypeElem1 Elem1 = *Elem1##_IT.first.first ; \ + Elem1##_IT.second ; \ + Elem1##_IT.second = false) \ + for(TypeElem2 Elem2 = *Elem1##_IT.first.second ; \ + Elem1##_IT.second ; \ + Elem1##_IT.second = false) /// Iterate over two collections in parallel, their type must be declared with DECLARE_TYPEOF. /** Usage: FOR_EACH_2(e1,collect1, e2,collect2) { body-of-loop } */ -#define FOR_EACH_2(Elem1,Collection1, Elem2,Collection2) \ - FOR_EACH_2_T(TYPEOF_IT(Collection1), TYPEOF_REF(Collection1), Elem1, Collection1, \ - TYPEOF_IT(Collection2), TYPEOF_REF(Collection2), Elem2, Collection2) +#define FOR_EACH_2(Elem1,Collection1, Elem2,Collection2) \ + FOR_EACH_2_T(TYPEOF_IT(Collection1), TYPEOF_REF(Collection1), Elem1, Collection1, \ + TYPEOF_IT(Collection2), TYPEOF_REF(Collection2), Elem2, Collection2) /// Iterate over two constants collections in parallel, their type must be declared with DECLARE_TYPEOF. /** Usage: FOR_EACH_2_CONST(e1,collect1, e2,collect2) { body-of-loop } */ -#define FOR_EACH_2_CONST(Elem1,Collection1, Elem2,Collection2) \ - FOR_EACH_2_T(TYPEOF_CIT(Collection1), TYPEOF_CREF(Collection1), Elem1, Collection1, \ - TYPEOF_CIT(Collection2), TYPEOF_CREF(Collection2), Elem2, Collection2) +#define FOR_EACH_2_CONST(Elem1,Collection1, Elem2,Collection2) \ + FOR_EACH_2_T(TYPEOF_CIT(Collection1), TYPEOF_CREF(Collection1), Elem1, Collection1, \ + TYPEOF_CIT(Collection2), TYPEOF_CREF(Collection2), Elem2, Collection2) // ----------------------------------------------------------------------------- : EOF