From c666e98645c472b0273cc0e863729aaf0fe40f69 Mon Sep 17 00:00:00 2001 From: twanvl Date: Sat, 17 May 2008 01:51:50 +0000 Subject: [PATCH] Allow multiple cards to be selected in a card list, Allow card actions to add/remove multiple cards. not yet: actually use these multicard actions. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@853 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/action/keyword.cpp | 36 +++++++--------- src/data/action/keyword.hpp | 14 +++---- src/data/action/set.cpp | 49 ++++++---------------- src/data/action/set.hpp | 24 +++-------- src/gui/control/card_list.cpp | 71 +++++++++++++++++--------------- src/gui/control/card_list.hpp | 1 + src/gui/control/item_list.cpp | 47 ++++++++++++++------- src/gui/control/item_list.hpp | 19 ++++++--- src/gui/control/keyword_list.cpp | 12 ++++-- src/gui/control/keyword_list.hpp | 1 + src/gui/set/keywords_panel.cpp | 2 +- src/gui/symbol/selection.cpp | 2 +- src/mse.vcproj | 3 ++ src/script/script_manager.cpp | 13 ++++-- 14 files changed, 145 insertions(+), 149 deletions(-) diff --git a/src/data/action/keyword.cpp b/src/data/action/keyword.cpp index 70d84835..bf325238 100644 --- a/src/data/action/keyword.cpp +++ b/src/data/action/keyword.cpp @@ -19,40 +19,34 @@ DECLARE_TYPEOF_COLLECTION(KeywordModeP); // ----------------------------------------------------------------------------- : Add Keyword -AddKeywordAction::AddKeywordAction(Adding, Set& set, const KeywordP& keyword) - : KeywordListAction(set), adding(true), keyword(keyword ? keyword : new_intrusive()) - , keyword_id(set.keywords.size()) +AddKeywordAction::AddKeywordAction(Set& set) + : KeywordListAction(set) + , action(ADD, new_intrusive(), set.keywords) { + Keyword& keyword = *action.steps.front().item; // find default mode FOR_EACH(mode, set.game->keyword_modes) { if (mode->is_default) { - this->keyword->mode = mode->name; + keyword.mode = mode->name; break; } } } -AddKeywordAction::AddKeywordAction(Removing, Set& set, const KeywordP& keyword) - : KeywordListAction(set), adding(false), keyword(keyword) - // find the keyword_id of the keyword we want to remove - , keyword_id(find(set.keywords.begin(), set.keywords.end(), keyword) - set.keywords.begin()) -{ - if (keyword_id >= set.keywords.size()) { - throw InternalError(_("Keyword to remove not found in set")); - } -} +AddKeywordAction::AddKeywordAction(AddingOrRemoving ar, Set& set, const KeywordP& keyword) + : KeywordListAction(set) + , action(ar, keyword, set.keywords) +{} +/*AddKeywordAction::AddKeywordAction(AddingOrRemoving ar, Set& set, const vector& keyword) + : KeywordListAction(set) + , action(ar, keywords, set.keywords) +{}*/ String AddKeywordAction::getName(bool to_undo) const { - return adding ? _("Add keyword") : _("Remove keyword"); + return action.getName(); } void AddKeywordAction::perform(bool to_undo) { - if (adding != to_undo) { - assert(keyword_id <= set.keywords.size()); - set.keywords.insert(set.keywords.begin() + keyword_id, keyword); - } else { - assert(keyword_id < set.keywords.size()); - set.keywords.erase(set.keywords.begin() + keyword_id); - } + action.perform(set.keywords, to_undo); set.keyword_db.clear(); } diff --git a/src/data/action/keyword.hpp b/src/data/action/keyword.hpp index 995fb80a..9a1ea36a 100644 --- a/src/data/action/keyword.hpp +++ b/src/data/action/keyword.hpp @@ -18,9 +18,11 @@ #include #include #include +#include class Set; DECLARE_POINTER_TYPE(Keyword); +DECLARE_TYPEOF_COLLECTION(GenericAddAction::Step); // ----------------------------------------------------------------------------- : Add Keyword @@ -34,22 +36,16 @@ class KeywordListAction : public Action { // therefore we don't need a smart pointer }; -enum Adding {ADD}; -enum Removing {REMOVE}; - /// Adding or removing a keyword from a set class AddKeywordAction : public KeywordListAction { public: - AddKeywordAction(Adding, Set& set, const KeywordP& keyword = KeywordP()); - AddKeywordAction(Removing, Set& set, const KeywordP& keyword); + AddKeywordAction(Set& set); + AddKeywordAction(AddingOrRemoving, Set& set, const KeywordP& keyword); virtual String getName(bool to_undo) const; virtual void perform(bool to_undo); - //private: - const bool adding; ///< Was a keyword added? (as opposed to removed) - const KeywordP keyword; ///< The new/removed keyword - const size_t keyword_id; ///< Position of the keyword in the set + const GenericAddAction action; }; // ----------------------------------------------------------------------------- : Changing keywords diff --git a/src/data/action/set.cpp b/src/data/action/set.cpp index 8b1641ab..5166869a 100644 --- a/src/data/action/set.cpp +++ b/src/data/action/set.cpp @@ -18,51 +18,26 @@ DECLARE_TYPEOF_COLLECTION(IndexMap); // ----------------------------------------------------------------------------- : Add card AddCardAction::AddCardAction(Set& set) - : CardListAction(set), card(new Card(*set.game)) + : CardListAction(set) + , action(ADD, new_intrusive1(*set.game), set.cards) {} -AddCardAction::AddCardAction(Set& set, const CardP& card) - : CardListAction(set), card(card) +AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const CardP& card) + : CardListAction(set) + , action(ar, card, set.cards) +{} + +AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector& cards) + : CardListAction(set) + , action(ar, cards, set.cards) {} String AddCardAction::getName(bool to_undo) const { - return _("Add card"); + return action.getName(); } void AddCardAction::perform(bool to_undo) { - if (!to_undo) { - set.cards.push_back(card); - } else { - assert(!set.cards.empty()); - set.cards.pop_back(); - } -} - - -// ----------------------------------------------------------------------------- : Remove card - -RemoveCardAction::RemoveCardAction(Set& set, const CardP& card) - : CardListAction(set), card(card) - // find the card_id of the card we want to remove - , card_id(find(set.cards.begin(), set.cards.end(), card) - set.cards.begin()) -{ - if (card_id >= set.cards.size()) { - throw InternalError(_("Card to remove not found in set")); - } -} - -String RemoveCardAction::getName(bool to_undo) const { - return _("Remove card"); -} - -void RemoveCardAction::perform(bool to_undo) { - if (!to_undo) { - assert(card_id < set.cards.size()); - set.cards.erase(set.cards.begin() + card_id); - } else { - assert(card_id <= set.cards.size()); - set.cards.insert(set.cards.begin() + card_id, card); - } + action.perform(set.cards, to_undo); } diff --git a/src/data/action/set.hpp b/src/data/action/set.hpp index 7396b9cd..4dfe49f2 100644 --- a/src/data/action/set.hpp +++ b/src/data/action/set.hpp @@ -16,12 +16,14 @@ #include #include +#include class Set; DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(StyleSheet); DECLARE_POINTER_TYPE(Field); DECLARE_POINTER_TYPE(Value); +DECLARE_TYPEOF_COLLECTION(GenericAddAction::Step); // ----------------------------------------------------------------------------- : Add card @@ -38,29 +40,15 @@ class CardListAction : public Action { /// Adding a new card to a set class AddCardAction : public CardListAction { public: + /// Add a newly allocated card AddCardAction(Set& set); - AddCardAction(Set& set, const CardP& card); + AddCardAction(AddingOrRemoving, Set& set, const CardP& card); + AddCardAction(AddingOrRemoving, Set& set, const vector& cards); virtual String getName(bool to_undo) const; virtual void perform(bool to_undo); - //private: - const CardP card; ///< The new card -}; - -// ----------------------------------------------------------------------------- : Remove card - -/// Removing a card from a set -class RemoveCardAction : public CardListAction { - public: - RemoveCardAction(Set& set, const CardP& card); - - virtual String getName(bool to_undo) const; - virtual void perform(bool to_undo); - - //private: - const CardP card; ///< The removed card - const size_t card_id; ///< Position of the card in the set + const GenericAddAction action; }; // ----------------------------------------------------------------------------- : Reorder cards diff --git a/src/gui/control/card_list.cpp b/src/gui/control/card_list.cpp index bee2a882..5c23c499 100644 --- a/src/gui/control/card_list.cpp +++ b/src/gui/control/card_list.cpp @@ -41,7 +41,7 @@ DEFINE_EVENT_TYPE(EVENT_CARD_ACTIVATE); vector CardListBase::card_lists; CardListBase::CardListBase(Window* parent, int id, long additional_style) - : ItemList(parent, id, additional_style) + : ItemList(parent, id, additional_style, true) { // add to the list of card lists card_lists.push_back(this); @@ -62,38 +62,36 @@ void CardListBase::onChangeSet() { void CardListBase::onAction(const Action& action, bool undone) { TYPE_CASE(action, AddCardAction) { - if (undone) { + if (action.action.adding != undone) { + // select the new cards + focusNone(); + selectItem(action.action.steps.front().item, false, true); refreshList(); - if (!allowModify()) { - // Let some other card list else do the selecting - return; - } - selectItemPos(GetItemCount() - 1, true); + FOR_EACH_CONST(s, action.action.steps) focusItem(s.item); // focus all the new cards } else { - // select the new card - selectItem(action.card, false /*list will be refreshed anyway*/, true); - refreshList(); - } - } - TYPE_CASE(action, RemoveCardAction) { - if (undone) { - // select the re-added card - selectItem(action.card, false /*list will be refreshed anyway*/, true); - refreshList(); - } else { - long pos = selected_item_pos; - refreshList(); - if (!allowModify()) { - // Let some other card list else do the selecting - return; - } - if (action.card == selected_item) { - // select the next card, if not possible, select the last - if (pos + 1 < GetItemCount()) { - selectItemPos(pos, true); - } else { - selectItemPos(GetItemCount() - 1, true); + long pos = -1; + // adjust focus for all the removed cards + //FOR_EACH_CONST(s, action.action.steps) focusItem(s.item, false); + long count = GetItemCount(); + long delta = 0; + for (long i = 0 ; i < count ; ++i) { + if (delta < (long)action.action.steps.size() && getItem(i) == action.action.steps[delta].item) { + Select(i - delta, false); + delta++; + } else if (delta > 0) { + Select(i - delta, IsSelected(i)); } + if (pos == -1 && IsSelected(i - delta)) pos = i - delta; + } + if (pos == -1) pos = selected_item_pos; // select next item if selection would become empty + refreshList(); + if (!allowModify()) { + // Let some other card list do the selecting, otherwise we get conflicting events + return; + } + if (selected_item_pos == -1) { + // selected item was deleted, select something else + selectItemPos(pos, true, true); } } } @@ -105,7 +103,7 @@ void CardListBase::onAction(const Action& action, bool undone) { // reselect the current card, it has moved selected_item_pos = (long)action.card_id1 == selected_item_pos ? (long)action.card_id2 : (long)action.card_id1; // select the right card - selectCurrentItem(); + focusSelectedItem(); } RefreshItem((long)action.card_id1); RefreshItem((long)action.card_id2); @@ -148,7 +146,7 @@ bool CardListBase::doCut() { // cut = copy + delete if (!canCut()) return false; if (!doCopy()) return false; - set->actions.add(new RemoveCardAction(*set, getCard())); + doDelete(); return true; } bool CardListBase::doPaste() { @@ -162,12 +160,17 @@ bool CardListBase::doPaste() { // add card to set CardP card = data.getCard(set); if (card) { - set->actions.add(new AddCardAction(*set, card)); + set->actions.add(new AddCardAction(ADD, *set, card)); return true; } else { return false; } } +bool CardListBase::doDelete() { + //vector<> + set->actions.add(new AddCardAction(REMOVE, *set, getCard())); + return true; +} // ----------------------------------------------------------------------------- : CardListBase : Building the list @@ -310,7 +313,7 @@ void CardListBase::onSelectColumns(wxCommandEvent&) { void CardListBase::onChar(wxKeyEvent& ev) { if (ev.GetKeyCode() == WXK_DELETE && allowModify()) { - set->actions.add(new RemoveCardAction(*set, getCard())); + doDelete(); } else if (ev.GetKeyCode() == WXK_TAB) { // send a navigation event to our parent, to select another control // we need this because tabs are not handled on the cards panel diff --git a/src/gui/control/card_list.hpp b/src/gui/control/card_list.hpp index 1c4a8f32..ed8a71ac 100644 --- a/src/gui/control/card_list.hpp +++ b/src/gui/control/card_list.hpp @@ -71,6 +71,7 @@ class CardListBase : public ItemList, public SetView { bool doCut(); bool doCopy(); bool doPaste(); + bool doDelete(); // --------------------------------------------------- : Set actions diff --git a/src/gui/control/item_list.cpp b/src/gui/control/item_list.cpp index 8e398b23..38570aea 100644 --- a/src/gui/control/item_list.cpp +++ b/src/gui/control/item_list.cpp @@ -13,8 +13,8 @@ // ----------------------------------------------------------------------------- : ItemList -ItemList::ItemList(Window* parent, int id, long additional_style) - : wxListView(parent, id, wxDefaultPosition, wxDefaultSize, additional_style | wxLC_REPORT | wxLC_VIRTUAL | wxLC_SINGLE_SEL) +ItemList::ItemList(Window* parent, int id, long additional_style, bool multi_sel) + : wxListView(parent, id, wxDefaultPosition, wxDefaultSize, additional_style | wxLC_REPORT | wxLC_VIRTUAL | (multi_sel ? 0 : wxLC_SINGLE_SEL)) , selected_item_pos(-1) , sort_by_column(-1), sort_ascending(true) { @@ -52,21 +52,23 @@ void ItemList::selectItem(const VoidP& item, bool focus, bool event) { selected_item = item; if (event) sendEvent(); findSelectedItemPos(); - if (focus) { - selectCurrentItem(); - } + if (focus) focusSelectedItem(); } -void ItemList::selectItemPos(long pos, bool focus) { - if (selected_item_pos == pos && !focus) return; // this item is already selected +void ItemList::selectItemPos(long pos, bool focus, bool force_focus) { + VoidP item; if ((size_t)pos < sorted_list.size()) { - // only if there is something to select - selectItem(getItem(pos), false, true); + item = getItem(pos); + } else if (!sorted_list.empty()) { + item = sorted_list.back(); } else { - selectItem(VoidP(), false, true); + // clear selection } - selected_item_pos = pos; - if (focus) selectCurrentItem(); + if (item != selected_item) { + selectItem(item, false, true); + } + //!selected_item_pos = pos; + if (focus) focusSelectedItem(force_focus); } void ItemList::findSelectedItemPos() { @@ -80,18 +82,33 @@ void ItemList::findSelectedItemPos() { } } } -void ItemList::selectCurrentItem() { +void ItemList::focusSelectedItem(bool force_focus) { if (GetItemCount() > 0) { if (selected_item_pos == -1 || (size_t)selected_item_pos > sorted_list.size()) { // deselect currently selected item, if any long sel = GetFirstSelected(); Select(sel, false); - } else { + } else if (selected_item_pos != GetFocusedItem() || force_focus) { Select(selected_item_pos); Focus (selected_item_pos); } } } +void ItemList::focusNone() { + long count = GetItemCount(); + for (long pos = 0 ; pos < count ; ++pos) { + Select(pos, false); + } +} +void ItemList::focusItem(const VoidP& item, bool focus) { + long count = GetItemCount(); + for (long pos = 0 ; pos < count ; ++pos) { + if (getItem(pos) == item) { + Select(pos, focus); + break; + } + } +} // ----------------------------------------------------------------------------- : ItemList : Building the list @@ -124,7 +141,7 @@ void ItemList::refreshList() { if (item_count == 0) Refresh(); // (re)select current item findSelectedItemPos(); - selectCurrentItem(); + focusSelectedItem(); } void ItemList::sortBy(long column, bool ascending) { diff --git a/src/gui/control/item_list.hpp b/src/gui/control/item_list.hpp index 0746483f..269e07ac 100644 --- a/src/gui/control/item_list.hpp +++ b/src/gui/control/item_list.hpp @@ -17,10 +17,14 @@ /// A generic list of items /** The list is shown in report mode, and allows sorting. * Currently used for cards and keywords. + * + * Terminology: + * selected item = a single item in the variable selected_item + * focused items = items that are drawn as selected in the control */ class ItemList : public wxListView { public: - ItemList(Window* parent, int id, long additional_style = 0); + ItemList(Window* parent, int id, long additional_style = 0, bool multi_sel = false); // --------------------------------------------------- : Selection @@ -72,15 +76,20 @@ class ItemList : public wxListView { /// Select an item, send an event to the parent /** If focus then the item is also focused and selected in the actual control. - * This should abviously not be done when the item is selected because it was focused (leading to a loop). + * This should not be done when the item is selected because it was focused (leading to a loop). */ void selectItem(const VoidP& item, bool focus, bool event); /// Select a item at the specified position - void selectItemPos(long pos, bool focus); + void selectItemPos(long pos, bool focus, bool force_focus = false); /// Find the position for the selected_item void findSelectedItemPos(); - /// Actually select the card at selected_item_pos in the control - void selectCurrentItem(); + /// Actually select the item at selected_item_pos in the control + /** if force_focus == true, then the item is highlighted again if it already is focused. */ + void focusSelectedItem(bool force_focus = false); + /// Deselect everything in the control + void focusNone(); + /// Actually select a certain item in the control + void focusItem(const VoidP& item, bool focus = true); // --------------------------------------------------- : Data VoidP selected_item; ///< The currently selected item diff --git a/src/gui/control/keyword_list.cpp b/src/gui/control/keyword_list.cpp index 2c3c90ec..47f291af 100644 --- a/src/gui/control/keyword_list.cpp +++ b/src/gui/control/keyword_list.cpp @@ -57,10 +57,10 @@ void KeywordList::onChangeSet() { } void KeywordList::onAction(const Action& action, bool undone) { - TYPE_CASE(action, AddKeywordAction) { + /*TYPE_CASE(action, AddKeywordAction) { if (action.adding != undone) { // select the new keyword - selectItem(action.keyword, false /*list will be refreshed anyway*/, true); + selectItem(action.keyword, false /*list will be refreshed anyway* /, true); refreshList(); } else { long pos = selected_item_pos; @@ -74,7 +74,7 @@ void KeywordList::onAction(const Action& action, bool undone) { } } } - } + }*/ // TODO!!! TYPE_CASE(action, ValueAction) { if (!action.card) { KeywordTextValue* value = dynamic_cast(action.valueP.get()); @@ -117,7 +117,7 @@ bool KeywordList::doCut() { // cut = copy + delete if (!canCut()) return false; if (!doCopy()) return false; - set->actions.add(new AddKeywordAction(REMOVE, *set, getKeyword())); + doDelete(); return true; } bool KeywordList::doPaste() { @@ -137,6 +137,10 @@ bool KeywordList::doPaste() { return false; } } +bool KeywordList::doDelete() { + set->actions.add(new AddKeywordAction(REMOVE, *set, getKeyword())); + return true; +} // ----------------------------------------------------------------------------- : KeywordListBase : for ItemList diff --git a/src/gui/control/keyword_list.hpp b/src/gui/control/keyword_list.hpp index 7faa5585..92057bcc 100644 --- a/src/gui/control/keyword_list.hpp +++ b/src/gui/control/keyword_list.hpp @@ -60,6 +60,7 @@ class KeywordList : public ItemList, public SetView { bool doCut(); bool doCopy(); bool doPaste(); + bool doDelete(); // --------------------------------------------------- : The keywords protected: diff --git a/src/gui/set/keywords_panel.cpp b/src/gui/set/keywords_panel.cpp index 54ce6a71..df43fdf9 100644 --- a/src/gui/set/keywords_panel.cpp +++ b/src/gui/set/keywords_panel.cpp @@ -154,7 +154,7 @@ void KeywordsPanel::onCommand(int id) { list->selectNext(); break; case ID_KEYWORD_ADD: - set->actions.add(new AddKeywordAction(ADD, *set)); + set->actions.add(new AddKeywordAction(*set)); break; case ID_KEYWORD_REMOVE: if (!list->getKeyword()->fixed) { diff --git a/src/gui/symbol/selection.cpp b/src/gui/symbol/selection.cpp index 72f34ee5..2e2ccebc 100644 --- a/src/gui/symbol/selection.cpp +++ b/src/gui/symbol/selection.cpp @@ -25,7 +25,7 @@ void SymbolPartsSelection::clear() { } bool SymbolPartsSelection::select(const SymbolPartP& part, SelectMode mode) { - assert(part); + if (!part) return false; // make sure part is not the decendent of a part that is already selected if (mode != SELECT_OVERRIDE) { FOR_EACH(s, selection) { diff --git a/src/mse.vcproj b/src/mse.vcproj index da1d90f1..1d764557 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -1422,6 +1422,9 @@ + + data) { - v->update(ctx); + if (action.action.adding != undone) { + // update the added cards specificly + FOR_EACH_CONST(step, action.action.steps) { + const CardP& card = step.item; + Context& ctx = getContext(card); + FOR_EACH(v, card->data) { + v->update(ctx); + } + } } // note: fallthrough }