From 2932d0007d9c764452082a756429b1ebedd0b054 Mon Sep 17 00:00:00 2001 From: GenevensiS <66968533+G-e-n-e-v-e-n-s-i-S@users.noreply.github.com> Date: Thu, 4 Dec 2025 15:44:04 +0100 Subject: [PATCH] Bulk card modification --- resource/tool/card_modify_multiple.png | Bin 0 -> 4622 bytes resource/win32_res.rc | 1 + src/data/action/set.cpp | 27 ++ src/data/action/set.hpp | 30 +++ src/data/action/value.cpp | 32 ++- src/data/action/value.hpp | 52 ++-- src/gui/bulk_modification_window.cpp | 330 +++++++++++++++++++++++++ src/gui/bulk_modification_window.hpp | 48 ++++ src/gui/control/card_list.cpp | 12 +- src/gui/control/card_list.hpp | 8 +- src/gui/set/cards_panel.cpp | 4 + src/util/window_id.hpp | 7 +- 12 files changed, 527 insertions(+), 24 deletions(-) create mode 100644 resource/tool/card_modify_multiple.png create mode 100644 src/gui/bulk_modification_window.cpp create mode 100644 src/gui/bulk_modification_window.hpp diff --git a/resource/tool/card_modify_multiple.png b/resource/tool/card_modify_multiple.png new file mode 100644 index 0000000000000000000000000000000000000000..eb3d9b22b611ec9232fff57526fb5e800f18cf7b GIT binary patch literal 4622 zcmeHKeNYo;8sA72MXR92kE-Vq&=GNyO|n^%Jt81M6C@A;75o_4>~3Jqr^!MB*i#X0 zIeSc%ij~7^tF2XAM#Vc7M5TUDsV-;cf*G;*O?ntDXX%{2ihLQ7Ws`@I8SolAJCUsfO4GI;%{?Bu(Kkk+YYQ?#<< zZtc`xqbqjoZbdJnUp^W*Y)z9Vf6wLerPl_1>+fMl*4Dj9tT*T8?RQPRAFWA`PpKA^ zR)sv6Qd+S@opdGBWW+9-;n(*#VYT2In)Y5XTDJ;<1O;qNj9wcP)13@Rq3nYVD$U8L zvFkiv$Hh+b%l4mpPQUfhmq`=m1g=m2;$YyyEcD2;5v5p2sHiC4R8zC<^qw{AE6RtL z=fiD2w?&H3N=>0>^4igoo6GA@=6QZ~v`&Pvz47uq!>T=LvxtB(&h~kd=08I}1brMl zO_H2w99_{oVQFjglb53JD~>*VHNhvYhF+BzQY5*t@1yXKcKo&E$DD17Qx`VQT#*pL zTpCz7>4>PRRKir99*(g&7#I^_A{2>rv)NMN3_m!+K^uuA^{g%kFj5IK zInGXq#V(ginXOaW_DoWwY7 zSq_Sc&1S4zaBm2j>hZT{In3U4XiChO84ECVf>|Yfrkt(S>3ckQ3Nl!W-RlL&?qkWZ z#y4d3iH+BI)9D=uaPPtGW8Iy**BDsobcEVQW%1!@)hZ!BKSA3lmL|Nf5(ZV$jNFJA zPz*&d95*7QTuCFCoRmssC?>^8LoX<;)ya`ois7LExQGQfQi)uOp%My_Q51z>j8cvm z7&(r}XqiMIBXLTpko1B`bg-Z+NptV0cqke`84L!RmID+ejRGiKfguVhra%~@QHmMl z6ef{My-+ko%(6KwBq%3qAu|}U-J0Q5@Prf5daX(*6`^k=dNauxfdg0rtd+L8oNrVq ztc6MDNS;qgxLl${6;fP@<5;)?dt)@8aX3LQ@~9G2B*VQLzAywx2T)7$oeBWFa*z!X z<6ub6=18&G%qk%t6wG_}sC8gL(IiKzNsa-as8mj%;owSP*2&W;3)mPJq>^qB2Qq z1_Snwu7>TFv%k>{BpR-yNJ@&(7-m2)62(Ag;S54yC?z3r98{9&i|(`;ITz_*qB8)G zfGg0TUasJ&U8M@`YwyZr_&NZ}5HuWIJ(LN>UCE019iuzj2=RaM5#crHwZ#CxP8ry` zz)mRc*$TV(;y0b&@zYg@-*E;2-9O1&@!L;VKV5Idz*`yjcUM1MZ^gh{8TWVB|BWuc zH-{<43jP7Pz)|Van(J-gm^H{SXSN!8&40I7?jlV1ofew!Hfe%=G+5;9hPX7Ab7l()E-s=cx&-(iU zI4C@S?YM?ln`#^GU2GYC>NW!5f57+IB3BD!=c`ZW?9^;kqA!*{{VKp9c!k$PHxJd# zJ-Mbsb_v;-yRN>hFf{4h#ex%UV{ZFv+zXFSTGVoOKT-=mKf`MswLv885ciFpSEOE+}-1M d9#xjV7+-U2*X9U3Yz!zZq>W8bm(NVk{|~V$vTy(Z literal 0 HcmV?d00001 diff --git a/resource/win32_res.rc b/resource/win32_res.rc index 4d052b5c..21d8b6bd 100644 --- a/resource/win32_res.rc +++ b/resource/win32_res.rc @@ -55,6 +55,7 @@ tool/no_auto IMAGE "tool/no_auto.png" tool/card_add IMAGE "tool/card_add.png" tool/card_add_multiple IMAGE "tool/card_add_multiple.png" +tool/card_modify_multiple IMAGE "tool/card_modify_multiple.png" tool/card_del IMAGE "tool/card_del.png" tool/card_link IMAGE "tool/card_link.png" tool/card_copy IMAGE "tool/card_copy.png" diff --git a/src/data/action/set.cpp b/src/data/action/set.cpp index 8f445e87..a5470368 100644 --- a/src/data/action/set.cpp +++ b/src/data/action/set.cpp @@ -212,7 +212,34 @@ String ChangeCardHasStylingAction::getName(bool to_undo) const { void ChangeCardHasStylingAction::perform(bool to_undo) { card->has_styling = !card->has_styling; swap(card->styling_data, styling_data); +} + +// ----------------------------------------------------------------------------- : Change notes + +ChangeCardNotesAction::ChangeCardNotesAction(const CardP& card, const String& notes) + : card(card), notes(notes) +{} +String ChangeCardNotesAction::getName(bool to_undo) const { + return _("Change notes"); } +void ChangeCardNotesAction::perform(bool to_undo) { + swap(card->notes, notes); +} + +// ----------------------------------------------------------------------------- : Change uid + +ChangeCardUIDAction::ChangeCardUIDAction(Set& set, const CardP& card, const String& uid) + : CardListAction(set), card(card), uid(uid) +{} +String ChangeCardUIDAction::getName(bool to_undo) const { + return _("Change ID"); +} +void ChangeCardUIDAction::perform(bool to_undo) { + FOR_EACH(c, set.cards) { + c->updateLink(card->uid, uid); + } + swap(card->uid, uid); +} // ----------------------------------------------------------------------------- : Pack types diff --git a/src/data/action/set.hpp b/src/data/action/set.hpp index 9e43864c..d8156466 100644 --- a/src/data/action/set.hpp +++ b/src/data/action/set.hpp @@ -147,8 +147,38 @@ public: Set& set; ///< The set to copy styling from CardP card; ///< The affected card IndexMap styling_data; ///< The old styling of the card +}; + +// ----------------------------------------------------------------------------- : Change notes + +/// Changing the notes of a card +class ChangeCardNotesAction : public Action { +public: + ChangeCardNotesAction(const CardP& card, const String& notes); + + String getName(bool to_undo) const override; + void perform(bool to_undo) override; + + //private: + CardP card; ///< The affected card + String notes; ///< Its old notes }; +// ----------------------------------------------------------------------------- : Change uid + +/// Changing the uid of a card +class ChangeCardUIDAction : public CardListAction { +public: + ChangeCardUIDAction(Set& set, const CardP& card, const String& id); + + String getName(bool to_undo) const override; + void perform(bool to_undo) override; + + //private: + CardP card; ///< The affected card + String uid; ///< Its old uid +}; + // ----------------------------------------------------------------------------- : Pack types /// An Action the changes the pack types of a set diff --git a/src/data/action/value.cpp b/src/data/action/value.cpp index 2cd5bb55..888bdf5a 100644 --- a/src/data/action/value.cpp +++ b/src/data/action/value.cpp @@ -36,7 +36,10 @@ void ValueAction::setCard(CardP const& card) { } // ----------------------------------------------------------------------------- : Simple - + +unique_ptr value_action(const TextValueP& value, const Defaultable& new_value) { + return make_unique>(value, new_value); +} unique_ptr value_action(const ChoiceValueP& value, const Defaultable& new_value) { return make_unique>(value, new_value); } @@ -205,7 +208,34 @@ String ScriptStyleEvent::getName(bool) const { } void ScriptStyleEvent::perform(bool) { assert(false); // this action is just an event, it should not be performed +} + +// ----------------------------------------------------------------------------- : Bulk action + +BulkAction::BulkAction(const vector>& actions, const SetP& set, CardListBase* card_list_window) + : actions(actions), set(set), card_list_window(card_list_window) +{ + if (actions.empty()) throw InternalError(_("BulkAction created with no actions")); + name_do = actions.front()->getName(false) + _(" ") + _ACTION_("bulk"); + name_undo = actions.front()->getName(true) + _(" ") + _ACTION_("bulk"); } +BulkAction::~BulkAction() {} + +String BulkAction::getName(bool to_undo) const { + return to_undo ? name_undo : name_do; +} + +void BulkAction::perform(bool to_undo) { + FOR_EACH(action, actions) { + action->perform(to_undo); + set->actions.tellListeners(*action, to_undo); + } + card_list_window->Refresh(); +} + +bool BulkAction::merge(const Action& action) { + return false; +} // ----------------------------------------------------------------------------- : Action performer diff --git a/src/data/action/value.hpp b/src/data/action/value.hpp index 3a5c736f..f7ba1606 100644 --- a/src/data/action/value.hpp +++ b/src/data/action/value.hpp @@ -23,6 +23,7 @@ #include #include #include +#include class StyleSheet; class LocalFileName; @@ -30,15 +31,8 @@ DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(Set); DECLARE_POINTER_TYPE(Value); DECLARE_POINTER_TYPE(Style); -DECLARE_POINTER_TYPE(TextValue); -DECLARE_POINTER_TYPE(ChoiceValue); -DECLARE_POINTER_TYPE(MultipleChoiceValue); -DECLARE_POINTER_TYPE(ColorValue); -DECLARE_POINTER_TYPE(ImageValue); -DECLARE_POINTER_TYPE(SymbolValue); -DECLARE_POINTER_TYPE(PackageChoiceValue); -// ----------------------------------------------------------------------------- : ValueAction (based class) +// ----------------------------------------------------------------------------- : ValueAction (base class) /// An Action the changes a Value class ValueAction : public Action { @@ -72,6 +66,15 @@ inline void swap_value(MultipleChoiceValue& a, MultipleChoiceValue::ValueType& b swap(a.last_change, b.last_change); } +/// Action that updates a Value to a new value +unique_ptr value_action(const TextValueP& value, const Defaultable& new_value); +unique_ptr value_action(const ChoiceValueP& value, const Defaultable& new_value); +unique_ptr value_action(const MultipleChoiceValueP& value, const Defaultable& new_value, const String& last_change); +unique_ptr value_action(const ColorValueP& value, const Defaultable& new_value); +unique_ptr value_action(const ImageValueP& value, const LocalFileName& new_value); +unique_ptr value_action(const SymbolValueP& value, const LocalFileName& new_value); +unique_ptr value_action(const PackageChoiceValueP& value, const String& new_value); + /// A ValueAction that swaps between old and new values template class SimpleValueAction : public ValueAction { @@ -79,13 +82,13 @@ public: inline SimpleValueAction(const intrusive_ptr& value, const typename T::ValueType& new_value) : ValueAction(value), new_value(new_value) {} - + void perform(bool to_undo) override { ValueAction::perform(to_undo); swap_value(static_cast(*valueP), new_value); valueP->onAction(*this, to_undo); // notify value } - + bool merge(const Action& action) override { if (!ALLOW_MERGE) return false; TYPE_CASE(action, SimpleValueAction) { @@ -97,18 +100,10 @@ public: } return false; } - + typename T::ValueType new_value; }; -/// Action that updates a Value to a new value -unique_ptr value_action(const ChoiceValueP& value, const Defaultable& new_value); -unique_ptr value_action(const MultipleChoiceValueP& value, const Defaultable& new_value, const String& last_change); -unique_ptr value_action(const ColorValueP& value, const Defaultable& new_value); -unique_ptr value_action(const ImageValueP& value, const LocalFileName& new_value); -unique_ptr value_action(const SymbolValueP& value, const LocalFileName& new_value); -unique_ptr value_action(const PackageChoiceValueP& value, const String& new_value); - // ----------------------------------------------------------------------------- : Text /// An action that changes a TextValue @@ -206,6 +201,25 @@ public: const Style* style; ///< The modified style }; +// ----------------------------------------------------------------------------- : Bulk action + +// An action that's just a list of other actions +class BulkAction : public Action { +public: + BulkAction(const vector>& actions, const SetP& set, CardListBase* card_list_window); + ~BulkAction() override; + + String getName(bool to_undo) const override; + void perform(bool to_undo) override; + bool merge(const Action& action) override; + +private: + String name_do; + String name_undo; + vector> actions; + SetP set; + CardListBase* card_list_window; +}; // ----------------------------------------------------------------------------- : Action performer diff --git a/src/gui/bulk_modification_window.cpp b/src/gui/bulk_modification_window.cpp new file mode 100644 index 00000000..edeb71d4 --- /dev/null +++ b/src/gui/bulk_modification_window.cpp @@ -0,0 +1,330 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) Twan van Laarhoven and the other MSE developers | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +// ----------------------------------------------------------------------------- : Includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include