From f22046d77b7eac2d8a7d6869d5fef992447b0c12 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: Wed, 3 Dec 2025 17:50:48 +0100 Subject: [PATCH] prevent drag and drop from within the same card list --- src/data/format/clipboard.cpp | 15 +++++++++------ src/data/format/clipboard.hpp | 9 +++++---- src/gui/control/card_list.cpp | 22 +++++++++++++--------- src/gui/control/card_list.hpp | 6 ++++-- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/data/format/clipboard.cpp b/src/data/format/clipboard.cpp index 27714b60..6b11840c 100644 --- a/src/data/format/clipboard.cpp +++ b/src/data/format/clipboard.cpp @@ -45,6 +45,7 @@ void deserialize_from_clipboard(T& object, Package& package, const String& data) struct WrappedCards { Game* expected_game; String game_name; + String id; vector cards; DECLARE_REFLECTION(); @@ -52,6 +53,7 @@ struct WrappedCards { IMPLEMENT_REFLECTION(WrappedCards) { REFLECT(game_name); + REFLECT(id); if (game_name == expected_game->name()) { WITH_DYNAMIC_ARG(game_for_reading, expected_game); REFLECT(cards); @@ -61,7 +63,7 @@ IMPLEMENT_REFLECTION(WrappedCards) { wxDataFormat CardsDataObject::format = _("application/x-mse-cards"); -CardsDataObject::CardsDataObject(const SetP& set, const vector& cards) { +CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector& cards) { // set the stylesheet, so when deserializing we know whos style options we are reading vector has_styling; for (size_t i = 0 ; i < cards.size() ; ++i) { @@ -70,7 +72,7 @@ CardsDataObject::CardsDataObject(const SetP& set, const vector& cards) { cards[i]->stylesheet = set->stylesheet; } } - WrappedCards data = { set->game.get(), set->game->name(), cards }; + WrappedCards data = { set->game.get(), set->game->name(), id, cards }; SetText(serialize_for_clipboard(*set, data)); // restore cards for (size_t i = 0 ; i < cards.size() ; ++i) { @@ -85,10 +87,11 @@ CardsDataObject::CardsDataObject() { SetFormat(format); } -bool CardsDataObject::getCards(const SetP& set, vector& out) { +bool CardsDataObject::getCards(const SetP& set, const String id, vector& out) { WrappedCards data = { set->game.get(), set->game->name() }; deserialize_from_clipboard(data, *set, GetText()); if (data.cards.empty()) return false; + if (!id.empty() && data.id == id) return false; if (data.game_name == set->game->name()) { // Cards are from the same game out = data.cards; @@ -140,7 +143,7 @@ KeywordP KeywordDataObject::getKeyword(const SetP& set) { // ----------------------------------------------------------------------------- : Card on clipboard -CardsOnClipboard::CardsOnClipboard(const SetP& set, const vector& cards) { +CardsOnClipboard::CardsOnClipboard(const SetP& set, const String id, const vector& cards) { // Conversion to image file if (cards.size() < 6) { Image img; @@ -156,6 +159,6 @@ CardsOnClipboard::CardsOnClipboard(const SetP& set, const vector& cards) data->AddFile(temp_path); Add(data); } - // Conversion to serialized card format - Add(new CardsDataObject(set, cards), true); + // Conversion to serialized card format + Add(new CardsDataObject(set, id, cards), true); } diff --git a/src/data/format/clipboard.hpp b/src/data/format/clipboard.hpp index 3bdf0353..fbaedce8 100644 --- a/src/data/format/clipboard.hpp +++ b/src/data/format/clipboard.hpp @@ -25,11 +25,12 @@ public: CardsDataObject(); /// Store a card - CardsDataObject(const SetP& set, const vector& cards); + CardsDataObject(const SetP& set, const String id, const vector& cards); - /// Retrieve the cards, only if it is made with the same game as set + /// Retrieve the cards, only if this is made with the same game as set + /// And if this is NOT of the same id as the given one /** Return true if the cards are correctly retrieved, and there is at least one card */ - bool getCards(const SetP& set, vector& out); + bool getCards(const SetP& set, const String id, vector& out); }; // ----------------------------------------------------------------------------- : KeywordDataObject @@ -53,6 +54,6 @@ public: /// A DataObject for putting one or more cards on the clipboard, in multiple formats class CardsOnClipboard : public wxDataObjectComposite { public: - CardsOnClipboard(const SetP& set, const vector& cards); + CardsOnClipboard(const SetP& set, const String id, const vector& cards); }; diff --git a/src/gui/control/card_list.cpp b/src/gui/control/card_list.cpp index f5885259..2af3ae63 100644 --- a/src/gui/control/card_list.cpp +++ b/src/gui/control/card_list.cpp @@ -7,6 +7,7 @@ // ----------------------------------------------------------------------------- : Includes #include +#include #include #include #include // for sorting all cardlists in a window @@ -163,7 +164,7 @@ bool CardListBase::doCopy() { if (cards_to_copy.empty()) return false; // put on clipboard if (!wxTheClipboard->Open()) return false; - bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, cards_to_copy)); // ignore result + bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result wxTheClipboard->Close(); return ok; } @@ -189,7 +190,7 @@ bool CardListBase::doCopyCardAndLinkedCards() { } } } - bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, cards_to_copy)); // ignore result + bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result wxTheClipboard->Close(); return ok; } @@ -199,7 +200,7 @@ bool CardListBase::doPaste() { if (!wxTheClipboard->Open()) return false; bool ok = wxTheClipboard->GetData(*drop_target->data_object); wxTheClipboard->Close(); - if (ok) return parseData(); + if (ok) return parseData(false); return false; } @@ -328,14 +329,15 @@ bool CardListBase::parseText(String& text, vector& out) { return j < out.size(); } -bool CardListBase::parseData() { +bool CardListBase::parseData(bool ignore_cards_from_own_card_list) { wxBusyCursor wait; wxDataFormat format = drop_target->data_object->GetReceivedFormat(); wxDataObject *data = drop_target->data_object->GetObject(format); vector new_cards; - if (CardsDataObject* card_data = dynamic_cast(data)) { - card_data->getCards(set, new_cards); + if (CardsDataObject* card_data = dynamic_cast(data)) { + String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _(""); + card_data->getCards(set, id, new_cards); } else switch (format.GetType()) { @@ -596,7 +598,9 @@ void CardListBase::onChar(wxKeyEvent& ev) { void CardListBase::onBeginDrag(wxListEvent&) { vector cards; getSelection(cards); - CardsOnClipboard* card_data = new CardsOnClipboard(set, cards); + String transaction_id = generate_uid(); + CardsOnClipboard* card_data = new CardsOnClipboard(set, transaction_id, cards); + drop_target->ignored_id = transaction_id; wxDropSource drag_source(this); drag_source.SetData(*card_data); drag_source.DoDragDrop(wxDrag_CopyOnly); @@ -645,7 +649,7 @@ void CardListBase::onItemActivate(wxListEvent& ev) { // ----------------------------------------------------------------------------- : CardListDropTarget CardListDropTarget::CardListDropTarget(CardListBase* card_list) - : card_list(card_list) + : card_list(card_list), ignored_id(_("")) { data_object = new wxDataObjectComposite(); data_object->Add(new CardsDataObject(), true); @@ -659,7 +663,7 @@ CardListDropTarget::~CardListDropTarget() {} wxDragResult CardListDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult defaultDragResult) { if (!GetData()) return wxDragNone; - if (!card_list->parseData()) return wxDragError; + if (!card_list->parseData(true)) return wxDragError; return wxDragCopy; } diff --git a/src/gui/control/card_list.hpp b/src/gui/control/card_list.hpp index 557814dd..8287c1d1 100644 --- a/src/gui/control/card_list.hpp +++ b/src/gui/control/card_list.hpp @@ -86,7 +86,7 @@ public: bool doAddJSON(); // Look for cards inside some given data - bool parseData(); + bool parseData(bool ignore_cards_from_own_card_list); bool parseUrl (String& url, vector& out); bool parseFiles(wxArrayString& filenames, vector& out); bool parseText (String& text, vector& out); @@ -177,7 +177,9 @@ public: wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult defaultDragResult) override; - wxDataObjectComposite* data_object; ///< the object that acquires the data from the Clipboard or a Drag'n'Drop + wxDataObjectComposite* data_object; ///< the object that acquires the data from the Clipboard or a Drag'n'Drop + + String ignored_id; ///< the id of the transaction we need to ignore (the one coming from our own card_list) private: CardListBase* card_list; ///< the card list we are the drop target of };