From 135beab53117efcca97befc213ff4e37709dc66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 12 May 2026 19:51:37 +0200 Subject: [PATCH] Revert UI. Took 25 minutes Took 5 seconds --- cockatrice/CMakeLists.txt | 107 --- cockatrice/src/filters/deck_filter_string.cpp | 213 ------ cockatrice/src/filters/deck_filter_string.h | 55 -- .../src/game/deckview/deck_view_container.cpp | 40 +- .../src/game/deckview/deck_view_container.h | 2 - .../widgets/cards/card_size_widget.cpp | 1 - .../cards/deck_card_zone_display_widget.cpp | 251 ------- .../cards/deck_card_zone_display_widget.h | 78 -- .../deck_preview_card_picture_widget.cpp | 62 -- .../cards/deck_preview_card_picture_widget.h | 44 -- .../deck_editor_database_display_widget.cpp | 17 +- .../deck_editor_deck_dock_widget.cpp | 18 - .../deck_editor_deck_dock_widget.h | 5 +- .../widgets/dialogs/dlg_settings.cpp | 103 --- .../interface/widgets/dialogs/dlg_settings.h | 13 - .../widgets/general/background_sources.cpp | 3 - .../widgets/general/background_sources.h | 68 -- .../widgets/general/home_styled_button.cpp | 103 --- .../widgets/general/home_styled_button.h | 25 - .../interface/widgets/general/home_widget.cpp | 377 ---------- .../interface/widgets/general/home_widget.h | 52 -- .../printing_selector_card_overlay_widget.cpp | 1 + .../widgets/tabs/abstract_tab_deck_editor.h | 3 +- .../archidekt_deck_listing_api_response.cpp | 29 - .../archidekt_deck_listing_api_response.h | 22 - .../api_response/archidekt_formats.h | 227 ------ .../card/archidekt_api_response_card.cpp | 61 -- .../card/archidekt_api_response_card.h | 68 -- .../archidekt_api_response_card_entry.cpp | 68 -- .../card/archidekt_api_response_card_entry.h | 65 -- .../card/archidekt_api_response_edition.cpp | 19 - .../card/archidekt_api_response_edition.h | 51 -- .../deck/archidekt_api_response_deck.cpp | 79 --- .../deck/archidekt_api_response_deck.h | 76 -- .../archidekt_api_response_deck_category.cpp | 19 - .../archidekt_api_response_deck_category.h | 55 -- ...kt_api_response_deck_listing_container.cpp | 64 -- ...dekt_api_response_deck_listing_container.h | 133 ---- .../archidekt_api_response_deck_owner.cpp | 22 - .../archidekt_api_response_deck_owner.h | 36 - ...idekt_api_response_deck_display_widget.cpp | 218 ------ ...chidekt_api_response_deck_display_widget.h | 129 ---- ...api_response_deck_entry_display_widget.cpp | 237 ------- ...t_api_response_deck_entry_display_widget.h | 121 ---- ..._response_deck_listings_display_widget.cpp | 58 -- ...pi_response_deck_listings_display_widget.h | 98 --- ...dekt_deck_preview_image_display_widget.cpp | 80 --- ...hidekt_deck_preview_image_display_widget.h | 66 -- .../tabs/api/archidekt/tab_archidekt.cpp | 669 ------------------ .../tabs/api/archidekt/tab_archidekt.h | 294 -------- .../edhrec_api_response_archidekt_links.cpp | 42 -- .../edhrec_api_response_archidekt_links.h | 39 - .../edhrec_average_deck_api_response.cpp | 47 -- .../edhrec_average_deck_api_response.h | 33 - .../average_deck/edhrec_deck_api_response.cpp | 23 - .../average_deck/edhrec_deck_api_response.h | 27 - .../edhrec_api_response_card_prices.cpp | 31 - .../edhrec_api_response_card_prices.h | 72 -- .../edhrec_api_response_card_container.cpp | 49 -- .../edhrec_api_response_card_container.h | 64 -- .../edhrec_api_response_card_details.cpp | 36 - .../cards/edhrec_api_response_card_details.h | 35 - .../cards/edhrec_api_response_card_list.cpp | 33 - .../cards/edhrec_api_response_card_list.h | 32 - ...mmander_api_response_commander_details.cpp | 90 --- ...commander_api_response_commander_details.h | 178 ----- .../edhrec_commander_api_response.cpp | 45 -- .../commander/edhrec_commander_api_response.h | 31 - ...r_api_response_average_deck_statistics.cpp | 15 - ...der_api_response_average_deck_statistics.h | 26 - .../edhrec_top_cards_api_response.cpp | 19 - .../top_cards/edhrec_top_cards_api_response.h | 25 - .../edhrec_top_commanders_api_response.cpp | 19 - .../edhrec_top_commanders_api_response.h | 25 - .../top_tags/edhrec_top_tags_api_response.cpp | 19 - .../top_tags/edhrec_top_tags_api_response.h | 25 - ...pi_response_card_prices_display_widget.cpp | 66 -- ..._api_response_card_prices_display_widget.h | 48 -- ...i_response_card_details_display_widget.cpp | 87 --- ...api_response_card_details_display_widget.h | 50 -- ...response_card_inclusion_display_widget.cpp | 41 -- ...i_response_card_inclusion_display_widget.h | 33 - ..._api_response_card_list_display_widget.cpp | 33 - ...ec_api_response_card_list_display_widget.h | 35 - ...i_response_card_synergy_display_widget.cpp | 28 - ...api_response_card_synergy_display_widget.h | 31 - ...ponse_commander_details_display_widget.cpp | 82 --- ...esponse_commander_details_display_widget.h | 44 -- ...api_response_bracket_navigation_widget.cpp | 95 --- ...r_api_response_bracket_navigation_widget.h | 37 - ..._api_response_budget_navigation_widget.cpp | 97 --- ...er_api_response_budget_navigation_widget.h | 37 - ..._commander_api_response_display_widget.cpp | 103 --- ...ec_commander_api_response_display_widget.h | 35 - ...mmander_api_response_navigation_widget.cpp | 89 --- ...commander_api_response_navigation_widget.h | 51 -- ..._top_cards_api_response_display_widget.cpp | 45 -- ...ec_top_cards_api_response_display_widget.h | 31 - ...commanders_api_response_display_widget.cpp | 47 -- ...p_commanders_api_response_display_widget.h | 31 - ...c_top_tags_api_response_display_widget.cpp | 45 -- ...rec_top_tags_api_response_display_widget.h | 30 - .../widgets/tabs/api/edhrec/tab_edhrec.cpp | 108 --- .../widgets/tabs/api/edhrec/tab_edhrec.h | 41 -- .../tabs/api/edhrec/tab_edhrec_main.cpp | 391 ---------- .../widgets/tabs/api/edhrec/tab_edhrec_main.h | 74 -- .../interface/widgets/tabs/tab_deck_editor.h | 1 - .../src/interface/widgets/tabs/tab_home.cpp | 11 - .../src/interface/widgets/tabs/tab_home.h | 33 - .../interface/widgets/tabs/tab_supervisor.cpp | 166 +---- .../interface/widgets/tabs/tab_supervisor.h | 19 +- .../tabs/tab_visual_database_display.cpp | 20 - .../tabs/tab_visual_database_display.h | 31 - .../tab_deck_editor_visual.cpp | 331 --------- .../tab_deck_editor_visual.h | 176 ----- .../tab_deck_editor_visual_tab_widget.cpp | 168 ----- .../tab_deck_editor_visual_tab_widget.h | 137 ---- .../tab_deck_storage_visual.cpp | 35 - .../tab_deck_storage_visual.h | 48 -- ...l_database_display_color_filter_widget.cpp | 252 ------- ...ual_database_display_color_filter_widget.h | 71 -- .../visual_database_display_filter_button.h | 21 - ...tabase_display_filter_save_load_widget.cpp | 159 ----- ...database_display_filter_save_load_widget.h | 50 -- ...database_display_filter_toolbar_widget.cpp | 158 ----- ...l_database_display_filter_toolbar_widget.h | 50 -- ..._display_format_legality_filter_widget.cpp | 221 ------ ...se_display_format_legality_filter_widget.h | 46 -- ...tabase_display_main_type_filter_widget.cpp | 217 ------ ...database_display_main_type_filter_widget.h | 51 -- ...al_database_display_name_filter_widget.cpp | 176 ----- ...sual_database_display_name_filter_widget.h | 52 -- ...ual_database_display_set_filter_widget.cpp | 282 -------- ...isual_database_display_set_filter_widget.h | 66 -- ...atabase_display_sub_type_filter_widget.cpp | 225 ------ ..._database_display_sub_type_filter_widget.h | 51 -- .../visual_database_display_widget.cpp | 377 ---------- .../visual_database_display_widget.h | 131 ---- .../visual_database_filter_display_widget.cpp | 80 --- .../visual_database_filter_display_widget.h | 46 -- .../visual_deck_display_options_widget.cpp | 125 ---- .../visual_deck_display_options_widget.h | 138 ---- .../visual_deck_editor_placeholder_widget.cpp | 41 -- .../visual_deck_editor_placeholder_widget.h | 22 - .../visual_deck_editor_sample_hand_widget.cpp | 138 ---- .../visual_deck_editor_sample_hand_widget.h | 47 -- .../visual_deck_editor_widget.cpp | 417 ----------- .../visual_deck_editor_widget.h | 106 --- ...k_preview_color_identity_filter_widget.cpp | 120 ---- ...eck_preview_color_identity_filter_widget.h | 43 -- .../deck_preview_deck_tags_display_widget.cpp | 191 ----- .../deck_preview_deck_tags_display_widget.h | 42 -- .../deck_preview_tag_addition_widget.cpp | 88 --- .../deck_preview_tag_addition_widget.h | 32 - .../deck_preview/deck_preview_tag_dialog.cpp | 190 ----- .../deck_preview/deck_preview_tag_dialog.h | 50 -- .../deck_preview_tag_display_widget.cpp | 132 ---- .../deck_preview_tag_display_widget.h | 80 --- .../deck_preview_tag_item_widget.cpp | 20 - .../deck_preview_tag_item_widget.h | 28 - .../deck_preview/deck_preview_widget.cpp | 517 -------------- .../deck_preview/deck_preview_widget.h | 128 ---- ...ual_deck_storage_folder_display_widget.cpp | 225 ------ ...isual_deck_storage_folder_display_widget.h | 49 -- ...ual_deck_storage_quick_settings_widget.cpp | 186 ----- ...isual_deck_storage_quick_settings_widget.h | 73 -- .../visual_deck_storage_search_widget.cpp | 81 --- .../visual_deck_storage_search_widget.h | 33 - .../visual_deck_storage_sort_widget.cpp | 117 --- .../visual_deck_storage_sort_widget.h | 47 -- .../visual_deck_storage_tag_filter_widget.cpp | 176 ----- .../visual_deck_storage_tag_filter_widget.h | 37 - .../visual_deck_storage_widget.cpp | 214 ------ .../visual_deck_storage_widget.h | 75 -- 174 files changed, 14 insertions(+), 15702 deletions(-) delete mode 100644 cockatrice/src/filters/deck_filter_string.cpp delete mode 100644 cockatrice/src/filters/deck_filter_string.h delete mode 100644 cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.h delete mode 100644 cockatrice/src/interface/widgets/general/background_sources.cpp delete mode 100644 cockatrice/src/interface/widgets/general/background_sources.h delete mode 100644 cockatrice/src/interface/widgets/general/home_styled_button.cpp delete mode 100644 cockatrice/src/interface/widgets/general/home_styled_button.h delete mode 100644 cockatrice/src/interface/widgets/general/home_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/general/home_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.h delete mode 100644 cockatrice/src/interface/widgets/tabs/tab_home.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/tab_home.h delete mode 100644 cockatrice/src/interface/widgets/tabs/tab_visual_database_display.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h delete mode 100644 cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h delete mode 100644 cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h delete mode 100644 cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp delete mode 100644 cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp delete mode 100644 cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 1d07371d8..d1186dec1 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -51,7 +51,6 @@ set(cockatrice_SOURCES src/interface/widgets/dialogs/dlg_view_log.cpp src/interface/widgets/dialogs/override_printing_warning.cpp src/interface/widgets/dialogs/tip_of_the_day.cpp - src/filters/deck_filter_string.cpp src/filters/filter_builder.cpp src/filters/filter_tree_model.cpp src/filters/syntax_help.cpp @@ -145,33 +144,6 @@ set(cockatrice_SOURCES src/interface/widgets/cards/card_info_picture_with_text_overlay_widget.cpp src/interface/widgets/cards/card_info_text_widget.cpp src/interface/widgets/cards/card_size_widget.cpp - src/interface/widgets/cards/deck_card_zone_display_widget.cpp - src/interface/widgets/cards/deck_preview_card_picture_widget.cpp - src/interface/widgets/deck_analytics/abstract_analytics_panel_widget.cpp - src/interface/widgets/deck_analytics/add_analytics_panel_dialog.cpp - src/interface/widgets/deck_analytics/analytics_panel_widget_factory.cpp - src/interface/widgets/deck_analytics/analytics_panel_widget_registrar.cpp - src/interface/widgets/deck_analytics/deck_analytics_widget.cpp - src/interface/widgets/deck_analytics/deck_list_statistics_analyzer.cpp - src/interface/widgets/deck_analytics/resizable_panel.cpp - src/interface/widgets/deck_analytics/analyzer_modules/draw_probability/draw_probability_config.cpp - src/interface/widgets/deck_analytics/analyzer_modules/draw_probability/draw_probability_config_dialog.cpp - src/interface/widgets/deck_analytics/analyzer_modules/draw_probability/draw_probability_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_base/mana_base_config.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_base/mana_base_config_dialog.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_base/mana_base_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_config.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_config_dialog.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_devotion/mana_devotion_config.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_devotion/mana_devotion_config_dialog.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_devotion/mana_devotion_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_config.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_config_dialog.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_single_display_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp - src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp @@ -182,7 +154,6 @@ set(cockatrice_SOURCES src/interface/widgets/deck_editor/deck_list_style_proxy.cpp src/interface/widgets/deck_editor/deck_state_manager.cpp src/interface/widgets/deck_editor/printing_disabled_info_widget.cpp - src/interface/widgets/general/background_sources.cpp src/interface/widgets/general/display/background_plate_widget.cpp src/interface/widgets/general/display/banner_widget.cpp src/interface/widgets/general/display/dynamic_font_size_label.cpp @@ -196,8 +167,6 @@ set(cockatrice_SOURCES src/interface/widgets/general/display/charts/bars/bar_chart_background_widget.cpp src/interface/widgets/general/display/charts/bars/segmented_bar_widget.cpp src/interface/widgets/general/display/charts/pies/color_pie.cpp - src/interface/widgets/general/home_styled_button.cpp - src/interface/widgets/general/home_widget.cpp src/interface/widgets/general/layout_containers/flow_widget.cpp src/interface/widgets/general/layout_containers/overlap_control_widget.cpp src/interface/widgets/general/layout_containers/overlap_widget.cpp @@ -234,99 +203,23 @@ set(cockatrice_SOURCES src/interface/widgets/utility/sequence_edit.cpp src/interface/widgets/utility/visibility_change_listener.cpp src/interface/widgets/utility/visibility_change_listener.h - src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp - src/interface/widgets/visual_database_display/visual_database_display_widget.cpp - src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp - src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp - src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp - src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp - src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp - src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp - src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp - src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp - src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp - src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp - src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp - src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp src/interface/window_main.cpp src/main.cpp src/interface/widgets/tabs/abstract_tab_deck_editor.cpp - src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp - src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp - src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h - src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp - src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp - src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp - src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp - src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp - src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp - src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp - src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp - src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp - src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp - src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp - src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp - src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp - src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp - src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp - src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp - src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp - src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp - src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp - src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp - src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp - src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp - src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp - src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp - src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp - src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp src/interface/widgets/tabs/tab.cpp src/interface/widgets/tabs/tab_account.cpp src/interface/widgets/tabs/tab_admin.cpp src/interface/widgets/tabs/tab_deck_editor.cpp src/interface/widgets/tabs/tab_deck_storage.cpp src/interface/widgets/tabs/tab_game.cpp - src/interface/widgets/tabs/tab_home.cpp src/interface/widgets/tabs/tab_logs.cpp src/interface/widgets/tabs/tab_message.cpp src/interface/widgets/tabs/tab_replays.cpp src/interface/widgets/tabs/tab_room.cpp src/interface/widgets/tabs/tab_server.cpp src/interface/widgets/tabs/tab_supervisor.cpp - src/interface/widgets/tabs/tab_visual_database_display.cpp - src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp - src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp - src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp src/interface/key_signals.cpp src/interface/logger.cpp - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp - src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h ) add_subdirectory(sounds) diff --git a/cockatrice/src/filters/deck_filter_string.cpp b/cockatrice/src/filters/deck_filter_string.cpp deleted file mode 100644 index 6b671831d..000000000 --- a/cockatrice/src/filters/deck_filter_string.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "deck_filter_string.h" - -#include -#include -#include -#include - -static peg::parser search(R"( -Start <- QueryPartList -~ws <- [ ]+ -QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws* - -ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart -SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart - -QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / FormatQuery / CommentQuery / GenericQuery - -NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart - -DeckContentQuery <- CardSearch NumericExpression? -CardSearch <- '[[' CardFilterString ']]' -CardFilterString <- (!']]'.)* - -DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String -FileNameQuery <- [Ff] ([Nn] / 'ile' ([Nn] 'ame')?) [:] String -PathQuery <- [Pp] 'ath'? [:] String -FormatQuery <- [Ff] 'ormat'? [:] String -CommentQuery <- [Cc] ('omment' 's'?)? [:] String - -GenericQuery <- String - -NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["]. -NonSingleQuoteUnlessEscaped <- "\\\'". / ![']. -UnescapedStringListPart <- !['":<>()=! ]. -SingleApostropheString <- (UnescapedStringListPart+ ws*)* ['] (UnescapedStringListPart+ ws*)* - -String <- SingleApostropheString / UnescapedStringListPart+ / ["] ["] / ['] ['] - -NumericExpression <- NumericOperator ws? NumericValue -NumericOperator <- [=:] / <[> -NumericValue <- [0-9]+ -)"); - -static std::once_flag init; - -static void setupParserRules() -{ - // plumbing - auto passthru = [](const peg::SemanticValues &sv) -> DeckFilter { - return !sv.empty() ? std::any_cast(sv[0]) : nullptr; - }; - - search["Start"] = passthru; - search["QueryPartList"] = [](const peg::SemanticValues &sv) -> DeckFilter { - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) { - auto matchesFilter = [&deck, &info](const std::any &query) { - return std::any_cast(query)(deck, info); - }; - return std::all_of(sv.begin(), sv.end(), matchesFilter); - }; - }; - search["ComplexQueryPart"] = [](const peg::SemanticValues &sv) -> DeckFilter { - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) { - auto matchesFilter = [&deck, &info](const std::any &query) { - return std::any_cast(query)(deck, info); - }; - return std::any_of(sv.begin(), sv.end(), matchesFilter); - }; - }; - search["SomewhatComplexQueryPart"] = passthru; - search["QueryPart"] = passthru; - search["NotQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - const auto dependent = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) -> bool { - return !dependent(deck, info); - }; - }; - - search["String"] = [](const peg::SemanticValues &sv) -> QString { - if (sv.choice() == 0) { - return QString::fromStdString(std::string(sv.sv())); - } - - return QString::fromStdString(std::string(sv.token(0))); - }; - - search["NumericExpression"] = [](const peg::SemanticValues &sv) -> NumberMatcher { - const auto arg = std::any_cast(sv[1]); - const auto op = std::any_cast(sv[0]); - - if (op == ">") - return [=](const int s) { return s > arg; }; - if (op == ">=") - return [=](const int s) { return s >= arg; }; - if (op == "<") - return [=](const int s) { return s < arg; }; - if (op == "<=") - return [=](const int s) { return s <= arg; }; - if (op == "=") - return [=](const int s) { return s == arg; }; - if (op == ":") - return [=](const int s) { return s == arg; }; - if (op == "!=") - return [=](const int s) { return s != arg; }; - return [](int) { return false; }; - }; - - search["NumericValue"] = [](const peg::SemanticValues &sv) -> int { - return QString::fromStdString(std::string(sv.sv())).toInt(); - }; - - search["NumericOperator"] = [](const peg::SemanticValues &sv) -> QString { - return QString::fromStdString(std::string(sv.sv())); - }; - - // actual functionality - search["DeckContentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto cardFilter = FilterString(std::any_cast(sv[0])); - auto numberMatcher = sv.size() > 1 ? std::any_cast(sv[1]) : [](int count) { return count > 0; }; - - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool { - int count = 0; - auto cardNodes = deck->deckLoader->getDeck().deckList.getCardNodes(); - for (auto node : cardNodes) { - auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName()); - if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) { - count += node->getNumber(); - } - } - return numberMatcher(count); - }; - }; - - search["CardSearch"] = [](const peg::SemanticValues &sv) -> QString { return std::any_cast(sv[0]); }; - - search["CardFilterString"] = [](const peg::SemanticValues &sv) -> QString { - return QString::fromStdString(std::string(sv.sv())); - }; - - search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto name = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { - return deck->deckLoader->getDeck().deckList.getName().contains(name, Qt::CaseInsensitive); - }; - }; - - search["FileNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto name = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { - auto filename = QFileInfo(deck->filePath).fileName(); - return filename.contains(name, Qt::CaseInsensitive); - }; - }; - - search["PathQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto name = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *, const ExtraDeckSearchInfo &info) { - return info.relativeFilePath.contains(name, Qt::CaseInsensitive); - }; - }; - - search["FormatQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto format = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { - auto gameFormat = deck->deckLoader->getDeck().deckList.getGameFormat(); - return QString::compare(format, gameFormat, Qt::CaseInsensitive) == 0; - }; - }; - - search["CommentQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto value = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { - auto comments = deck->deckLoader->getDeck().deckList.getComments(); - return comments.contains(value, Qt::CaseInsensitive); - }; - }; - - search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter { - auto name = std::any_cast(sv[0]); - return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) { - return deck->getDisplayName().contains(name, Qt::CaseInsensitive); - }; - }; -} - -DeckFilterString::DeckFilterString() -{ - filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; }; - _error = "Not initialized"; -} - -DeckFilterString::DeckFilterString(const QString &expr) -{ - QByteArray ba = expr.simplified().toUtf8(); - - std::call_once(init, setupParserRules); - - _error = QString(); - - if (ba.isEmpty()) { - filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return true; }; - return; - } - - search.set_logger([&](size_t /*ln*/, size_t col, const std::string &msg) { - _error = QString("Error at position %1: %2").arg(col).arg(QString::fromStdString(msg)); - }); - - if (!search.parse(ba.data(), filter)) { - qCInfo(DeckFilterStringLog).nospace() << "DeckFilterString error for " << expr << "; " << qPrintable(_error); - filter = [](const DeckPreviewWidget *, const ExtraDeckSearchInfo &) { return false; }; - } -} \ No newline at end of file diff --git a/cockatrice/src/filters/deck_filter_string.h b/cockatrice/src/filters/deck_filter_string.h deleted file mode 100644 index 1b43d770d..000000000 --- a/cockatrice/src/filters/deck_filter_string.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file deck_filter_string.h - * @ingroup DeckStorageWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_FILTER_STRING_H -#define DECK_FILTER_STRING_H - -#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h" - -#include -#include -#include - -inline Q_LOGGING_CATEGORY(DeckFilterStringLog, "deck_filter_string"); - -/** - * Extra info relevant to filtering that isn't present in the DeckPreviewWidget - */ -struct ExtraDeckSearchInfo -{ - /** - * The relative filepath starting from the deck folder - */ - QString relativeFilePath; -}; - -typedef std::function DeckFilter; - -class DeckFilterString -{ -public: - DeckFilterString(); - explicit DeckFilterString(const QString &expr); - bool check(const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &info) const - { - return filter(deck, info); - } - - [[nodiscard]] bool valid() const - { - return _error.isEmpty(); - } - - QString error() - { - return _error; - } - -private: - QString _error; - DeckFilter filter; -}; -#endif // DECK_FILTER_STRING_H diff --git a/cockatrice/src/game/deckview/deck_view_container.cpp b/cockatrice/src/game/deckview/deck_view_container.cpp index 44b2be6d1..774e92aae 100644 --- a/cockatrice/src/game/deckview/deck_view_container.cpp +++ b/cockatrice/src/game/deckview/deck_view_container.cpp @@ -46,7 +46,7 @@ void ToggleButton::setState(bool _state) } DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent) - : QWidget(nullptr), visualDeckStorageWidget(nullptr), parentGame(parent), playerId(_playerId) + : QWidget(nullptr), parentGame(parent), playerId(_playerId) { loadLocalButton = new QPushButton; loadRemoteButton = new QPushButton; @@ -101,23 +101,6 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent) switchToDeckSelectView(); } -/** - * Creates the VDS widget and inserts it into the layout. No-ops if the widget already exists - */ -void DeckViewContainer::tryCreateVisualDeckStorageWidget() -{ - if (visualDeckStorageWidget) { - return; - } - - visualDeckStorageWidget = new VisualDeckStorageWidget(this); - connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this, - &DeckViewContainer::loadDeckFromFile); - connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, parentGame, &TabGame::openDeckEditor); - - deckViewLayout->addWidget(visualDeckStorageWidget); -} - void DeckViewContainer::retranslateUi() { loadLocalButton->setText(tr("Load deck...")); @@ -138,17 +121,7 @@ static void setVisibility(QPushButton *button, bool visible) void DeckViewContainer::switchToDeckSelectView() { - if (SettingsCache::instance().getVisualDeckStorageInGame()) { - deckView->setHidden(true); - - tryCreateVisualDeckStorageWidget(); - visualDeckStorageWidget->setHidden(false); - } else { - deckView->setHidden(false); - if (visualDeckStorageWidget) { - visualDeckStorageWidget->setHidden(true); - } - } + deckView->setHidden(false); deckViewLayout->update(); @@ -172,9 +145,6 @@ void DeckViewContainer::switchToDeckSelectView() void DeckViewContainer::switchToDeckLoadedView() { deckView->setHidden(false); - if (visualDeckStorageWidget) { - visualDeckStorageWidget->setHidden(true); - } deckViewLayout->update(); @@ -227,15 +197,9 @@ void DeckViewContainer::setVisualDeckStorageExists(bool exists) if (loadLocalButton->isEnabled()) { // We only need to handle the setting changing while in deck select state; tryCreate already gets called // when switching from deck loaded to deck select state - tryCreateVisualDeckStorageWidget(); - visualDeckStorageWidget->setHidden(false); deckView->setHidden(true); } } else { - if (visualDeckStorageWidget) { - visualDeckStorageWidget->deleteLater(); - visualDeckStorageWidget = nullptr; - } deckView->setHidden(false); } diff --git a/cockatrice/src/game/deckview/deck_view_container.h b/cockatrice/src/game/deckview/deck_view_container.h index 6d685cd79..5fb124157 100644 --- a/cockatrice/src/game/deckview/deck_view_container.h +++ b/cockatrice/src/game/deckview/deck_view_container.h @@ -54,11 +54,9 @@ private: QPushButton *unloadDeckButton, *forceStartGameButton; ToggleButton *readyStartButton, *sideboardLockButton; DeckView *deckView; - VisualDeckStorageWidget *visualDeckStorageWidget; TabGame *parentGame; int playerId; - void tryCreateVisualDeckStorageWidget(); void sendReadyStartCommand(bool ready); private slots: void switchToDeckSelectView(); diff --git a/cockatrice/src/interface/widgets/cards/card_size_widget.cpp b/cockatrice/src/interface/widgets/cards/card_size_widget.cpp index 14e45743d..8c05e046f 100644 --- a/cockatrice/src/interface/widgets/cards/card_size_widget.cpp +++ b/cockatrice/src/interface/widgets/cards/card_size_widget.cpp @@ -1,7 +1,6 @@ #include "card_size_widget.h" #include "../printing_selector/printing_selector.h" -#include "../visual_deck_storage/visual_deck_storage_widget.h" /** * @class CardSizeWidget diff --git a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp b/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp deleted file mode 100644 index a8a97a4ca..000000000 --- a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include "deck_card_zone_display_widget.h" - -#include "card_group_display_widgets/flat_card_group_display_widget.h" -#include "card_group_display_widgets/overlapped_card_group_display_widget.h" -#include "libcockatrice/card/database/card_database_manager.h" - -#include -#include - -DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent, - DeckListModel *_deckListModel, - QItemSelectionModel *_selectionModel, - QPersistentModelIndex _trackedIndex, - QString _zoneName, - QString _activeGroupCriteria, - QStringList _activeSortCriteria, - DisplayType _displayType, - int bannerOpacity, - int subBannerOpacity, - CardSizeWidget *_cardSizeWidget) - : QWidget(parent), deckListModel(_deckListModel), selectionModel(_selectionModel), trackedIndex(_trackedIndex), - zoneName(_zoneName), activeGroupCriteria(_activeGroupCriteria), activeSortCriteria(_activeSortCriteria), - displayType(_displayType), bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity), - cardSizeWidget(_cardSizeWidget) -{ - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - layout = new QVBoxLayout(this); - setLayout(layout); - - banner = new BannerWidget(this, zoneName, Qt::Orientation::Vertical, bannerOpacity); - layout->addWidget(banner); - - cardGroupContainer = new QWidget(this); - cardGroupLayout = new QVBoxLayout(cardGroupContainer); - cardGroupContainer->setLayout(cardGroupLayout); - layout->addWidget(cardGroupContainer); - - banner->setBuddy(cardGroupContainer); - - displayCards(); - - connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &DeckCardZoneDisplayWidget::onCategoryAddition); - if (selectionModel) { - connect(selectionModel, &QItemSelectionModel::selectionChanged, this, - &DeckCardZoneDisplayWidget::onSelectionChanged); - } - connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &DeckCardZoneDisplayWidget::onCategoryRemoval); -} - -// ===================================================================================================================== -// User Interaction -// ===================================================================================================================== - -void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card) -{ - emit cardClicked(event, card, zoneName); -} - -void DeckCardZoneDisplayWidget::onHover(const ExactCard &card) -{ - emit cardHovered(card); -} - -void DeckCardZoneDisplayWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) -{ - for (auto &range : selected) { - for (int row = range.top(); row <= range.bottom(); ++row) { - QModelIndex idx = range.model()->index(row, 0, range.parent()); - auto it = indexToWidgetMap.find(QPersistentModelIndex(idx)); - if (it != indexToWidgetMap.end()) { - // it.value()->setHighlighted(true); - } - } - } - - for (auto &range : deselected) { - for (int row = range.top(); row <= range.bottom(); ++row) { - QModelIndex idx = range.model()->index(row, 0, range.parent()); - auto it = indexToWidgetMap.find(QPersistentModelIndex(idx)); - if (it != indexToWidgetMap.end()) { - // it.value()->setHighlighted(false); - } - } - } -} - -// ===================================================================================================================== -// Display Widget Management -// ===================================================================================================================== - -void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex index) -{ - if (indexToWidgetMap.contains(index)) { - return; - } - - auto categoryName = index.sibling(index.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString(); - if (displayType == DisplayType::Overlap) { - auto *displayWidget = new OverlappedCardGroupDisplayWidget( - cardGroupContainer, deckListModel, selectionModel, index, zoneName, categoryName, activeGroupCriteria, - activeSortCriteria, subBannerOpacity, cardSizeWidget); - connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardClicked, this, - &DeckCardZoneDisplayWidget::onClick); - connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardHovered, this, - &DeckCardZoneDisplayWidget::onHover); - connect(displayWidget, &CardGroupDisplayWidget::cleanupRequested, this, - &DeckCardZoneDisplayWidget::cleanupInvalidCardGroup); - connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, displayWidget, - &CardGroupDisplayWidget::onActiveSortCriteriaChanged); - cardGroupLayout->addWidget(displayWidget); - indexToWidgetMap.insert(index, displayWidget); - } else if (displayType == DisplayType::Flat) { - auto *displayWidget = new FlatCardGroupDisplayWidget(cardGroupContainer, deckListModel, selectionModel, index, - zoneName, categoryName, activeGroupCriteria, - activeSortCriteria, subBannerOpacity, cardSizeWidget); - connect(displayWidget, &FlatCardGroupDisplayWidget::cardClicked, this, &DeckCardZoneDisplayWidget::onClick); - connect(displayWidget, &FlatCardGroupDisplayWidget::cardHovered, this, &DeckCardZoneDisplayWidget::onHover); - connect(displayWidget, &CardGroupDisplayWidget::cleanupRequested, this, - &DeckCardZoneDisplayWidget::cleanupInvalidCardGroup); - connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, displayWidget, - &CardGroupDisplayWidget::onActiveSortCriteriaChanged); - cardGroupLayout->addWidget(displayWidget); - indexToWidgetMap.insert(index, displayWidget); - } -} - -void DeckCardZoneDisplayWidget::displayCards() -{ - QSortFilterProxyModel proxy; - proxy.setSourceModel(deckListModel); - proxy.setSortRole(Qt::EditRole); - proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder); - - // 1. trackedIndex is a source index → map it to proxy space - QModelIndex proxyParent = proxy.mapFromSource(trackedIndex); - - // 2. iterate children under the proxy parent - for (int i = 0; i < proxy.rowCount(proxyParent); ++i) { - QModelIndex proxyIndex = proxy.index(i, 0, proxyParent); - - // 3. map back to source - QModelIndex sourceIndex = proxy.mapToSource(proxyIndex); - - // 4. persist the source index - QPersistentModelIndex persistent(sourceIndex); - - constructAppropriateWidget(persistent); - } -} - -void DeckCardZoneDisplayWidget::refreshDisplayType(const DisplayType &_displayType) -{ - displayType = _displayType; - QLayoutItem *item; - while ((item = cardGroupLayout->takeAt(0)) != nullptr) { - if (item->widget()) { - item->widget()->deleteLater(); - } else if (item->layout()) { - item->layout()->deleteLater(); - } - delete item; - } - - indexToWidgetMap.clear(); - - // We gotta wait for all the deleteLater's to finish so we fire after the next event cycle - - auto timer = new QTimer(this); - timer->setSingleShot(true); - connect(timer, &QTimer::timeout, this, [this]() { displayCards(); }); - timer->start(); -} - -void DeckCardZoneDisplayWidget::cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget) -{ - cardGroupLayout->removeWidget(displayWidget); - displayWidget->setParent(nullptr); - for (auto idx : indexToWidgetMap.keys()) { - if (!idx.isValid()) { - indexToWidgetMap.remove(idx); - } - } - delete displayWidget; -} - -// ===================================================================================================================== -// DeckListModel Signal Responses -// ===================================================================================================================== - -void DeckCardZoneDisplayWidget::onCategoryAddition(const QModelIndex &parent, int first, int last) -{ - if (!trackedIndex.isValid()) { - emit requestCleanup(this); - return; - } - if (parent == trackedIndex) { - for (int i = first; i <= last; i++) { - QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(i, 0, trackedIndex)); - - constructAppropriateWidget(index); - } - } -} - -void DeckCardZoneDisplayWidget::onCategoryRemoval(const QModelIndex &parent, int first, int last) -{ - Q_UNUSED(parent); - Q_UNUSED(first); - Q_UNUSED(last); - for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) { - if (!idx.isValid()) { - cardGroupLayout->removeWidget(indexToWidgetMap.value(idx)); - indexToWidgetMap.value(idx)->deleteLater(); - indexToWidgetMap.remove(idx); - } - } - if (!trackedIndex.isValid()) { - emit requestCleanup(this); - } -} - -void DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged(QString _activeGroupCriteria) -{ - activeGroupCriteria = _activeGroupCriteria; - displayCards(); -} - -void DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSortCriteria) -{ - activeSortCriteria = _activeSortCriteria; - emit activeSortCriteriaChanged(activeSortCriteria); -} - -QList DeckCardZoneDisplayWidget::getGroupCriteriaValueList() -{ - QList groupCriteriaValues; - - QList nodes = deckListModel->getCardNodesForZone(zoneName); - - for (auto node : nodes) { - CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(node->getName()); - if (info) { - groupCriteriaValues.append(info->getProperty(activeGroupCriteria)); - } - } - - groupCriteriaValues.removeDuplicates(); - groupCriteriaValues.sort(); - - return groupCriteriaValues; -} diff --git a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h b/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h deleted file mode 100644 index dc0f3d734..000000000 --- a/cockatrice/src/interface/widgets/cards/deck_card_zone_display_widget.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file deck_card_zone_display_widget.h - * @ingroup DeckEditorWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_CARD_ZONE_DISPLAY_WIDGET_H -#define DECK_CARD_ZONE_DISPLAY_WIDGET_H - -#include "../general/display/banner_widget.h" -#include "../general/layout_containers/overlap_widget.h" -#include "../visual_deck_editor/visual_deck_editor_widget.h" -#include "card_group_display_widgets/card_group_display_widget.h" -#include "card_info_picture_with_text_overlay_widget.h" -#include "card_size_widget.h" - -#include -#include -#include - -class DeckCardZoneDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - DeckCardZoneDisplayWidget(QWidget *parent, - DeckListModel *deckListModel, - QItemSelectionModel *selectionModel, - QPersistentModelIndex trackedIndex, - QString zoneName, - QString activeGroupCriteria, - QStringList activeSortCriteria, - DisplayType displayType, - int bannerOpacity, - int subBannerOpacity, - CardSizeWidget *_cardSizeWidget); - void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); - DeckListModel *deckListModel; - QItemSelectionModel *selectionModel; - QPersistentModelIndex trackedIndex; - QString zoneName; - void addCardsToOverlapWidget(); - -public slots: - void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card); - void onHover(const ExactCard &card); - void cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget); - void constructAppropriateWidget(QPersistentModelIndex index); - void displayCards(); - void refreshDisplayType(const DisplayType &displayType); - void onActiveGroupCriteriaChanged(QString activeGroupCriteria); - void onActiveSortCriteriaChanged(QStringList activeSortCriteria); - QList getGroupCriteriaValueList(); - void onCategoryAddition(const QModelIndex &parent, int first, int last); - void onCategoryRemoval(const QModelIndex &parent, int first, int last); - -signals: - void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card, QString zoneName); - void cardHovered(const ExactCard &card); - void activeSortCriteriaChanged(QStringList activeSortCriteria); - void requestCleanup(DeckCardZoneDisplayWidget *displayWidget); - -private: - QString activeGroupCriteria; - QStringList activeSortCriteria; - DisplayType displayType = DisplayType::Overlap; - int bannerOpacity = 20; - int subBannerOpacity = 10; - CardSizeWidget *cardSizeWidget; - QVBoxLayout *layout; - BannerWidget *banner; - QWidget *cardGroupContainer; - QVBoxLayout *cardGroupLayout; - OverlapWidget *overlapWidget; - QHash indexToWidgetMap; -}; - -#endif // DECK_CARD_ZONE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.cpp b/cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.cpp deleted file mode 100644 index b27fe274f..000000000 --- a/cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "deck_preview_card_picture_widget.h" - -#include "../../../client/settings/cache_settings.h" - -#include -#include -#include -#include -#include -#include - -/** - * @brief Constructs a CardPictureWithTextOverlay widget. - * @param parent The parent widget. - * @param hoverToZoomEnabled If this widget will spawn a larger widget when hovered over. - * @param textColor The color of the overlay text. - * @param outlineColor The color of the outline around the text. - * @param fontSize The font size of the overlay text. - * @param alignment The alignment of the text within the overlay. - * - * Sets the widget's size policy and default border style. - */ -DeckPreviewCardPictureWidget::DeckPreviewCardPictureWidget(QWidget *parent, - const bool hoverToZoomEnabled, - const bool raiseOnEnter, - const QColor &textColor, - const QColor &outlineColor, - const int fontSize, - const Qt::Alignment alignment) - : CardInfoPictureWithTextOverlayWidget(parent, - hoverToZoomEnabled, - raiseOnEnter, - textColor, - outlineColor, - fontSize, - alignment) -{ - singleClickTimer = new QTimer(this); - singleClickTimer->setSingleShot(true); - connect(singleClickTimer, &QTimer::timeout, this, [this]() { emit imageClicked(lastMouseEvent, this); }); - connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageSelectionAnimationChanged, this, - &CardInfoPictureWidget::setRaiseOnEnterEnabled); -} - -void DeckPreviewCardPictureWidget::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - lastMouseEvent = event; - singleClickTimer->start(QApplication::doubleClickInterval()); - } else { - emit imageClicked(event, this); - event->accept(); - } -} - -void DeckPreviewCardPictureWidget::mouseDoubleClickEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - singleClickTimer->stop(); // Prevent single-click logic - emit imageDoubleClicked(lastMouseEvent, this); - } -} diff --git a/cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.h b/cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.h deleted file mode 100644 index acb67a49a..000000000 --- a/cockatrice/src/interface/widgets/cards/deck_preview_card_picture_widget.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file deck_preview_card_picture_widget.h - * @ingroup CardWidgets - * @ingroup Lobby - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_CARD_PICTURE_WIDGET_H -#define DECK_PREVIEW_CARD_PICTURE_WIDGET_H - -#include "card_info_picture_with_text_overlay_widget.h" - -#include -#include -#include -#include - -class DeckPreviewCardPictureWidget final : public CardInfoPictureWithTextOverlayWidget -{ - Q_OBJECT - -public: - explicit DeckPreviewCardPictureWidget(QWidget *parent, - bool hoverToZoomEnabled = false, - bool raiseOnEnter = false, - const QColor &textColor = Qt::white, - const QColor &outlineColor = Qt::black, - int fontSize = 12, - Qt::Alignment alignment = Qt::AlignCenter); - -signals: - void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance); - void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance); - -private: - QTimer *singleClickTimer; - QMouseEvent *lastMouseEvent = nullptr; // Store the last mouse event - -protected: - void mousePressEvent(QMouseEvent *event) override; - void mouseDoubleClickEvent(QMouseEvent *event) override; -}; - -#endif // DECK_PREVIEW_CARD_PICTURE_WIDGET_H diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp index 20eef180a..d20aac86a 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp @@ -14,13 +14,6 @@ #include #include -static bool canBeCommander(const CardInfo &cardInfo) -{ - return (cardInfo.getCardType().contains("Legendary", Qt::CaseInsensitive) && - cardInfo.getCardType().contains("Creature", Qt::CaseInsensitive)) || - cardInfo.getText().contains("can be your commander", Qt::CaseInsensitive); -} - DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent, AbstractTabDeckEditor *deckEditor) : QWidget(parent), deckEditor(deckEditor) { @@ -186,22 +179,14 @@ void DeckEditorDatabaseDisplayWidget::databaseCustomMenu(QPoint point) if (card) { // add to deck and sideboard options - QAction *addToDeck, *addToSideboard, *selectPrinting, *edhRecCommander, *edhRecCard; + QAction *addToDeck, *addToSideboard, *selectPrinting; addToDeck = menu.addAction(tr("Add to Deck")); addToSideboard = menu.addAction(tr("Add to Sideboard")); selectPrinting = menu.addAction(tr("Select Printing")); connect(selectPrinting, &QAction::triggered, this, [this, card] { deckEditor->showPrintingSelector(); }); - if (canBeCommander(card.getInfo())) { - edhRecCommander = menu.addAction(tr("Show on EDHRec (Commander)")); - connect(edhRecCommander, &QAction::triggered, this, - [this, card] { deckEditor->getTabSupervisor()->addEdhrecTab(card.getCardPtr(), true); }); - } - edhRecCard = menu.addAction(tr("Show on EDHRec (Card)")); connect(addToDeck, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck); connect(addToSideboard, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard); - connect(edhRecCard, &QAction::triggered, this, - [this, card] { deckEditor->getTabSupervisor()->addEdhrecTab(card.getCardPtr()); }); // filling out the related cards submenu auto *relatedMenu = new QMenu(tr("Show Related cards")); diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp index f939ae99d..4dc4890c5 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp @@ -119,8 +119,6 @@ void DeckEditorDeckDockWidget::createDeckDock() showTagsWidgetCheckBox->setChecked(SettingsCache::instance().getDeckEditorTagsWidgetVisible()); connect(showTagsWidgetCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), &SettingsCache::setDeckEditorTagsWidgetVisible); - connect(&SettingsCache::instance(), &SettingsCache::deckEditorTagsWidgetVisibleChanged, this, - &DeckEditorDeckDockWidget::updateShowTagsWidget); quickSettingsWidget->addSettingsWidget(showBannerCardCheckBox); quickSettingsWidget->addSettingsWidget(showTagsWidgetCheckBox); @@ -164,11 +162,6 @@ void DeckEditorDeckDockWidget::createDeckDock() &DeckEditorDeckDockWidget::writeBannerCard); bannerCardComboBox->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible()); - deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, {}); - deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible()); - connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, deckStateManager, - &DeckStateManager::setTags); - activeGroupCriteriaLabel = new QLabel(this); activeGroupCriteriaComboBox = new QComboBox(this); @@ -219,8 +212,6 @@ void DeckEditorDeckDockWidget::createDeckDock() upperLayout->addWidget(bannerCardLabel, 3, 0); upperLayout->addWidget(bannerCardComboBox, 3, 1); - upperLayout->addWidget(deckTagsDisplayWidget, 4, 1); - upperLayout->addWidget(activeGroupCriteriaLabel, 5, 0); upperLayout->addWidget(activeGroupCriteriaComboBox, 5, 1); @@ -439,11 +430,6 @@ void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible) bannerCardComboBox->setHidden(!visible); } -void DeckEditorDeckDockWidget::updateShowTagsWidget(const bool visible) -{ - deckTagsDisplayWidget->setHidden(!visible); -} - void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck() { if (deckStateManager->getMetadata().bannerCard.name == "") { @@ -488,10 +474,6 @@ void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel() formatComboBox->blockSignals(true); formatComboBox->setCurrentIndex(formatComboBox->findData(deckStateManager->getMetadata().gameFormat)); formatComboBox->blockSignals(false); - - deckTagsDisplayWidget->blockSignals(true); - deckTagsDisplayWidget->setTags(deckStateManager->getMetadata().tags); - deckTagsDisplayWidget->blockSignals(false); } /** diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h index 8dddf5882..1a3ccb41a 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h +++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h @@ -11,10 +11,11 @@ #include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h" #include "../../key_signals.h" #include "../utility/custom_line_edit.h" -#include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "deck_list_history_manager_widget.h" #include "deck_list_style_proxy.h" +#include +#include #include #include #include @@ -79,7 +80,6 @@ private: QTextEdit *commentsEdit; QTimer *commentsDebounceTimer; QLabel *bannerCardLabel; - DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget; QLabel *hashLabel1; LineEditUnfocusable *hashLabel; QLabel *activeGroupCriteriaLabel; @@ -104,7 +104,6 @@ private slots: void updateHash(); void refreshShortcuts(); void updateShowBannerCardComboBox(bool visible); - void updateShowTagsWidget(bool visible); void syncBannerCardComboBoxSelectionWithDeck(); void changeSelectedCard(int changeBy); void recursiveExpand(const QModelIndex &parent); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index 6238bc80b..8f458cd06 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -7,7 +7,6 @@ #include "../client/sound_engine.h" #include "../interface/card_picture_loader/card_picture_loader.h" #include "../interface/theme_manager.h" -#include "../interface/widgets/general/background_sources.h" #include "../interface/widgets/tabs/tab_supervisor.h" #include "../interface/widgets/utility/custom_line_edit.h" #include "../interface/widgets/utility/get_text_with_max.h" @@ -425,45 +424,10 @@ AppearanceSettingsPage::AppearanceSettingsPage() connect(&themeBox, qOverload(&QComboBox::currentIndexChanged), this, &AppearanceSettingsPage::themeBoxChanged); connect(&openThemeButton, &QPushButton::clicked, this, &AppearanceSettingsPage::openThemeLocation); - for (const auto &entry : BackgroundSources::all()) { - homeTabBackgroundSourceBox.addItem(QObject::tr(entry.trKey), QVariant::fromValue(entry.type)); - } - - QString homeTabBackgroundSource = SettingsCache::instance().getHomeTabBackgroundSource(); - int homeTabBackgroundSourceId = - homeTabBackgroundSourceBox.findData(BackgroundSources::fromId(homeTabBackgroundSource)); - if (homeTabBackgroundSourceId != -1) { - homeTabBackgroundSourceBox.setCurrentIndex(homeTabBackgroundSourceId); - } - - connect(&homeTabBackgroundSourceBox, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { - auto type = homeTabBackgroundSourceBox.currentData().value(); - SettingsCache::instance().setHomeTabBackgroundSource(BackgroundSources::toId(type)); - updateHomeTabSettingsVisibility(); - }); - - homeTabBackgroundShuffleFrequencySpinBox.setRange(0, 3600); - homeTabBackgroundShuffleFrequencySpinBox.setSuffix(tr(" seconds")); - homeTabBackgroundShuffleFrequencySpinBox.setValue(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency()); - connect(&homeTabBackgroundShuffleFrequencySpinBox, qOverload(&QSpinBox::valueChanged), - &SettingsCache::instance(), &SettingsCache::setHomeTabBackgroundShuffleFrequency); - - homeTabDisplayCardNameCheckBox.setChecked(settings.getHomeTabDisplayCardName()); - connect(&homeTabDisplayCardNameCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, - &SettingsCache::setHomeTabDisplayCardName); - - updateHomeTabSettingsVisibility(); - auto *themeGrid = new QGridLayout; themeGrid->addWidget(&themeLabel, 0, 0); themeGrid->addWidget(&themeBox, 0, 1); themeGrid->addWidget(&openThemeButton, 1, 1); - themeGrid->addWidget(&homeTabBackgroundSourceLabel, 2, 0); - themeGrid->addWidget(&homeTabBackgroundSourceBox, 2, 1); - themeGrid->addWidget(&homeTabBackgroundShuffleFrequencyLabel, 3, 0); - themeGrid->addWidget(&homeTabBackgroundShuffleFrequencySpinBox, 3, 1); - themeGrid->addWidget(&homeTabDisplayCardNameLabel, 4, 0); - themeGrid->addWidget(&homeTabDisplayCardNameCheckBox, 4, 1); themeGroupBox = new QGroupBox; themeGroupBox->setLayout(themeGrid); @@ -660,17 +624,6 @@ void AppearanceSettingsPage::openThemeLocation() } } -void AppearanceSettingsPage::updateHomeTabSettingsVisibility() -{ - bool visible = - SettingsCache::instance().getHomeTabBackgroundSource() != BackgroundSources::toId(BackgroundSources::Theme); - - homeTabBackgroundShuffleFrequencyLabel.setVisible(visible); - homeTabBackgroundShuffleFrequencySpinBox.setVisible(visible); - homeTabDisplayCardNameLabel.setVisible(visible); - homeTabDisplayCardNameCheckBox.setVisible(visible); -} - void AppearanceSettingsPage::showShortcutsChanged(QT_STATE_CHANGED_T value) { SettingsCache::instance().setShowShortcuts(value); @@ -724,10 +677,6 @@ void AppearanceSettingsPage::retranslateUi() themeGroupBox->setTitle(tr("Theme settings")); themeLabel.setText(tr("Current theme:")); openThemeButton.setText(tr("Open themes folder")); - homeTabBackgroundSourceLabel.setText(tr("Home tab background source:")); - homeTabBackgroundShuffleFrequencyLabel.setText(tr("Home tab background shuffle frequency:")); - homeTabBackgroundShuffleFrequencySpinBox.setSpecialValueText(tr("Disabled")); - homeTabDisplayCardNameLabel.setText(tr("Display card name of background in bottom right:")); menuGroupBox->setTitle(tr("Menu settings")); showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus")); @@ -872,47 +821,8 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() connect(&openDeckInNewTabCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), &SettingsCache::setOpenDeckInNewTab); - visualDeckStorageInGameCheckBox.setChecked(SettingsCache::instance().getVisualDeckStorageInGame()); - connect(&visualDeckStorageInGameCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageInGame); - - visualDeckStorageSelectionAnimationCheckBox.setChecked( - SettingsCache::instance().getVisualDeckStorageSelectionAnimation()); - connect(&visualDeckStorageSelectionAnimationCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageSelectionAnimation); - - visualDeckStoragePromptForConversionSelector.addItem(""); // these will be set in retranslateUI - visualDeckStoragePromptForConversionSelector.addItem(""); - visualDeckStoragePromptForConversionSelector.addItem(""); - if (SettingsCache::instance().getVisualDeckStoragePromptForConversion()) { - visualDeckStoragePromptForConversionSelector.setCurrentIndex(visualDeckStoragePromptForConversionIndexPrompt); - } else if (SettingsCache::instance().getVisualDeckStorageAlwaysConvert()) { - visualDeckStoragePromptForConversionSelector.setCurrentIndex(visualDeckStoragePromptForConversionIndexAlways); - } else { - visualDeckStoragePromptForConversionSelector.setCurrentIndex(visualDeckStoragePromptForConversionIndexNone); - } - connect(&visualDeckStoragePromptForConversionSelector, QOverload::of(&QComboBox::currentIndexChanged), this, - [](int index) { - SettingsCache::instance().setVisualDeckStoragePromptForConversion( - index == visualDeckStoragePromptForConversionIndexPrompt); - SettingsCache::instance().setVisualDeckStorageAlwaysConvert( - index == visualDeckStoragePromptForConversionIndexAlways); - }); - - defaultDeckEditorTypeSelector.addItem(""); // these will be set in retranslateUI - defaultDeckEditorTypeSelector.addItem(""); - defaultDeckEditorTypeSelector.setCurrentIndex(SettingsCache::instance().getDefaultDeckEditorType()); - connect(&defaultDeckEditorTypeSelector, QOverload::of(&QComboBox::currentIndexChanged), - &SettingsCache::instance(), &SettingsCache::setDefaultDeckEditorType); - auto *deckEditorGrid = new QGridLayout; deckEditorGrid->addWidget(&openDeckInNewTabCheckBox, 0, 0); - deckEditorGrid->addWidget(&visualDeckStorageInGameCheckBox, 1, 0); - deckEditorGrid->addWidget(&visualDeckStorageSelectionAnimationCheckBox, 2, 0); - deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionLabel, 3, 0); - deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionSelector, 3, 1); - deckEditorGrid->addWidget(&defaultDeckEditorTypeLabel, 4, 0); - deckEditorGrid->addWidget(&defaultDeckEditorTypeSelector, 4, 1); deckEditorGroupBox = new QGroupBox; deckEditorGroupBox->setLayout(deckEditorGrid); @@ -976,19 +886,6 @@ void UserInterfaceSettingsPage::retranslateUi() tapAnimationCheckBox.setText(tr("&Tap/untap animation")); deckEditorGroupBox->setTitle(tr("Deck editor/storage settings")); openDeckInNewTabCheckBox.setText(tr("Open deck in new tab by default")); - visualDeckStorageInGameCheckBox.setText(tr("Use visual deck storage in game lobby")); - visualDeckStorageSelectionAnimationCheckBox.setText(tr("Use selection animation for Visual Deck Storage")); - visualDeckStoragePromptForConversionLabel.setText( - tr("When adding a tag in the visual deck storage to a .txt deck:")); - visualDeckStoragePromptForConversionSelector.setItemText(visualDeckStoragePromptForConversionIndexNone, - tr("do nothing")); - visualDeckStoragePromptForConversionSelector.setItemText(visualDeckStoragePromptForConversionIndexPrompt, - tr("ask to convert to .cod")); - visualDeckStoragePromptForConversionSelector.setItemText(visualDeckStoragePromptForConversionIndexAlways, - tr("always convert to .cod")); - defaultDeckEditorTypeLabel.setText(tr("Default deck editor type")); - defaultDeckEditorTypeSelector.setItemText(TabSupervisor::ClassicDeckEditor, tr("Classic Deck Editor")); - defaultDeckEditorTypeSelector.setItemText(TabSupervisor::VisualDeckEditor, tr("Visual Deck Editor")); replayGroupBox->setTitle(tr("Replay settings")); rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:")); rewindBufferingMsBox.setSuffix(" ms"); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h index b655a30bc..e2f0dd44e 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h @@ -103,7 +103,6 @@ class AppearanceSettingsPage : public AbstractSettingsPage private slots: void themeBoxChanged(int index); void openThemeLocation(); - void updateHomeTabSettingsVisibility(); void showShortcutsChanged(QT_STATE_CHANGED_T enabled); void overrideAllCardArtWithPersonalPreferenceToggled(QT_STATE_CHANGED_T enabled); @@ -114,12 +113,6 @@ private: QLabel themeLabel; QComboBox themeBox; QPushButton openThemeButton; - QLabel homeTabBackgroundSourceLabel; - QComboBox homeTabBackgroundSourceBox; - QLabel homeTabBackgroundShuffleFrequencyLabel; - QSpinBox homeTabBackgroundShuffleFrequencySpinBox; - QLabel homeTabDisplayCardNameLabel; - QCheckBox homeTabDisplayCardNameCheckBox; QLabel minPlayersForMultiColumnLayoutLabel; QLabel maxFontSizeForCardsLabel; QCheckBox showShortcutsCheckBox; @@ -176,12 +169,6 @@ private: QCheckBox useTearOffMenusCheckBox; QCheckBox tapAnimationCheckBox; QCheckBox openDeckInNewTabCheckBox; - QLabel visualDeckStoragePromptForConversionLabel; - QComboBox visualDeckStoragePromptForConversionSelector; - QCheckBox visualDeckStorageInGameCheckBox; - QCheckBox visualDeckStorageSelectionAnimationCheckBox; - QLabel defaultDeckEditorTypeLabel; - QComboBox defaultDeckEditorTypeSelector; QLabel rewindBufferingMsLabel; QSpinBox rewindBufferingMsBox; QGroupBox *generalGroupBox; diff --git a/cockatrice/src/interface/widgets/general/background_sources.cpp b/cockatrice/src/interface/widgets/general/background_sources.cpp deleted file mode 100644 index 0d3efa330..000000000 --- a/cockatrice/src/interface/widgets/general/background_sources.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "background_sources.h" - -// Required so moc generates Q_OBJECT macros \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/general/background_sources.h b/cockatrice/src/interface/widgets/general/background_sources.h deleted file mode 100644 index 15bf1d377..000000000 --- a/cockatrice/src/interface/widgets/general/background_sources.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file background_sources.h - * @ingroup UI - * @brief TODO: Document this. - */ - -#ifndef COCKATRICE_BACKGROUND_SOURCES_H -#define COCKATRICE_BACKGROUND_SOURCES_H - -#include -#include -#include - -class BackgroundSources -{ - Q_GADGET -public: - enum Type - { - Theme, - RandomCardArt, - DeckFileArt - }; - Q_ENUM(Type) - - struct Entry - { - Type type; - const char *id; // stable ID for settings - const char *trKey; // key for translation - }; - - static QList all() - { - return {{Theme, "theme", QT_TR_NOOP("Theme")}, - {RandomCardArt, "random_card_art", QT_TR_NOOP("Art crop of random card")}, - {DeckFileArt, "deck_file_art", QT_TR_NOOP("Art crop of background.cod deck file")}}; - } - - static QString toId(Type type) - { - for (const auto &e : all()) { - if (e.type == type) - return e.id; - } - return {}; - } - - static Type fromId(const QString &id) - { - for (const auto &e : all()) { - if (id == e.id) - return e.type; - } - return Theme; // default - } - - static QString toDisplay(Type type) - { - for (const auto &e : all()) { - if (e.type == type) - return QObject::tr(e.trKey); - } - return {}; - } -}; - -#endif // COCKATRICE_BACKGROUND_SOURCES_H diff --git a/cockatrice/src/interface/widgets/general/home_styled_button.cpp b/cockatrice/src/interface/widgets/general/home_styled_button.cpp deleted file mode 100644 index c7bdd1e5e..000000000 --- a/cockatrice/src/interface/widgets/general/home_styled_button.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "home_styled_button.h" - -#include -#include -#include -#include - -HomeStyledButton::HomeStyledButton(const QString &text, QPair _gradientColors, QWidget *parent) - : QPushButton(text, parent), gradientColors(_gradientColors) -{ - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setMinimumHeight(25); - setStyleSheet(generateButtonStylesheet(gradientColors)); -} - -void HomeStyledButton::updateStylesheet(const QPair &colors) -{ - gradientColors = colors; - setStyleSheet(generateButtonStylesheet(gradientColors)); -} - -QString HomeStyledButton::generateButtonStylesheet(const QPair &colors) -{ - QColor baseGradientStart = colors.first; - QColor baseGradientEnd = colors.second; - - QColor hoverGradientStart = baseGradientStart.lighter(120); // 20% lighter - QColor hoverGradientEnd = baseGradientEnd.lighter(120); - - QColor pressedGradientStart = baseGradientStart.darker(130); // 30% darker - QColor pressedGradientEnd = baseGradientEnd.darker(130); - - // Disabled: more gray, less saturated - QColor disabledGradientStart = baseGradientStart.toHsv(); - disabledGradientStart.setHsv(disabledGradientStart.hue(), disabledGradientStart.saturation() * 0.2, - disabledGradientStart.value() * 0.6); - QColor disabledGradientEnd = baseGradientEnd.toHsv(); - disabledGradientEnd.setHsv(disabledGradientEnd.hue(), disabledGradientEnd.saturation() * 0.2, - disabledGradientEnd.value() * 0.6); - - return QString(R"( - QPushButton { - font-size: 34px; - font-weight: bold; - font-family: sans-serif, "Segoe UI", "Helvetica Neue"; - padding: 30px; - color: white; - border: 2px solid %1; - border-radius: 20px; - background: qlineargradient(x1:0, y1:1, x2:0, y2:0, - stop:0 %2, stop:1 %3); - } - QPushButton:hover { - background: qlineargradient(x1:0, y1:1, x2:0, y2:0, - stop:0 %4, stop:1 %5); - } - QPushButton:pressed { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 %6, stop:1 %7); - } - QPushButton:disabled { - color: #aaaaaa; - border: 2px solid #888888; - background: qlineargradient(x1:0, y1:1, x2:0, y2:0, - stop:0 %8, stop:1 %9); - } - )") - .arg(baseGradientStart.name()) - .arg(baseGradientStart.name()) - .arg(baseGradientEnd.name()) - .arg(hoverGradientStart.name()) - .arg(hoverGradientEnd.name()) - .arg(pressedGradientStart.name()) - .arg(pressedGradientEnd.name()) - .arg(disabledGradientStart.name()) - .arg(disabledGradientEnd.name()); -} - -void HomeStyledButton::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); // Event is just used for update clipping, we redraw the whole widget. - QStyleOptionButton opt; - initStyleOption(&opt); - opt.text.clear(); // prevent style from drawing text - - QPainter painter(this); - style()->drawControl(QStyle::CE_PushButton, &opt, &painter, this); - - // Draw white text with a black outline - painter.setRenderHint(QPainter::Antialiasing); - painter.setRenderHint(QPainter::TextAntialiasing); - - QFontMetrics fm(font()); - QSize textSize = fm.size(Qt::TextSingleLine, text()); - QPointF center((width() - textSize.width()) / 2.0, (height() + textSize.height() / 2.0) / 2.0); - - QPainterPath path; - path.addText(center, font(), text()); - - QPen pen(Qt::black, 4.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); - painter.strokePath(path, pen); - painter.fillPath(path, Qt::white); -} diff --git a/cockatrice/src/interface/widgets/general/home_styled_button.h b/cockatrice/src/interface/widgets/general/home_styled_button.h deleted file mode 100644 index a053993da..000000000 --- a/cockatrice/src/interface/widgets/general/home_styled_button.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file home_styled_button.h - * @ingroup Widgets - * @brief TODO: Document this. - */ - -#ifndef HOME_STYLED_BUTTON_H -#define HOME_STYLED_BUTTON_H -#include - -class HomeStyledButton : public QPushButton -{ - Q_OBJECT -public: - HomeStyledButton(const QString &text, QPair gradientColors, QWidget *parent = nullptr); - void updateStylesheet(const QPair &colors); - QString generateButtonStylesheet(const QPair &colors); -public slots: - void paintEvent(QPaintEvent *event) override; - -private: - QPair gradientColors; -}; - -#endif // HOME_STYLED_BUTTON_H diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp deleted file mode 100644 index a87d69119..000000000 --- a/cockatrice/src/interface/widgets/general/home_widget.cpp +++ /dev/null @@ -1,377 +0,0 @@ -#include "home_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../../../interface/widgets/tabs/tab_supervisor.h" -#include "../../theme_manager.h" -#include "../../window_main.h" -#include "background_sources.h" -#include "home_styled_button.h" - -#include -#include -#include -#include -#include -#include -#include - -HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor) - : QWidget(parent), tabSupervisor(_tabSupervisor), background("theme:backgrounds/home"), overlay("theme:cockatrice") -{ - layout = new QGridLayout(this); - - backgroundSourceCard = new CardInfoPictureArtCropWidget(this); - - gradientColors = extractDominantColors(background); - - layout->addWidget(createButtons(), 1, 1, Qt::AlignVCenter | Qt::AlignHCenter); - - layout->setRowStretch(0, 1); - layout->setRowStretch(2, 1); - layout->setColumnStretch(0, 1); - layout->setColumnStretch(2, 1); - - setLayout(layout); - - cardChangeTimer = new QTimer(this); - connect(cardChangeTimer, &QTimer::timeout, this, &HomeWidget::updateRandomCard); - - initializeBackgroundFromSource(); - - updateConnectButton(tabSupervisor->getClient()->getStatus()); - - connect(tabSupervisor->getClient(), &RemoteClient::statusChanged, this, &HomeWidget::updateConnectButton); - connect(&SettingsCache::instance(), &SettingsCache::homeTabBackgroundSourceChanged, this, - &HomeWidget::initializeBackgroundFromSource); - connect(&SettingsCache::instance(), &SettingsCache::homeTabBackgroundShuffleFrequencyChanged, this, - &HomeWidget::onBackgroundShuffleFrequencyChanged); - // Lambda is cleaner to read than overloading this - connect(&SettingsCache::instance(), &SettingsCache::homeTabDisplayCardNameChanged, this, [this] { repaint(); }); - connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, - &HomeWidget::initializeBackgroundFromSource); - connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, - &HomeWidget::updateButtonsToBackgroundColor); -} - -void HomeWidget::initializeBackgroundFromSource() -{ - if (CardDatabaseManager::getInstance()->getLoadStatus() != LoadStatus::Ok) { - connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this, - &HomeWidget::initializeBackgroundFromSource); - return; - } - - auto backgroundSourceType = BackgroundSources::fromId(SettingsCache::instance().getHomeTabBackgroundSource()); - - switch (backgroundSourceType) { - case BackgroundSources::Theme: - cardChangeTimer->stop(); - background = QPixmap("theme:backgrounds/home"); - backgroundSourceDeck = DeckList(); - backgroundSourceCard->setCard(ExactCard()); - updateButtonsToBackgroundColor(); - update(); - break; - case BackgroundSources::RandomCardArt: - backgroundSourceDeck = DeckList(); - updateRandomCard(); - onBackgroundShuffleFrequencyChanged(); - break; - case BackgroundSources::DeckFileArt: - loadBackgroundSourceDeck(); - updateRandomCard(); - onBackgroundShuffleFrequencyChanged(); - break; - } -} - -void HomeWidget::loadBackgroundSourceDeck() -{ - std::optional deckOpt = DeckLoader::loadFromFile( - SettingsCache::instance().getDeckPath() + "background.cod", DeckFileFormat::Cockatrice, false); - backgroundSourceDeck = deckOpt.has_value() ? deckOpt.value().deckList : DeckList(); -} - -void HomeWidget::setRandomCard(ExactCard &newCard) -{ - static constexpr int ATTEMPTS = 10; - for (int i = 0; i < ATTEMPTS; ++i) { - ExactCard tmpCard = CardDatabaseManager::query()->getRandomCard(); - if (tmpCard != backgroundSourceCard->getCard() && tmpCard.getCardPtr()->getProperty("layout") == "normal" && - tmpCard.getPrinting().getSet() != nullptr) { - newCard = tmpCard; - return; - } - } - qWarning() << "failed to set random card image after" << ATTEMPTS << "attempts"; -} - -void HomeWidget::updateRandomCard() -{ - auto backgroundSourceType = BackgroundSources::fromId(SettingsCache::instance().getHomeTabBackgroundSource()); - - ExactCard newCard; - - switch (backgroundSourceType) { - case BackgroundSources::Theme: - break; - case BackgroundSources::RandomCardArt: - setRandomCard(newCard); - break; - case BackgroundSources::DeckFileArt: - QList cardRefs = backgroundSourceDeck.getCardRefList(); - ExactCard oldCard = backgroundSourceCard->getCard(); - - if (!cardRefs.empty()) { - if (cardRefs.size() == 1) { - newCard = CardDatabaseManager::query()->getCard(cardRefs.first()); - } else { - // Keep picking until different - do { - int idx = QRandomGenerator::global()->bounded(cardRefs.size()); - newCard = CardDatabaseManager::query()->getCard(cardRefs.at(idx)); - } while (newCard == oldCard); - } - } else { - do { - newCard = CardDatabaseManager::query()->getRandomCard(); - } while (newCard == oldCard); - } - break; - } - if (!newCard) - return; - - connect(newCard.getCardPtr().data(), &CardInfo::pixmapUpdated, this, &HomeWidget::updateBackgroundProperties); - backgroundSourceCard->setCard(newCard); - background = backgroundSourceCard->getBackground(); -} - -void HomeWidget::onBackgroundShuffleFrequencyChanged() -{ - cardChangeTimer->stop(); - if (SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() > 0) { - cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000); - } -} - -void HomeWidget::updateBackgroundProperties() -{ - background = backgroundSourceCard->getBackground(); - updateButtonsToBackgroundColor(); - update(); // Triggers repaint -} - -void HomeWidget::updateButtonsToBackgroundColor() -{ - gradientColors = extractDominantColors(background); - for (HomeStyledButton *button : findChildren()) { - button->updateStylesheet(gradientColors); - button->update(); - } -} - -QGroupBox *HomeWidget::createButtons() -{ - QGroupBox *box = new QGroupBox(this); - box->setStyleSheet(R"( - QGroupBox { - font-size: 20px; - color: white; /* Title text color */ - background: transparent; - } - - QGroupBox::title { - color: white; - subcontrol-origin: margin; - subcontrol-position: top center; /* or top left / right */ - } -)"); - box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QVBoxLayout *boxLayout = new QVBoxLayout; - boxLayout->setAlignment(Qt::AlignHCenter); - - QLabel *logoLabel = new QLabel; - logoLabel->setPixmap(overlay.scaledToWidth(200, Qt::SmoothTransformation)); - logoLabel->setAlignment(Qt::AlignCenter); - boxLayout->addWidget(logoLabel); - boxLayout->addSpacing(25); - - connectButton = new HomeStyledButton("Connect/Play", gradientColors); - boxLayout->addWidget(connectButton); - - auto visualDeckEditorButton = new HomeStyledButton(tr("Create New Deck"), gradientColors); - connect(visualDeckEditorButton, &QPushButton::clicked, tabSupervisor, - [this] { tabSupervisor->openDeckInNewTab(LoadedDeck()); }); - boxLayout->addWidget(visualDeckEditorButton); - auto visualDeckStorageButton = new HomeStyledButton(tr("Browse Decks"), gradientColors); - connect(visualDeckStorageButton, &QPushButton::clicked, tabSupervisor, - [this] { tabSupervisor->actTabVisualDeckStorage(true); }); - boxLayout->addWidget(visualDeckStorageButton); - auto visualDatabaseDisplayButton = new HomeStyledButton(tr("Browse Card Database"), gradientColors); - connect(visualDatabaseDisplayButton, &QPushButton::clicked, tabSupervisor, - &TabSupervisor::addVisualDatabaseDisplayTab); - boxLayout->addWidget(visualDatabaseDisplayButton); - auto edhrecButton = new HomeStyledButton(tr("Browse EDHRec"), gradientColors); - connect(edhrecButton, &QPushButton::clicked, tabSupervisor, &TabSupervisor::addEdhrecMainTab); - boxLayout->addWidget(edhrecButton); - auto archidektButton = new HomeStyledButton(tr("Browse Archidekt"), gradientColors); - connect(archidektButton, &QPushButton::clicked, tabSupervisor, &TabSupervisor::addArchidektTab); - boxLayout->addWidget(archidektButton); - auto replaybutton = new HomeStyledButton(tr("View Replays"), gradientColors); - connect(replaybutton, &QPushButton::clicked, tabSupervisor, [this] { tabSupervisor->actTabReplays(true); }); - boxLayout->addWidget(replaybutton); - if (qobject_cast(tabSupervisor->parentWidget())) { - auto exitButton = new HomeStyledButton(tr("Quit"), gradientColors); - connect(exitButton, &QPushButton::clicked, qobject_cast(tabSupervisor->parentWidget()), - &MainWindow::actExit); - boxLayout->addWidget(exitButton); - } - - box->setLayout(boxLayout); - return box; -} - -void HomeWidget::updateConnectButton(const ClientStatus status) -{ - disconnect(connectButton, &QPushButton::clicked, nullptr, nullptr); - switch (status) { - case StatusConnecting: - connectButton->setText(tr("Connecting...")); - connectButton->setEnabled(false); - break; - case StatusDisconnected: - connectButton->setText(tr("Connect")); - connectButton->setEnabled(true); - connect(connectButton, &QPushButton::clicked, qobject_cast(tabSupervisor->parentWidget()), - &MainWindow::actConnect); - break; - case StatusLoggedIn: - connectButton->setText(tr("Play")); - connectButton->setEnabled(true); - connect(connectButton, &QPushButton::clicked, tabSupervisor, - &TabSupervisor::switchToFirstAvailableNetworkTab); - break; - default: - break; - } -} - -QPair HomeWidget::extractDominantColors(const QPixmap &pixmap) -{ - if (themeManager->isBuiltInTheme() && - SettingsCache::instance().getHomeTabBackgroundSource() == BackgroundSources::toId(BackgroundSources::Theme)) { - return QPair(QColor::fromRgb(20, 140, 60), QColor::fromRgb(120, 200, 80)); - } - - // Step 1: Downscale image for performance - QImage image = pixmap.toImage() - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation) - .convertToFormat(QImage::Format_RGB32); - - QMap colorCount; - - // Step 2: Count quantized colors - for (int y = 0; y < image.height(); ++y) { - const QRgb *scanLine = reinterpret_cast(image.scanLine(y)); - for (int x = 0; x < image.width(); ++x) { - QColor color = QColor::fromRgb(scanLine[x]); - - int r = color.red() & 0xF0; - int g = color.green() & 0xF0; - int b = color.blue() & 0xF0; - - QRgb quantized = qRgb(r, g, b); - colorCount[quantized]++; - } - } - - // Step 3: Sort by frequency - QVector> sortedColors; - for (auto it = colorCount.constBegin(); it != colorCount.constEnd(); ++it) { - sortedColors.append(qMakePair(it.key(), it.value())); - } - - std::sort(sortedColors.begin(), sortedColors.end(), - [](const QPair &a, const QPair &b) { return a.second > b.second; }); - - // Step 4: Pick top two distinct colors - QColor first = QColor(sortedColors.value(0).first); - QColor second = first; - - for (int i = 1; i < sortedColors.size(); ++i) { - QColor candidate = QColor(sortedColors[i].first); - if (candidate != first) { - second = candidate; - break; - } - } - - return QPair(first, second); -} - -void HomeWidget::paintEvent(QPaintEvent *event) -{ - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - - if (!background.isNull()) { - QSize widgetSize = size() * devicePixelRatio(); - QPixmap toDraw = background.scaled(widgetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - - // Draw scaled background centered - QSize bgSize = toDraw.size(); - QPoint topLeft((widgetSize.width() - bgSize.width()) / (devicePixelRatio() * 2), // undo scaling for painter - (widgetSize.height() - bgSize.height()) / (devicePixelRatio() * 2)); - - painter.drawPixmap(topLeft, toDraw); - } - - // Draw translucent black overlay with rounded corners - QRectF overlayRect(5, 5, width() - 10, height() - 10); - QPainterPath roundedRectPath; - roundedRectPath.addRoundedRect(overlayRect, 20, 20); - - QColor semiTransparentBlack(0, 0, 0, static_cast(255 * 0.33)); - painter.fillPath(roundedRectPath, semiTransparentBlack); - - // Card name overlay (bottom-right) - QString cardName; - ExactCard card = backgroundSourceCard->getCard(); - if (card) { - cardName = card.getCardPtr()->getName(); - if (card.getPrinting().getSet() != nullptr) { - cardName += " (" + card.getPrinting().getSet()->getCorrectedShortName() + ") " + - card.getPrinting().getProperty("num"); - } - } - - if (!cardName.isEmpty() && SettingsCache::instance().getHomeTabDisplayCardName()) { - QFont font = painter.font(); - font.setPointSize(14); - font.setBold(true); - painter.setFont(font); - - QFontMetrics fm(font); - constexpr int padding = 10; - constexpr int margin = 15; - - QRect textRect = fm.boundingRect(cardName); - - QRect bgRect(width() - textRect.width() - padding * 2 - margin, - height() - textRect.height() - padding * 2 - margin, textRect.width() + padding * 2, - textRect.height() + padding * 2); - - // Background bubble - painter.setPen(Qt::NoPen); - painter.setBrush(QColor(0, 0, 0, 160)); - painter.drawRoundedRect(bgRect, 8, 8); - - // Text - painter.setPen(Qt::white); - painter.drawText(bgRect.adjusted(padding, padding, -padding, -padding), Qt::AlignRight | Qt::AlignVCenter, - cardName); - } - - QWidget::paintEvent(event); -} diff --git a/cockatrice/src/interface/widgets/general/home_widget.h b/cockatrice/src/interface/widgets/general/home_widget.h deleted file mode 100644 index b30bb5407..000000000 --- a/cockatrice/src/interface/widgets/general/home_widget.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file home_widget.h - * @ingroup Core - * @ingroup Widgets - * @brief TODO: Document this. - */ - -#ifndef HOME_WIDGET_H -#define HOME_WIDGET_H -#include "../../../interface/widgets/tabs/tab_supervisor.h" -#include "../cards/card_info_picture_art_crop_widget.h" -#include "home_styled_button.h" - -#include -#include -#include - -class HomeWidget : public QWidget -{ - - Q_OBJECT - -public: - HomeWidget(QWidget *parent, TabSupervisor *tabSupervisor); - void updateRandomCard(); - QPair extractDominantColors(const QPixmap &pixmap); - -public slots: - void paintEvent(QPaintEvent *event) override; - void initializeBackgroundFromSource(); - void onBackgroundShuffleFrequencyChanged(); - void updateBackgroundProperties(); - void updateButtonsToBackgroundColor(); - QGroupBox *createButtons(); - void updateConnectButton(const ClientStatus status); - -private: - QGridLayout *layout; - QTimer *cardChangeTimer; - TabSupervisor *tabSupervisor; - QPixmap background; - CardInfoPictureArtCropWidget *backgroundSourceCard = nullptr; - DeckList backgroundSourceDeck; - QPixmap overlay; - QPair gradientColors; - HomeStyledButton *connectButton; - - void setRandomCard(ExactCard &newCard); - void loadBackgroundSourceDeck(); -}; - -#endif // HOME_WIDGET_H diff --git a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp index 1508b5243..697a4c48e 100644 --- a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp +++ b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp @@ -1,6 +1,7 @@ #include "printing_selector_card_overlay_widget.h" #include "../../../client/settings/cache_settings.h" +#include "../cards/card_info_picture_widget.h" #include "printing_selector_card_display_widget.h" #include diff --git a/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.h b/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.h index 477c3f973..a6d9ae164 100644 --- a/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.h +++ b/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.h @@ -8,6 +8,8 @@ #ifndef TAB_GENERIC_DECK_EDITOR_H #define TAB_GENERIC_DECK_EDITOR_H +#include "../../deck_loader/deck_loader.h" +#include "../../deck_loader/loaded_deck.h" #include "../interface/widgets/deck_editor/deck_editor_card_database_dock_widget.h" #include "../interface/widgets/deck_editor/deck_editor_card_info_dock_widget.h" #include "../interface/widgets/deck_editor/deck_editor_database_display_widget.h" @@ -15,7 +17,6 @@ #include "../interface/widgets/deck_editor/deck_editor_filter_dock_widget.h" #include "../interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.h" #include "../interface/widgets/menus/deck_editor_menu.h" -#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "tab.h" #include diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp deleted file mode 100644 index 40882db04..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "archidekt_deck_listing_api_response.h" - -#include -#include - -void ArchidektDeckListingApiResponse::fromJson(const QJsonObject &json) -{ - count = json.value("count").toInt(); - next = QUrl(json.value("next").toString()); - - QJsonArray containerJson = json.value("results").toArray(); - - for (const QJsonValue &deckListingValue : containerJson) { - ArchidektApiResponseDeckListingContainer listingResult; - listingResult.fromJson(deckListingValue.toObject()); - results.append(listingResult); - } -} - -void ArchidektDeckListingApiResponse::debugPrint() const -{ - qDebug() << "Count:" << count; - qDebug() << "Next:" << next; - - qDebug() << "Results:"; - for (const auto &deckListing : results) { - deckListing.debugPrint(); - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.h deleted file mode 100644 index 723c65ce2..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_H -#define COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_H - -#include "deck_listings/archidekt_api_response_deck_listing_container.h" - -#include -#include -#include - -class ArchidektDeckListingApiResponse -{ - -public: - int count; - QUrl next; - QVector results; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -#endif // COCKATRICE_DECK_LISTING_API_RESPONSE_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h deleted file mode 100644 index ac1b66e14..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_FORMATS_H -#define COCKATRICE_ARCHIDEKT_FORMATS_H -#include -#include - -namespace ArchidektFormats -{ -enum class DeckFormat -{ - Standard = 0, - Modern = 1, - Commander = 2, - Legacy = 3, - Vintage = 4, - Pauper = 5, - Custom = 6, - Frontier = 7, - FutureStandard = 8, - PennyDreadful = 9, - Commander1v1 = 10, - DualCommander = 11, - Brawl = 12, - - // Values outside Archidekt range - Alchemy = 1000, - Historic = 1001, - Gladiator = 1002, - Oathbreaker = 1003, - OldSchool = 1004, - PauperCommander = 1005, - Pioneer = 1006, - PreDH = 1007, - Premodern = 1008, - StandardBrawl = 1009, - Timeless = 1010, - Unknown = 1011 -}; - -inline static QString formatToApiName(DeckFormat format) -{ - switch (format) { - case DeckFormat::Standard: - return "Standard"; - case DeckFormat::Modern: - return "Modern"; - case DeckFormat::Commander: - return "Commander"; - case DeckFormat::Legacy: - return "Legacy"; - case DeckFormat::Vintage: - return "Vintage"; - case DeckFormat::Pauper: - return "Pauper"; - case DeckFormat::Custom: - return "Custom"; - case DeckFormat::Frontier: - return "Frontier"; - case DeckFormat::FutureStandard: - return "Future Std"; - case DeckFormat::PennyDreadful: - return "Penny Dreadful"; - case DeckFormat::Commander1v1: - return "1v1 Commander"; - case DeckFormat::DualCommander: - return "Dual Commander"; - case DeckFormat::Brawl: - return "Brawl"; - - case DeckFormat::Alchemy: - return "Alchemy"; - case DeckFormat::Historic: - return "Historic"; - case DeckFormat::Gladiator: - return "Gladiator"; - case DeckFormat::Oathbreaker: - return "Oathbreaker"; - case DeckFormat::OldSchool: - return "Old School"; - case DeckFormat::PauperCommander: - return "Pauper Commander"; - case DeckFormat::Pioneer: - return "Pioneer"; - case DeckFormat::PreDH: - return "PreDH"; - case DeckFormat::Premodern: - return "Premodern"; - case DeckFormat::StandardBrawl: - return "Standard Brawl"; - case DeckFormat::Timeless: - return "Timeless"; - - default: - return "Unknown"; - } -} - -inline static DeckFormat apiNameToFormat(const QString &name) -{ - const QString n = name.trimmed(); - - if (n.compare("Standard", Qt::CaseInsensitive) == 0) - return DeckFormat::Standard; - if (n.compare("Modern", Qt::CaseInsensitive) == 0) - return DeckFormat::Modern; - if (n.compare("Commander", Qt::CaseInsensitive) == 0) - return DeckFormat::Commander; - if (n.compare("Legacy", Qt::CaseInsensitive) == 0) - return DeckFormat::Legacy; - if (n.compare("Vintage", Qt::CaseInsensitive) == 0) - return DeckFormat::Vintage; - if (n.compare("Pauper", Qt::CaseInsensitive) == 0) - return DeckFormat::Pauper; - if (n.compare("Custom", Qt::CaseInsensitive) == 0) - return DeckFormat::Custom; - if (n.compare("Frontier", Qt::CaseInsensitive) == 0) - return DeckFormat::Frontier; - if (n.compare("Future Std", Qt::CaseInsensitive) == 0) - return DeckFormat::FutureStandard; - if (n.compare("Penny Dreadful", Qt::CaseInsensitive) == 0) - return DeckFormat::PennyDreadful; - if (n.compare("1v1 Commander", Qt::CaseInsensitive) == 0) - return DeckFormat::Commander1v1; - if (n.compare("Dual Commander", Qt::CaseInsensitive) == 0) - return DeckFormat::DualCommander; - if (n.compare("Brawl", Qt::CaseInsensitive) == 0) - return DeckFormat::Brawl; - - if (n.compare("Alchemy", Qt::CaseInsensitive) == 0) - return DeckFormat::Alchemy; - if (n.compare("Historic", Qt::CaseInsensitive) == 0) - return DeckFormat::Historic; - if (n.compare("Gladiator", Qt::CaseInsensitive) == 0) - return DeckFormat::Gladiator; - if (n.compare("Oathbreaker", Qt::CaseInsensitive) == 0) - return DeckFormat::Oathbreaker; - if (n.compare("Old School", Qt::CaseInsensitive) == 0) - return DeckFormat::OldSchool; - if (n.compare("Pauper Commander", Qt::CaseInsensitive) == 0) - return DeckFormat::PauperCommander; - if (n.compare("Pioneer", Qt::CaseInsensitive) == 0) - return DeckFormat::Pioneer; - if (n.compare("PreDH", Qt::CaseInsensitive) == 0) - return DeckFormat::PreDH; - if (n.compare("Premodern", Qt::CaseInsensitive) == 0) - return DeckFormat::Premodern; - if (n.compare("Standard Brawl", Qt::CaseInsensitive) == 0) - return DeckFormat::StandardBrawl; - if (n.compare("Timeless", Qt::CaseInsensitive) == 0) - return DeckFormat::Timeless; - - return DeckFormat::Unknown; -} - -inline static QString formatToCockatriceName(DeckFormat format) -{ - switch (format) { - case DeckFormat::Standard: - return "standard"; - case DeckFormat::Modern: - return "modern"; - case DeckFormat::Commander: - return "commander"; - case DeckFormat::Legacy: - return "legacy"; - case DeckFormat::Vintage: - return "vintage"; - case DeckFormat::Pauper: - return "pauper"; - case DeckFormat::Brawl: - return "brawl"; - case DeckFormat::PennyDreadful: - return "penny"; - case DeckFormat::FutureStandard: - return "future"; - case DeckFormat::Commander1v1: - return "duel"; - case DeckFormat::DualCommander: - return "duel"; - case DeckFormat::Alchemy: - return "alchemy"; - case DeckFormat::Historic: - return "historic"; - case DeckFormat::Gladiator: - return "gladiator"; - case DeckFormat::Oathbreaker: - return "oathbreaker"; - case DeckFormat::OldSchool: - return "oldschool"; - case DeckFormat::PauperCommander: - return "paupercommander"; - case DeckFormat::Pioneer: - return "pioneer"; - case DeckFormat::PreDH: - return "predh"; - case DeckFormat::Premodern: - return "premodern"; - case DeckFormat::StandardBrawl: - return "standardbrawl"; - case DeckFormat::Timeless: - return "timeless"; - - default: - return {}; - } -} - -inline static DeckFormat cockatriceNameToFormat(const QString &apiName) -{ - static const QHash map = { - {"standard", DeckFormat::Standard}, {"modern", DeckFormat::Modern}, - {"commander", DeckFormat::Commander}, {"legacy", DeckFormat::Legacy}, - {"vintage", DeckFormat::Vintage}, {"pauper", DeckFormat::Pauper}, - {"brawl", DeckFormat::Brawl}, {"penny", DeckFormat::PennyDreadful}, - {"future", DeckFormat::FutureStandard}, {"duel", DeckFormat::Commander1v1}, - {"alchemy", DeckFormat::Alchemy}, {"historic", DeckFormat::Historic}, - {"gladiator", DeckFormat::Gladiator}, {"oathbreaker", DeckFormat::Oathbreaker}, - {"oldschool", DeckFormat::OldSchool}, {"paupercommander", DeckFormat::PauperCommander}, - {"pioneer", DeckFormat::Pioneer}, {"predh", DeckFormat::PreDH}, - {"premodern", DeckFormat::Premodern}, {"standardbrawl", DeckFormat::StandardBrawl}, - {"timeless", DeckFormat::Timeless}}; - - return map.value(apiName.toLower(), DeckFormat::Unknown); -} - -} // namespace ArchidektFormats - -#endif // COCKATRICE_ARCHIDEKT_FORMATS_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp deleted file mode 100644 index 5b879f8ae..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "archidekt_api_response_card.h" - -void ArchidektApiResponseCard::fromJson(const QJsonObject &json) -{ - id = json.value("id").toInt(); - artist = json.value("artist").toString(); - tcgProductId = json.value("tcgProductId").toInt(); - ckFoilId = json.value("ckFoilId").toInt(); - ckNormalId = json.value("ckNormalId").toInt(); - cmEd = json.value("cmEd").toString(); - scgSku = json.value("scgSku").toString(); - scgFoilSku = json.value("scgFoilSku").toString(); - collectorNumber = json.value("collectorNumber").toString(); - multiverseId = json.value("multiverseId").toInt(); - mtgoFoilId = json.value("mtgoFoilId").toInt(); - mtgoNormalId = json.value("mtgoNormalId").toInt(); - uid = json.value("uid").toString(); - displayName = json.value("displayName").toString(); - releasedAt = json.value("releasedAt").toString(); - - edition.fromJson(json.value("edition").toObject()); - - flavor = json.value("flavor").toString(); - //! \todo but not really important - //! \todo games = {""}; - //! \todo options = {""}; - scryfallImageHash = json.value("scryfallImageHash").toString(); - oracleCard = json.value("oracleCard").toObject(); - owned = json.value("owned").toInt(); - pinnedStatus = json.value("pinnedStatus").toInt(); - rarity = json.value("rarity").toString(); - //! \todo but not really important - //! \todo globalCategories = {""}; -} - -void ArchidektApiResponseCard::debugPrint() const -{ - qDebug() << "Id:" << id; - qDebug() << "id:" << artist; - qDebug() << "artist:" << tcgProductId; - qDebug() << "tcgProductId:" << ckFoilId; - qDebug() << "ckFoilId:" << ckNormalId; - qDebug() << "ckNormalId:" << cmEd; - qDebug() << "cmEd:" << scgSku; - qDebug() << "scgSku:" << scgFoilSku; - qDebug() << "scgFoilSku:" << collectorNumber; - qDebug() << "collectorNumber:" << multiverseId; - qDebug() << "multiverseId:" << mtgoFoilId; - qDebug() << "mtgoFoilId:" << mtgoNormalId; - qDebug() << "mtgoNormalId:" << uid; - qDebug() << "uid:" << displayName; - qDebug() << "displayName:" << releasedAt; - qDebug() << "releasedAt:" << flavor; - qDebug() << "flavor:" << games; - qDebug() << "games:" << options; - qDebug() << "options:" << scryfallImageHash; - qDebug() << "scryfallImageHash:" << owned; - qDebug() << "owned:" << pinnedStatus; - qDebug() << "pinnedStatus:" << rarity; - qDebug() << "rarity:" << globalCategories; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.h deleted file mode 100644 index 265498228..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_H - -#include "archidekt_api_response_edition.h" - -#include -#include -#include -#include -#include - -class ArchidektApiResponseCard -{ -public: - // Constructor - ArchidektApiResponseCard() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - QJsonObject getOracleCard() const - { - return oracleCard; - }; - - QString getCollectorNumber() const - { - return collectorNumber; - } - - ArchidektApiResponseEdition getEdition() const - { - return edition; - } - -private: - int id; - QString artist; - int tcgProductId; - int ckFoilId; - int ckNormalId; - QString cmEd; - QString scgSku; - QString scgFoilSku; - QString collectorNumber; - int multiverseId; - int mtgoFoilId; - int mtgoNormalId; - QString uid; - QString displayName; - QString releasedAt; - ArchidektApiResponseEdition edition; - QString flavor; - QStringList games; - QStringList options; - QString scryfallImageHash; - QJsonObject oracleCard; - int owned; - int pinnedStatus; - // ArchidektApiResponsePrices prices; - QString rarity; - QStringList globalCategories; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp deleted file mode 100644 index f51d0f3e7..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "archidekt_api_response_card_entry.h" - -void ArchidektApiResponseCardEntry::fromJson(const QJsonObject &json) -{ - id = json.value("id").toInt(); - - categories.clear(); - - auto categoriesJson = json.value("categories").toArray(); - - for (const auto &categoryValue : categoriesJson) { - Category cat; - - if (categoryValue.isObject()) { - QJsonObject obj = categoryValue.toObject(); - - cat.id = obj.value("id").toInt(); - cat.name = obj.value("name").toString(); - cat.isPremier = obj.value("isPremier").toBool(); - cat.includedInDeck = obj.value("includedInDeck").toBool(); - cat.includedInPrice = obj.value("includedInPrice").toBool(); - } else if (categoryValue.isString()) { - cat.name = categoryValue.toString(); - - // assume mainboard unless known otherwise - cat.includedInDeck = true; - } - - categories.append(cat); - } - - companion = json.value("companion").toBool(); - flippedDefault = json.value("flippedDefault").toBool(); - label = json.value("label").toString(); - modifier = json.value("modifier").toString(); - quantity = json.value("quantity").toInt(); - customCmc = json.value("customCmc").toInt(); - // removedCategories = {""}; - createdAt = json.value("createdAt").toString(); - updatedAt = json.value("updatedAt").toString(); - deletedAt = json.value("deletedAt").toString(); - notes = json.value("notes").toString(); - card.fromJson(json.value("card").toObject()); -} - -void ArchidektApiResponseCardEntry::debugPrint() const -{ - qDebug() << "Id:" << id; - for (auto category : categories) { - qDebug() << "Category ID:" << category.id; - qDebug() << "Category Name:" << category.name; - qDebug() << "Category Premier:" << category.isPremier; - qDebug() << "Category Included in Deck:" << category.includedInDeck; - qDebug() << "Category Included in Price:" << category.includedInPrice; - } - qDebug() << "Companion:" << companion; - qDebug() << "FlippedDefault:" << flippedDefault; - qDebug() << "Label:" << label; - qDebug() << "Modifier:" << modifier; - qDebug() << "Quantity:" << quantity; - qDebug() << "CustomCmc:" << customCmc; - qDebug() << "RemovedCategories:" << removedCategories; - qDebug() << "CreatedAt:" << createdAt; - qDebug() << "UpdatedAt:" << updatedAt; - qDebug() << "DeletedAt:" << deletedAt; - qDebug() << "Notes:" << notes; - card.debugPrint(); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h deleted file mode 100644 index f3961dc6f..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_ENTRY_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_ENTRY_H - -#include "archidekt_api_response_card.h" - -#include -#include -#include -#include -#include - -struct Category -{ - int id; - QString name; - bool isPremier; - bool includedInDeck; - bool includedInPrice; -}; - -class ArchidektApiResponseCardEntry -{ -public: - // Constructor - ArchidektApiResponseCardEntry() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - ArchidektApiResponseCard getCard() const - { - return card; - }; - - QList getCategories() const - { - return categories; - } - - int getQuantity() const - { - return quantity; - } - -private: - int id; - QList categories; - bool companion; - bool flippedDefault; - QString label; - QString modifier; - int quantity; - int customCmc; - QStringList removedCategories; - QString createdAt; - QString updatedAt; - QString deletedAt; - QString notes; - ArchidektApiResponseCard card; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_CARD_ENTRY_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp deleted file mode 100644 index 122617a22..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "archidekt_api_response_edition.h" - -void ArchidektApiResponseEdition::fromJson(const QJsonObject &json) -{ - editionCode = json.value("editioncode").toString(); - editionName = json.value("editionname").toString(); - editionDate = json.value("editiondate").toString(); - editionType = json.value("editiontype").toString(); - mtgoCode = json.value("mtgocode").toString(); -} - -void ArchidektApiResponseEdition::debugPrint() const -{ - qDebug() << "Edition Code: " << editionCode; - qDebug() << "Edition Name: " << editionName; - qDebug() << "Edition Date: " << editionDate; - qDebug() << "Edition Type: " << editionType; - qDebug() << "Mtgo Code: " << mtgoCode; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.h deleted file mode 100644 index b898cd816..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_EDITION_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_EDITION_H - -#include -#include -#include -#include -#include - -class ArchidektApiResponseEdition -{ -public: - // Constructor - ArchidektApiResponseEdition() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - [[nodiscard]] QString getEditionCode() const - { - return editionCode; - } - [[nodiscard]] QString getEditionName() const - { - return editionName; - } - [[nodiscard]] QString getEditionDate() const - { - return editionDate; - } - [[nodiscard]] QString getEditionType() const - { - return editionType; - } - [[nodiscard]] QString getMtgoCode() const - { - return mtgoCode; - } - -private: - QString editionCode; - QString editionName; - QString editionDate; - QString editionType; - QString mtgoCode; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_EDITION_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp deleted file mode 100644 index 98d8c6c8c..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "archidekt_api_response_deck.h" - -#include "../card/archidekt_api_response_card_entry.h" - -void ArchidektApiResponseDeck::fromJson(const QJsonObject &json) -{ - id = json.value("id").toInt(); - name = json.value("name").toString(); - size = json.value("size").toInt(); - updatedAt = json.value("updatedAt").toString(); - createdAt = json.value("createdAt").toString(); - deckFormat = json.value("deckFormat").toInt(); - edhBracket = json.value("edhBracket").toInt(); - featured = json.value("featured").toString(); - customFeatured = json.value("customFeatured").toString(); - viewCount = json.value("viewCount").toInt(); - privateDeck = json.value("private").toBool(); - unlisted = json.value("unlisted").toBool(); - theoryCrafted = json.value("theoryCrafted").toBool(); - points = json.value("points").toInt(); - userInput = json.value("userInput").toInt(); - owner.fromJson(json.value("owner").toObject()); - commentRoot = json.value("commentRoot").toInt(); - editors = json.value("editors").toString(); - parentFolderId = json.value("parentFolderId").toInt(); - bookmarked = json.value("bookmarked").toBool(); - - auto categoriesJson = json.value("categories").toArray(); - for (auto category : categoriesJson) { - ArchidektApiResponseDeckCategory categoryEntry; - categoryEntry.fromJson(category.toObject()); - categories.append(categoryEntry); - } - - // deckTags = {""}; - playgroupDeckUrl = json.value("playgroupDeckUrl").toString(); - cardPackage = json.value("cardPackage").toString(); - - auto cardsObject = json.value("cards").toArray(); - - for (auto card : cardsObject) { - ArchidektApiResponseCardEntry entry; - entry.fromJson(card.toObject()); - cards.append(entry); - } - - // TODO but not really important - // customCards = {""}; -} - -void ArchidektApiResponseDeck::debugPrint() const -{ - qDebug() << "Id:" << id; - qDebug() << "Name:" << name; - qDebug() << "Size:" << size; - qDebug() << "UpdatedAt:" << updatedAt; - qDebug() << "CreatedAt:" << createdAt; - qDebug() << "DeckFormat:" << deckFormat; - qDebug() << "EdhBracket:" << edhBracket; - qDebug() << "Featured:" << featured; - qDebug() << "CustomFeatured:" << customFeatured; - qDebug() << "ViewCount:" << viewCount; - qDebug() << "Private:" << privateDeck; - qDebug() << "Unlisted:" << unlisted; - qDebug() << "TheoryCrafted:" << theoryCrafted; - qDebug() << "Points:" << points; - qDebug() << "UserInput:" << userInput; - owner.debugPrint(); - qDebug() << "CommentRoot:" << commentRoot; - qDebug() << "Editors:" << editors; - qDebug() << "ParentFolderId:" << parentFolderId; - qDebug() << "Bookmarked:" << bookmarked; - qDebug() << "DeckTags:" << deckTags; - qDebug() << "PlaygroupDeckUrl:" << playgroupDeckUrl; - qDebug() << "CardPackage:" << cardPackage; - for (auto card : cards) { - card.debugPrint(); - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.h deleted file mode 100644 index fce437751..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_H - -#include "../card/archidekt_api_response_card.h" -#include "../card/archidekt_api_response_card_entry.h" -#include "../deck_listings/archidekt_api_response_deck_owner.h" -#include "archidekt_api_response_deck_category.h" - -#include -#include -#include -#include -#include - -class ArchidektApiResponseDeck -{ -public: - // Constructor - ArchidektApiResponseDeck() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - QVector getCards() const - { - return cards; - }; - - QVector getCategories() const - { - return categories; - } - - QString getDeckName() const - { - return name; - }; - - int getDeckFormat() const - { - return deckFormat; - } - -private: - int id; - QString name; - int size; - QString updatedAt; - QString createdAt; - int deckFormat; - int edhBracket; - QString featured; - QString customFeatured; - int viewCount; - bool privateDeck; - bool unlisted; - bool theoryCrafted; - int points; - int userInput; - ArchidektApiResponseDeckOwner owner; - int commentRoot; - QString editors; - int parentFolderId; - bool bookmarked; - QVector categories; - QStringList deckTags; - QString playgroupDeckUrl; - QString cardPackage; - QVector cards; - QStringList customCards; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp deleted file mode 100644 index 990293bc6..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "archidekt_api_response_deck_category.h" - -void ArchidektApiResponseDeckCategory::fromJson(const QJsonObject &json) -{ - id = json.value("id").toInt(); - name = json.value("name").toString(); - isPremier = json.value("isPremier").toBool(); - includedInDeck = json.value("includedInDeck").toBool(); - includedInPrice = json.value("includedInPrice").toBool(); -} - -void ArchidektApiResponseDeckCategory::debugPrint() const -{ - qDebug() << "Id:" << id; - qDebug() << "Name:" << name; - qDebug() << "isPremier:" << isPremier; - qDebug() << "IncludedInDeck:" << includedInDeck; - qDebug() << "IncludedInPrice:" << includedInPrice; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.h deleted file mode 100644 index 5e218b6a4..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck/archidekt_api_response_deck_category.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_CATEGORY_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_CATEGORY_H - -#include "../card/archidekt_api_response_card.h" -#include "../card/archidekt_api_response_card_entry.h" -#include "../deck_listings/archidekt_api_response_deck_owner.h" - -#include -#include -#include -#include -#include - -class ArchidektApiResponseDeckCategory -{ -public: - // Constructor - ArchidektApiResponseDeckCategory() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - [[nodiscard]] int getId() const - { - return id; - } - [[nodiscard]] QString getName() const - { - return name; - } - [[nodiscard]] bool getIsPremier() const - { - return isPremier; - } - [[nodiscard]] bool getIncludedInDeck() const - { - return includedInDeck; - } - [[nodiscard]] bool getIncludedInPrice() const - { - return includedInPrice; - } - -private: - int id; - QString name; - bool isPremier; - bool includedInDeck; - bool includedInPrice; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_CATEGORY_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp deleted file mode 100644 index 16ea60487..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "archidekt_api_response_deck_listing_container.h" - -#include "archidekt_api_response_deck_owner.h" - -#include -#include -#include - -void ArchidektApiResponseDeckListingContainer::fromJson(const QJsonObject &json) -{ - id = json.value("id").toInt(); - name = json.value("name").toString(); - size = json.value("size").toInt(); - updatedAt = json.value("updatedAt").toString(); - createdAt = json.value("createdAt").toString(); - deckFormat = json.value("deckFormat").toInt(); - edhBracket = json.value("edhBracket").toInt(); - featured = json.value("featured").toString(); - customFeatured = json.value("customFeatured").toString(); - viewCount = json.value("viewCount").toInt(); - privateDeck = json.value("private").toBool(); - unlisted = json.value("unlisted").toBool(); - theoryCrafted = json.value("theoryCrafted").toBool(); - game = json.value("game").toString(); - hasDescription = json.value("hasDescription").toBool(); - // TODO - // tags = {""}; - parentFolderId = json.value("parentFolderId").toInt(); - owner.fromJson(json.value("owner").toObject()); - - auto colorsJson = json.value("colors").toObject(); - - for (auto color : colorsJson.keys()) { - colors[color] = colorsJson[color].toInt(); - } - - cardPackage = json.value("cardPackage").toString(); - contest = json.value("contest").toString(); -} - -void ArchidektApiResponseDeckListingContainer::debugPrint() const -{ - qDebug() << "Id:" << id; - qDebug() << "Name:" << name; - qDebug() << "Size:" << size; - qDebug() << "UpdatedAt:" << updatedAt; - qDebug() << "CreatedAt:" << createdAt; - qDebug() << "DeckFormat:" << deckFormat; - qDebug() << "EdhBracket:" << edhBracket; - qDebug() << "Featured:" << featured; - qDebug() << "CustomFeatured:" << customFeatured; - qDebug() << "ViewCount:" << viewCount; - qDebug() << "Private:" << privateDeck; - qDebug() << "Unlisted:" << unlisted; - qDebug() << "TheoryCrafted:" << theoryCrafted; - qDebug() << "Game:" << game; - qDebug() << "HasDescription:" << hasDescription; - qDebug() << "Tags:" << tags; - qDebug() << "ParentFolderId:" << parentFolderId; - owner.debugPrint(); - qDebug() << "Colors:" << colors; - qDebug() << "CardPackage" << cardPackage; - qDebug() << "Contest:" << contest; -} diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.h deleted file mode 100644 index 8924bb3f5..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_listing_container.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_CONTAINER_H -#define COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_CONTAINER_H - -#include "archidekt_api_response_deck_owner.h" - -#include -#include -#include -#include -#include - -class ArchidektApiResponseDeckListingContainer -{ -public: - // Constructor - ArchidektApiResponseDeckListingContainer() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - [[nodiscard]] int getId() const - { - return id; - } - [[nodiscard]] QString getName() const - { - return name; - } - [[nodiscard]] int getSize() const - { - return size; - } - [[nodiscard]] QString getUpdatedAt() const - { - return updatedAt; - } - [[nodiscard]] QString getCreatedAt() const - { - return createdAt; - } - [[nodiscard]] int getDeckFormat() const - { - return deckFormat; - } - [[nodiscard]] int getEDHBracket() const - { - return edhBracket; - } - [[nodiscard]] QString getFeatured() const - { - return featured; - } - [[nodiscard]] QString getCustomFeatured() const - { - return customFeatured; - } - [[nodiscard]] int getViewCount() const - { - return viewCount; - } - [[nodiscard]] bool getPrivateDeck() const - { - return privateDeck; - } - [[nodiscard]] bool getUnlisted() const - { - return unlisted; - } - [[nodiscard]] bool getTheoryCrafted() const - { - return theoryCrafted; - } - [[nodiscard]] QString getGame() const - { - return game; - } - [[nodiscard]] bool getHasDescription() const - { - return hasDescription; - } - [[nodiscard]] QStringList getTags() const - { - return tags; - } - [[nodiscard]] int getParentFolderId() const - { - return parentFolderId; - } - [[nodiscard]] ArchidektApiResponseDeckOwner getOwner() const - { - return owner; - } - [[nodiscard]] QMap getColors() const - { - return colors; - } - [[nodiscard]] QString getCardPackage() const - { - return cardPackage; - } - [[nodiscard]] QString getContest() const - { - return contest; - } - -private: - int id; - QString name; - int size; - QString updatedAt; - QString createdAt; - int deckFormat; - int edhBracket; - QString featured; - QString customFeatured; - int viewCount; - bool privateDeck; - bool unlisted; - bool theoryCrafted; - QString game; - bool hasDescription; - QStringList tags; - int parentFolderId; - ArchidektApiResponseDeckOwner owner; - QMap colors; - QString cardPackage; - QString contest; -}; - -#endif // COCKATRICE_ARCHIDEKT_DECK_LISTING_API_RESPONSE_CONTAINER_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp deleted file mode 100644 index 2ba926f8b..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "archidekt_api_response_deck_owner.h" - -void ArchidektApiResponseDeckOwner::fromJson(const QJsonObject &json) -{ - id = json.value("id").toInt(); - userName = json.value("username").toString(); - avatar = QUrl(json.value("avatar").toString()); - moderator = json.value("moderator").toBool(); - pledgeLevel = json.value("pledgeLevel").toInt(); - // TODO but not really important - // roles = {""}; -} - -void ArchidektApiResponseDeckOwner::debugPrint() const -{ - qDebug() << "Id:" << id; - qDebug() << "UserName:" << userName; - qDebug() << "Avatar:" << avatar; - qDebug() << "Moderator:" << moderator; - qDebug() << "PledgeLevel:" << pledgeLevel; - qDebug() << "Roles:" << roles; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.h deleted file mode 100644 index df3f48fd2..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/api_response/deck_listings/archidekt_api_response_deck_owner.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_OWNER_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_OWNER_H - -#include -#include -#include -#include -#include - -class ArchidektApiResponseDeckOwner -{ -public: - // Constructor - ArchidektApiResponseDeckOwner() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - [[nodiscard]] QString getName() const - { - return userName; - } - -private: - int id; - QString userName; - QUrl avatar; - bool moderator; - int pledgeLevel; - QStringList roles; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_OWNER_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp deleted file mode 100644 index 66b68d823..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "archidekt_api_response_deck_display_widget.h" - -#include "../../../../../deck_loader/card_node_function.h" -#include "../../../../../deck_loader/deck_loader.h" -#include "../../../../cards/card_size_widget.h" -#include "../../../../cards/deck_card_zone_display_widget.h" -#include "../../../../visual_deck_editor/visual_deck_display_options_widget.h" -#include "../api_response/archidekt_formats.h" -#include "../api_response/deck/archidekt_api_response_deck.h" - -#include -#include - -ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWidget *parent, - ArchidektApiResponseDeck _response, - CardSizeWidget *_cardSizeSlider) - : QWidget(parent), response(_response), cardSizeSlider(_cardSizeSlider) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - navigationContainer = new QWidget(this); - navigationContainerLayout = new QHBoxLayout(navigationContainer); - - homeButton = new QPushButton(navigationContainer); - navigationContainerLayout->addWidget(homeButton); - - connect(homeButton, &QPushButton::clicked, this, &ArchidektApiResponseDeckDisplayWidget::requestSearch); - - openInEditorButton = new QPushButton(navigationContainer); - navigationContainerLayout->addWidget(openInEditorButton); - - connect(openInEditorButton, &QPushButton::clicked, this, - &ArchidektApiResponseDeckDisplayWidget::actOpenInDeckEditor); - - layout->addWidget(navigationContainer); - - displayOptionsWidget = new VisualDeckDisplayOptionsWidget(this); - layout->addWidget(displayOptionsWidget); - - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::groupCriteriaChanged, this, - &ArchidektApiResponseDeckDisplayWidget::onGroupCriteriaChange); - - scrollArea = new QScrollArea(this); - scrollArea->setWidgetResizable(true); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - - layout->addWidget(scrollArea); - - container = new QWidget(scrollArea); - - scrollArea->setWidget(container); - - containerLayout = new QVBoxLayout(container); - container->setLayout(containerLayout); - - zoneContainer = new QWidget(container); - containerLayout->addWidget(zoneContainer); - zoneContainerLayout = new QVBoxLayout(zoneContainer); - zoneContainer->setLayout(zoneContainerLayout); - - QString tempDeck; - QTextStream deckStream(&tempDeck); - - QString mainboardText; - QString sideboardText; - - QTextStream mainStream(&mainboardText); - QTextStream sideStream(&sideboardText); - - for (const auto &card : response.getCards()) { - QString fullName = card.getCard().getOracleCard().value("name").toString(); - // We don't really care about the second card, the card database already has it as a relation - QString cleanName = fullName.split("//").first().trimmed(); - - QString line = QString("%1 %2 (%3) %4\n") - .arg(card.getQuantity()) - .arg(cleanName) - .arg(card.getCard().getEdition().getEditionCode().toUpper()) - .arg(card.getCard().getCollectorNumber()); - - bool isCommander = false; - bool isSideboardCategory = false; - bool includedInDeck = false; - - for (const auto &cat : card.getCategories()) { - - if (cat.name.compare("Commander", Qt::CaseInsensitive) == 0) { - isCommander = true; - } - - if (cat.name.compare("Sideboard", Qt::CaseInsensitive) == 0 || - cat.name.compare("Maybeboard", Qt::CaseInsensitive) == 0) { - isSideboardCategory = true; - } - - if (cat.includedInDeck) { - includedInDeck = true; - } - } - - QString target; - - if (isCommander || isSideboardCategory) { - sideStream << line; - } else if (includedInDeck) { - mainStream << line; - } else { - sideStream << line; - } - } - - // Combine with blank line separator - tempDeck = mainboardText; - - if (!sideboardText.isEmpty()) { - tempDeck += "\n"; - tempDeck += sideboardText; - } - - model = new DeckListModel(this); - connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset); - - auto decklist = QSharedPointer(new DeckList); - decklist->loadFromStream_Plain(deckStream, false, CardNameNormalizer()); - model->setDeckList(decklist); - - model->forEachCard(CardNodeFunction::ResolveProviderId()); - - retranslateUi(); -} - -void ArchidektApiResponseDeckDisplayWidget::retranslateUi() -{ - homeButton->setText(tr("Back to results")); - openInEditorButton->setText(tr("Open Deck in Deck Editor")); -} - -void ArchidektApiResponseDeckDisplayWidget::onGroupCriteriaChange(const QString &activeGroupCriteria) -{ - model->setActiveGroupCriteria(DeckListModelGroupCriteria::fromString(activeGroupCriteria)); - model->sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder); -} - -void ArchidektApiResponseDeckDisplayWidget::actOpenInDeckEditor() -{ - DeckList deckList(*model->getDeckList()); - deckList.setName(response.getDeckName()); - deckList.setGameFormat( - ArchidektFormats::formatToCockatriceName(ArchidektFormats::DeckFormat(response.getDeckFormat() - 1))); - - LoadedDeck loadedDeck = {deckList, {}}; - - emit openInDeckEditor(loadedDeck); -} - -void ArchidektApiResponseDeckDisplayWidget::clearAllDisplayWidgets() -{ - for (auto idx : indexToWidgetMap.keys()) { - auto displayWidget = indexToWidgetMap.value(idx); - zoneContainerLayout->removeWidget(displayWidget); - indexToWidgetMap.remove(idx); - delete displayWidget; - } -} - -void ArchidektApiResponseDeckDisplayWidget::decklistModelReset() -{ - clearAllDisplayWidgets(); - constructZoneWidgetsFromDeckListModel(); -} - -void ArchidektApiResponseDeckDisplayWidget::constructZoneWidgetsFromDeckListModel() -{ - qDebug() << model->rowCount(model->getRoot()); - QSortFilterProxyModel proxy; - proxy.setSourceModel(model); - proxy.setSortRole(Qt::EditRole); - proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder); - - for (int i = 0; i < proxy.rowCount(); ++i) { - QModelIndex proxyIndex = proxy.index(i, 0); - QModelIndex sourceIndex = proxy.mapToSource(proxyIndex); - - // Make a persistent index from the *source* model - QPersistentModelIndex persistent(sourceIndex); - - if (indexToWidgetMap.contains(persistent)) { - continue; - } - - QString zoneName = - persistent.sibling(persistent.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString(); - - DeckCardZoneDisplayWidget *zoneDisplayWidget = - new DeckCardZoneDisplayWidget(zoneContainer, model, nullptr, persistent, zoneName, "maintype", {"name"}, - DisplayType::Overlap, 20, 10, cardSizeSlider); - - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::sortCriteriaChanged, zoneDisplayWidget, - &DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged); - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::groupCriteriaChanged, zoneDisplayWidget, - &DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged); - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::displayTypeChanged, zoneDisplayWidget, - &DeckCardZoneDisplayWidget::refreshDisplayType); - zoneContainerLayout->addWidget(zoneDisplayWidget); - - indexToWidgetMap.insert(persistent, zoneDisplayWidget); - } -} - -void ArchidektApiResponseDeckDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - layout->invalidate(); - layout->activate(); - layout->update(); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.h deleted file mode 100644 index aaf272718..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.h +++ /dev/null @@ -1,129 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_DISPLAY_WIDGET_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_DISPLAY_WIDGET_H - -#include "../../../../../deck_loader/deck_loader.h" -#include "../../../../cards/card_size_widget.h" -#include "../../../../general/layout_containers/flow_widget.h" -#include "../../../../visual_deck_editor/visual_deck_display_options_widget.h" -#include "../api_response/deck/archidekt_api_response_deck.h" -#include "deck_list_model.h" - -#include -#include -#include -#include -#include - -/** - * @class ArchidektApiResponseDeckDisplayWidget - * @brief Displays a full deck fetched from an Archidekt API response. - * - * This widget visualizes all cards in a deck retrieved from the Archidekt API. - * It supports: - * - Interactive display options via a VisualDeckDisplayOptionsWidget. - * - Scrollable display of deck zones/cards with DeckCardZoneDisplayWidget. - * - Integration with a CardSizeWidget slider for card scaling. - * - Opening the deck in a deck editor. - * - * The widget internally constructs a DeckListModel from the Archidekt API response, - * then builds zone widgets for each group of cards according to the active group - * criteria. It also responds dynamically to model resets or sorting/grouping changes. - * - * ### Signals - * - `requestNavigation(QString url)` — triggered when navigation to a deck URL is requested. - * - `openInDeckEditor(const LoadedDeck &deck)` — emitted when the user chooses to open the deck - * in the deck editor. - * - * ### Features - * - Automatically generates DeckCardZoneDisplayWidget instances for each card group. - * - Provides a scrollable layout for decks of arbitrary size. - * - Updates layouts dynamically when resized or when display/group/sort criteria change. - */ -class ArchidektApiResponseDeckDisplayWidget : public QWidget -{ - Q_OBJECT - -signals: - /** - * @brief Emitted when navigation to a deck URL is requested. - * @param url URL of the deck on Archidekt. - */ - void requestNavigation(QString url); - void requestSearch(); - - /** - * @brief Emitted when the deck should be opened in the deck editor. - * @param deck LoadedDeck containing the deck data. - */ - void openInDeckEditor(const LoadedDeck &deck); - -public: - /** - * @brief Constructs a display widget for an Archidekt deck. - * @param parent Parent widget. - * @param response API deck data container. - * @param cardSizeSlider Slider controlling card scaling. - */ - explicit ArchidektApiResponseDeckDisplayWidget(QWidget *parent, - ArchidektApiResponseDeck response, - CardSizeWidget *cardSizeSlider); - - /** - * @brief Updates all UI text for retranslation/localization. - * - * Called when the application language changes. - */ - void retranslateUi(); - - /** - * @brief Opens the deck in the deck editor. - */ - void actOpenInDeckEditor(); - - /** - * @brief Clears all dynamically generated card zone display widgets. - */ - void clearAllDisplayWidgets(); - - /** - * @brief Handles model reset by clearing and reconstructing display widgets. - */ - void decklistModelReset(); - - /** - * @brief Builds DeckCardZoneDisplayWidget instances from the current DeckListModel. - */ - void constructZoneWidgetsFromDeckListModel(); - -private slots: - /** - * @brief Slot triggered when the active group criteria change. - * @param activeGroupCriteria Name of the new grouping criteria. - */ - void onGroupCriteriaChange(const QString &activeGroupCriteria); - -private: - ArchidektApiResponseDeck response; ///< API deck data container - CardSizeWidget *cardSizeSlider; ///< Slider for adjusting card sizes - QVBoxLayout *layout; ///< Main vertical layout - QWidget *navigationContainer; - QHBoxLayout *navigationContainerLayout; - QPushButton *homeButton; - QPushButton *openInEditorButton; ///< Button to open deck in editor - VisualDeckDisplayOptionsWidget *displayOptionsWidget; ///< Controls grouping/sorting/display - QScrollArea *scrollArea; ///< Scrollable area for deck zones - QWidget *zoneContainer; ///< Container for deck zones - QVBoxLayout *zoneContainerLayout; ///< Layout for deck zones - QWidget *container; ///< Outer container for scroll area - QHash indexToWidgetMap; ///< Maps model indices to widgets - QVBoxLayout *containerLayout; ///< Layout for container - DeckListModel *model; ///< Deck list model -protected slots: - /** - * @brief Updates layout and display on resize. - * @param event Resize event. - */ - void resizeEvent(QResizeEvent *event) override; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp deleted file mode 100644 index c26220869..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include "archidekt_api_response_deck_entry_display_widget.h" - -#include "../../../../../card_picture_loader/card_picture_loader.h" -#include "../../../../cards/card_info_picture_with_text_overlay_widget.h" -#include "../../../../general/display/background_plate_widget.h" -#include "../../../../general/display/charts/bars/color_bar.h" -#include "archidekt_deck_preview_image_display_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -#define ARCHIDEKT_DEFAULT_IMAGE "https://storage.googleapis.com/topdekt-user/images/archidekt_deck_card_shadow.jpg" - -static QString timeAgo(const QString ×tamp) -{ - QDateTime dt = QDateTime::fromString(timestamp, Qt::ISODate); - - if (!dt.isValid()) - return timestamp; // fallback if parsing fails - - qint64 secs = dt.secsTo(QDateTime::currentDateTimeUtc()); - - if (secs < 60) - return QString("%1 seconds ago").arg(secs); - if (secs < 3600) - return QString("%1 minutes ago").arg(secs / 60); - if (secs < 86400) - return QString("%1 hours ago").arg(secs / 3600); - if (secs < 30 * 86400) - return QString("%1 days ago").arg(secs / 86400); - if (secs < 365 * 86400) - return QString("%1 months ago").arg(secs / (30 * 86400)); - - return QString("%1 years ago").arg(secs / (365 * 86400)); -} - -ArchidektApiResponseDeckEntryDisplayWidget::ArchidektApiResponseDeckEntryDisplayWidget( - QWidget *parent, - ArchidektApiResponseDeckListingContainer _response, - QNetworkAccessManager *_imageNetworkManager) - : QWidget(parent), response(_response), imageNetworkManager(_imageNetworkManager) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - this->setMaximumWidth(400); - this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); - - auto headerLayout = new QVBoxLayout(); - - previewWidget = new ArchidektDeckPreviewImageDisplayWidget(this); - - previewWidget->setMaximumWidth(400); - previewWidget->setMinimumHeight(300); // consistent height - - // Set deck name (ellided) - QFontMetrics fm(previewWidget->topLeftLabel->font()); - QString elided = fm.elidedText(response.getName(), Qt::ElideRight, 280); - previewWidget->topLeftLabel->setLabelText(elided); - previewWidget->topLeftLabel->setToolTip(response.getName()); - - // Set count - previewWidget->topRightLabel->setLabelText(QString::number(response.getSize())); - - // EDH bracket (skip if 0) - if (response.getEDHBracket() != 0) { - previewWidget->bottomLeftLabel->setLabelText(QString("EDH: %1").arg(response.getEDHBracket())); - } else { - previewWidget->bottomLeftLabel->hide(); - } - - // Views - previewWidget->bottomRightLabel->setLabelText(QString("Views: %1").arg(response.getViewCount())); - - // Use preview->imageLabel for image loading - picture = previewWidget->imageLabel; - - imageUrl = response.getFeatured().isEmpty() ? QUrl(ARCHIDEKT_DEFAULT_IMAGE) : QUrl(response.getFeatured()); - - QNetworkRequest req(imageUrl); - req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - QNetworkReply *reply = imageNetworkManager->get(req); - - // tag the reply with "this" so we know it belongs to us later - reply->setProperty("deckWidget", QVariant::fromValue(this)); - reply->setProperty("requestedUrl", imageUrl); - - connect(imageNetworkManager, &QNetworkAccessManager::finished, this, - &ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished); - - headerLayout->addWidget(previewWidget); - - auto colors = response.getColors(); - - ColorBar *colorBar = new ColorBar(colors, this); - colorBar->setMinPercentThreshold(3); - colorBar->setFixedHeight(22); - - headerLayout->addWidget(colorBar); - - // Create a shared plate for the labels - backgroundPlateWidget = new BackgroundPlateWidget(this); - backgroundPlateWidget->setFixedHeight(120); // Adjust height to fit all labels - - QVBoxLayout *plateLayout = new QVBoxLayout(backgroundPlateWidget); - - // Add labels to the plate layout - QLabel *ownerLabel = new QLabel(QString("Owner: %1").arg(response.getOwner().getName())); - plateLayout->addWidget(ownerLabel); - - QLabel *createdAtLabel = new QLabel(QString("Created: %1").arg(timeAgo(response.getCreatedAt()))); - plateLayout->addWidget(createdAtLabel); - - QLabel *updatedAtLabel = new QLabel(QString("Updated: %1").arg(timeAgo(response.getUpdatedAt()))); - plateLayout->addWidget(updatedAtLabel); - - // Add the shared plate to the header layout - headerLayout->addWidget(backgroundPlateWidget); - - layout->addLayout(headerLayout); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::mousePressEvent(QMouseEvent *event) -{ - QWidget::mousePressEvent(event); - actRequestNavigationToDeck(); -} - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -void ArchidektApiResponseDeckEntryDisplayWidget::enterEvent(QEnterEvent *event) -#else -void ArchidektApiResponseDeckEntryDisplayWidget::enterEvent(QEvent *event) -#endif -{ - QWidget::enterEvent(event); - backgroundPlateWidget->setFocused(true); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::leaveEvent(QEvent *event) -{ - QWidget::leaveEvent(event); - backgroundPlateWidget->setFocused(false); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::setScaleFactor(int scale) -{ - scaleFactor = scale; - updateScaledPreview(); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::onPreviewImageLoadFinished(QNetworkReply *reply) -{ - // Check if this is our reply - void *owner = reply->property("deckWidget").value(); - if (owner != this) { - return; // not our reply - } - - // Check that the requested URL matches what we asked - QUrl requestedUrl = reply->property("requestedUrl").toUrl(); - if (requestedUrl != imageUrl) { - reply->deleteLater(); - return; - } - - QPixmap loaded; - - if (reply->error() != QNetworkReply::NoError || !loaded.loadFromData(reply->readAll())) { - CardPictureLoader::getCardBackLoadingFailedPixmap(loaded, QSize(400, 400)); - } - - originalPixmap = loaded; - - // Always scale preview widget to this ratio - previewWidget->setAspectRatio(DESIGN_RATIO); - previewWidget->setPreviewWidth(400); - - // Initial scaling - updateScaledPreview(); - - reply->deleteLater(); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::updateScaledPreview() -{ - if (originalPixmap.isNull()) { - return; - } - - int baseWidth = 400; - int newWidth = baseWidth * scaleFactor / 100; - int newHeight = static_cast(newWidth * DESIGN_RATIO); - - previewWidget->setFixedSize(newWidth, newHeight); - - // Scale image to fill the preview area (crop edges) - QPixmap scaled = - originalPixmap.scaled(newWidth, newHeight, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - - // Crop to exact target size - QRect cropRect((scaled.width() - newWidth) / 2, (scaled.height() - newHeight) / 2, newWidth, newHeight); - QPixmap cropped = scaled.copy(cropRect); - - picture->setPixmap(cropped); - picture->setFixedSize(newWidth, newHeight); - - // Update the elided deck name based on new width - int textMaxWidth = int(newWidth * 0.7); // allow 70% of width for text - QFontMetrics fm(previewWidget->topLeftLabel->font()); - QString elided = fm.elidedText(response.getName(), Qt::ElideRight, textMaxWidth); - previewWidget->topLeftLabel->setLabelText(elided); - previewWidget->topLeftLabel->setToolTip(response.getName()); - - setFixedWidth(newWidth); - - layout->invalidate(); - layout->activate(); - updateGeometry(); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - layout->invalidate(); - layout->activate(); - layout->update(); -} - -void ArchidektApiResponseDeckEntryDisplayWidget::actRequestNavigationToDeck() -{ - emit requestNavigation(QString("https://archidekt.com/api/decks/%1/").arg(response.getId())); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.h deleted file mode 100644 index 365a99c9c..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H - -#include "../../../../cards/card_info_picture_with_text_overlay_widget.h" -#include "../api_response/deck_listings/archidekt_api_response_deck_listing_container.h" -#include "archidekt_deck_preview_image_display_widget.h" - -#include -#include -#include -#include -#include - -class BackgroundPlateWidget; - -/** - * @class ArchidektApiResponseDeckEntryDisplayWidget - * @brief Displays a single Archidekt deck listing as a preview card with metadata. - * - * This widget renders a deck entry received from an Archidekt API response. It includes: - * - A scaled deck preview image loaded asynchronously via QNetworkAccessManager. - * - Elided deck name in the top-left corner. - * - Deck size, EDH bracket, and view count labels. - * - A color distribution bar summarizing deck colors. - * - Metadata labels including owner, creation date, and last update date. - * - * The widget dynamically scales the preview image and labels according to a linked - * CardSizeWidget slider. Hovering over the widget highlights the background plate, - * and clicking emits a `requestNavigation` signal pointing to the deck URL. - * - * ### Features - * - Asynchronous image loading with fallback to a default placeholder image. - * - Maintains a fixed aspect ratio for the preview image (150:267). - * - Updates text elision dynamically when resized or scaled. - * - Integrates with FlowWidget containers for scrollable deck galleries. - * - * ### Signals - * - `requestNavigation(QString url)` — emitted when the widget is clicked to request - * navigation to the deck's Archidekt page. - * - * ### Slots - * - `actRequestNavigationToDeck()` — triggers navigation. - * - `setScaleFactor(int scale)` — adjusts preview image scaling. - */ -class ArchidektApiResponseDeckEntryDisplayWidget : public QWidget -{ - Q_OBJECT - -signals: - /** - * @brief Emitted when the user requests navigation. - * @param url Full URL to the Archidekt page. - */ - void requestNavigation(QString url); - -public: - /** - * @brief Constructs a deck entry display widget. - * @param parent Parent widget. - * @param response API container holding deck listing data. - * @param imageNetworkManager Shared network manager for fetching preview images. - */ - explicit ArchidektApiResponseDeckEntryDisplayWidget(QWidget *parent, - ArchidektApiResponseDeckListingContainer response, - QNetworkAccessManager *imageNetworkManager); - - /** - * @brief Handles finished network replies for preview images. - * @param reply QNetworkReply containing image data. - * - * Validates that the reply corresponds to this widget and updates the preview image. - */ - void onPreviewImageLoadFinished(QNetworkReply *reply); - - /** - * @brief Updates the scaled preview image and adjusts layout accordingly. - */ - void updateScaledPreview(); - - /** - * @brief Ensures layout responds correctly on resize events. - * @param event Resize event. - */ - void resizeEvent(QResizeEvent *event) override; - -public slots: - /** - * @brief Emits `requestNavigation` for the deck's URL. - */ - void actRequestNavigationToDeck(); - - /** - * @brief Sets a scaling factor (percentage) for the preview image. - * @param scale Scale percentage (100 = normal size). - */ - void setScaleFactor(int scale); - -protected: - void mousePressEvent(QMouseEvent *event) override; - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - void enterEvent(QEnterEvent *event) override; ///< Qt6 hover enter -#else - void enterEvent(QEvent *event) override; ///< Qt5 hover enter -#endif - void leaveEvent(QEvent *event) override; - -private: - QVBoxLayout *layout; ///< Main vertical layout - ArchidektApiResponseDeckListingContainer response; ///< Deck data - QUrl imageUrl; ///< URL of the deck's preview image - QNetworkAccessManager *imageNetworkManager; ///< Shared network manager - ArchidektDeckPreviewImageDisplayWidget *previewWidget; ///< Widget showing the deck preview - QLabel *picture; ///< QLabel displaying the scaled pixmap - QPixmap originalPixmap; ///< Original image for scaling (avoids degradation) - int scaleFactor = 100; ///< Current scaling percentage - BackgroundPlateWidget *backgroundPlateWidget; ///< Plate for metadata labels - static constexpr float DESIGN_RATIO = 150.0f / 267.0f; ///< Design aspect ratio -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_ENTRY_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp deleted file mode 100644 index 4d3dfd660..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "archidekt_api_response_deck_listings_display_widget.h" - -#include "../../../../cards/card_info_picture_with_text_overlay_widget.h" -#include "archidekt_api_response_deck_entry_display_widget.h" - -ArchidektApiResponseDeckListingsDisplayWidget::ArchidektApiResponseDeckListingsDisplayWidget( - QWidget *parent, - ArchidektDeckListingApiResponse response, - CardSizeWidget *_cardSizeSlider) - : QWidget(parent), cardSizeSlider(_cardSizeSlider) -{ - layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - setLayout(layout); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - - imageNetworkManager = new QNetworkAccessManager(this); - imageNetworkManager->setTransferTimeout(); // Use Qt's default timeout - imageNetworkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy); - - // Add widgets for deck listings - auto deckListings = response.results; - for (const auto &deckListing : deckListings) { - auto cardListDisplayWidget = - new ArchidektApiResponseDeckEntryDisplayWidget(this, deckListing, imageNetworkManager); - cardListDisplayWidget->setScaleFactor(cardSizeSlider->getSlider()->value()); - connect(cardListDisplayWidget, &ArchidektApiResponseDeckEntryDisplayWidget::requestNavigation, this, - &ArchidektApiResponseDeckListingsDisplayWidget::requestNavigation); - connect(cardSizeSlider->getSlider(), &QSlider::valueChanged, cardListDisplayWidget, - &ArchidektApiResponseDeckEntryDisplayWidget::setScaleFactor); - flowWidget->addWidget(cardListDisplayWidget); - } - - layout->addWidget(flowWidget); -} - -void ArchidektApiResponseDeckListingsDisplayWidget::append(const ArchidektDeckListingApiResponse &data) -{ - for (const auto &deckListing : data.results) { - auto cardListDisplayWidget = - new ArchidektApiResponseDeckEntryDisplayWidget(this, deckListing, imageNetworkManager); - cardListDisplayWidget->setScaleFactor(cardSizeSlider->getSlider()->value()); - connect(cardListDisplayWidget, &ArchidektApiResponseDeckEntryDisplayWidget::requestNavigation, this, - &ArchidektApiResponseDeckListingsDisplayWidget::requestNavigation); - connect(cardSizeSlider->getSlider(), &QSlider::valueChanged, cardListDisplayWidget, - &ArchidektApiResponseDeckEntryDisplayWidget::setScaleFactor); - flowWidget->addWidget(cardListDisplayWidget); - } -} - -void ArchidektApiResponseDeckListingsDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - layout->invalidate(); - layout->activate(); - layout->update(); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.h deleted file mode 100644 index 479de5fc8..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H -#define COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H - -#include "../../../../cards/card_size_widget.h" -#include "../../../../general/layout_containers/flow_widget.h" -#include "../api_response/archidekt_deck_listing_api_response.h" - -#include -#include -#include -#include -#include - -/** - * @class ArchidektApiResponseDeckListingsDisplayWidget - * @brief Displays a scrollable horizontal list of Archidekt deck listings with dynamic card sizing. - * - * This widget serves as a container for multiple - * ArchidektApiResponseDeckEntryDisplayWidget instances, each representing one deck listing - * returned from an Archidekt API call. - * - * ### Responsibilities - * - Creates a **FlowWidget** that arranges deck entries horizontally with wrapping. - * - Creates a shared **QNetworkAccessManager** for entry widgets to fetch card thumbnails. - * - Connects a **CardSizeWidget** slider to all deck entries to dynamically rescale their preview cards. - * - Propagates deck-navigation requests (`requestNavigation`) from children to the parent. - * - * ### Layout - * The widget uses a single `QHBoxLayout` containing the `FlowWidget`. - * The FlowWidget automatically manages child flow and scrollbar behavior (horizontal = off, - * vertical = auto), providing an efficient scrollable gallery of deck entries. - * - * ### API Integration - * The constructor consumes an `ArchidektDeckListingApiResponse`, iterates through its - * `results`, and instantiates a child entry widget for each deck. - * - * ### Signals - * - `requestNavigation(QString url)` — emitted whenever a child entry widget requests - * navigation to a deck or related Archidekt page. - * - * ### Performance Notes - * - All entry widgets share a single QNetworkAccessManager instance to reuse connections - * and avoid redundant session creation. - * - `resizeEvent()` forces layout invalidation to ensure the flow layout responds properly - * to container resizing. - */ -class ArchidektApiResponseDeckListingsDisplayWidget : public QWidget -{ - Q_OBJECT - -signals: - /** - * @brief Emitted when a child deck entry requests that the UI navigate to a particular URL. - * @param url The destination URL (typically an Archidekt deck page). - */ - void requestNavigation(QString url); - -public: - /** - * @brief Constructs a widget that displays multiple deck listing previews. - * - * @param parent Parent widget. - * @param response The Archidekt API response containing deck listings. - * @param cardSizeSlider A slider widget used to dynamically resize card previews. - * - * Each deck in `response.results` becomes its own - * ArchidektApiResponseDeckEntryDisplayWidget, added to the FlowWidget. - */ - explicit ArchidektApiResponseDeckListingsDisplayWidget(QWidget *parent, - ArchidektDeckListingApiResponse response, - CardSizeWidget *cardSizeSlider); - void append(const ArchidektDeckListingApiResponse &data); - - /** - * @brief Ensures FlowWidget layout properly recomputes on resize. - * - * Forces the layout to invalidate and activate itself so that the - * FlowWidget recalculates wrapping and child placement. - * - * @param event Resize event. - */ - void resizeEvent(QResizeEvent *event) override; - -private: - /// Slider controlling the scale of card thumbnails in all deck entry widgets. - CardSizeWidget *cardSizeSlider; - - /// Main horizontal layout containing the FlowWidget. - QHBoxLayout *layout; - - /// Container providing scrollable multi-row flow layout of deck entries. - FlowWidget *flowWidget; - - /// Shared network manager used to download card images for all child entry widgets. - QNetworkAccessManager *imageNetworkManager; -}; - -#endif // COCKATRICE_ARCHIDEKT_API_RESPONSE_DECK_LISTINGS_DISPLAY_WIDGET_H \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp deleted file mode 100644 index ced08491e..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "archidekt_deck_preview_image_display_widget.h" - -#include -#include - -ArchidektDeckPreviewImageDisplayWidget::ArchidektDeckPreviewImageDisplayWidget(QWidget *parent) : QWidget(parent) -{ - imageLabel = new QLabel(this); - imageLabel->setAlignment(Qt::AlignCenter); - - topLeftLabel = new ShadowBackgroundLabel(this, ""); - topRightLabel = new ShadowBackgroundLabel(this, ""); - bottomLeftLabel = new ShadowBackgroundLabel(this, ""); - bottomRightLabel = new ShadowBackgroundLabel(this, ""); - - QFont f; - f.setBold(true); - f.setPointSize(16); - topLeftLabel->setFont(f); - topRightLabel->setFont(f); - bottomLeftLabel->setFont(f); - bottomRightLabel->setFont(f); - - // Raise so labels appear above image - topLeftLabel->raise(); - topRightLabel->raise(); - bottomLeftLabel->raise(); - bottomRightLabel->raise(); -} - -void ArchidektDeckPreviewImageDisplayWidget::setAspectRatio(float ratio) -{ - aspectRatio = ratio; -} - -void ArchidektDeckPreviewImageDisplayWidget::setPreviewWidth(int width) -{ - int height = int(width * aspectRatio); - - setFixedSize(width, height); - updateGeometry(); - update(); -} - -void ArchidektDeckPreviewImageDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - - // Full size for the image - imageLabel->setGeometry(rect()); - - topLeftLabel->adjustSize(); - topRightLabel->adjustSize(); - bottomLeftLabel->adjustSize(); - bottomRightLabel->adjustSize(); - - // Padding settings - const int horizontalPadding = 8; - const int topPadding = 6; - const int bottomPadding = 6; - - // Left-aligned, top-aligned (Deck Name) - topLeftLabel->move(horizontalPadding, topPadding); - - // Right-aligned, top-aligned (Card Count) - topRightLabel->move(width() - topRightLabel->width() - horizontalPadding, topPadding); - - // Bottom-left, bottom-aligned (EDH bracket) - bottomLeftLabel->move(horizontalPadding, height() - bottomLeftLabel->height() - bottomPadding); - - // Bottom-right, bottom-aligned (views) - bottomRightLabel->move(width() - bottomRightLabel->width() - horizontalPadding, - height() - bottomRightLabel->height() - bottomPadding); - - // Ensure labels stay above image - topLeftLabel->raise(); - topRightLabel->raise(); - bottomLeftLabel->raise(); - bottomRightLabel->raise(); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h deleted file mode 100644 index 053823c45..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef COCKATRICE_ARCHIDEKT_DECK_PREVIEW_IMAGE_DISPLAY_WIDGET_H -#define COCKATRICE_ARCHIDEKT_DECK_PREVIEW_IMAGE_DISPLAY_WIDGET_H - -#include "../../../../general/display/shadow_background_label.h" - -#include -#include - -/** - * @class ArchidektDeckPreviewImageDisplayWidget - * @brief Widget for displaying a deck preview image with overlaid metadata labels. - * - * This widget shows a deck's preview image along with several overlay labels: - * - Top-left: Deck name. - * - Top-right: Card count. - * - Bottom-left: EDH bracket (if applicable). - * - Bottom-right: View count. - * - * Labels automatically scale and position themselves relative to the widget's size. - * The image can be scaled while maintaining a specified aspect ratio. - * - * ### Features - * - Adjustable preview width and aspect ratio. - * - Labels automatically repositioned on resize. - * - Supports overlaying multiple pieces of metadata with shadowed labels for readability. - */ -class ArchidektDeckPreviewImageDisplayWidget : public QWidget -{ - Q_OBJECT -public: - /** - * @brief Constructs the deck preview display widget. - * @param parent Optional parent widget. - */ - explicit ArchidektDeckPreviewImageDisplayWidget(QWidget *parent = nullptr); - - /** - * @brief Sets the aspect ratio for the preview image (height / width). - * @param ratio Aspect ratio to maintain. - */ - void setAspectRatio(float ratio); - - /** - * @brief Sets the width of the preview image; height is adjusted according to the aspect ratio. - * @param width Desired width in pixels. - */ - void setPreviewWidth(int width); - - QLabel *imageLabel; ///< QLabel to display the deck image - ShadowBackgroundLabel *topLeftLabel; ///< Overlay label at top-left (deck name) - ShadowBackgroundLabel *topRightLabel; ///< Overlay label at top-right (card count) - ShadowBackgroundLabel *bottomLeftLabel; ///< Overlay label at bottom-left (EDH bracket) - ShadowBackgroundLabel *bottomRightLabel; ///< Overlay label at bottom-right (views) - -protected: - /** - * @brief Handles resize events to reposition the image and overlay labels. - * @param event Resize event. - */ - void resizeEvent(QResizeEvent *event) override; - -private: - float aspectRatio = 1.0f; ///< Aspect ratio to maintain for the preview image -}; - -#endif // COCKATRICE_ARCHIDEKT_DECK_PREVIEW_IMAGE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp deleted file mode 100644 index 352d55c79..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp +++ /dev/null @@ -1,669 +0,0 @@ -#include "tab_archidekt.h" - -#include "../../../../../client/settings/cache_settings.h" -#include "../../../cards/additional_info/mana_symbol_widget.h" -#include "../../tab_supervisor.h" -#include "api_response/archidekt_deck_listing_api_response.h" -#include "display/archidekt_api_response_deck_display_widget.h" -#include "display/archidekt_api_response_deck_listings_display_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -TabArchidekt::TabArchidekt(TabSupervisor *_tabSupervisor) - : Tab(_tabSupervisor), currentPage(1), isLoadingMore(false), isListMode(true) -{ - // Initialize network - networkManager = new QNetworkAccessManager(this); - networkManager->setTransferTimeout(); - networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy); - connect(networkManager, &QNetworkAccessManager::finished, this, &TabArchidekt::processApiJson); - - // Initialize debounce timer - searchDebounceTimer = new QTimer(this); - searchDebounceTimer->setSingleShot(true); - searchDebounceTimer->setInterval(300); - connect(searchDebounceTimer, &QTimer::timeout, this, &TabArchidekt::doSearchImmediate); - - initializeUi(); - setupFilterWidgets(); - connectSignals(); - retranslateUi(); - - getTopDecks(); -} - -void TabArchidekt::initializeUi() -{ - // Main container - container = new QWidget(this); - mainLayout = new QVBoxLayout(container); - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->setSpacing(0); - - // Primary toolbar (most important filters) - primaryToolbar = new QWidget(container); - primaryToolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - primaryToolbarLayout = new QHBoxLayout(primaryToolbar); - primaryToolbarLayout->setContentsMargins(6, 6, 6, 6); - primaryToolbarLayout->setSpacing(6); - - // Sort controls - sortByLabel = new QLabel(primaryToolbar); - orderByCombo = new QComboBox(primaryToolbar); - orderByCombo->addItems({"name", "updatedAt", "createdAt", "viewCount", "size", "edhBracket"}); - orderByCombo->setCurrentText("updatedAt"); - orderByCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); - - orderDirButton = new QPushButton(tr("Desc."), primaryToolbar); - orderDirButton->setCheckable(true); - orderDirButton->setChecked(true); - orderDirButton->setFixedWidth(60); - - // Color filter (inline) - QWidget *colorWidget = new QWidget(primaryToolbar); - QHBoxLayout *colorLayout = new QHBoxLayout(colorWidget); - colorLayout->setContentsMargins(0, 0, 0, 0); - colorLayout->setSpacing(2); - - QString colorIdentity = "WUBRG"; - for (const QChar &color : colorIdentity) { - auto *manaSymbol = new ManaSymbolWidget(colorWidget, color, false, true); - manaSymbol->setFixedSize(28, 28); - colorSymbols.append(manaSymbol); - colorLayout->addWidget(manaSymbol); - - connect(manaSymbol, &ManaSymbolWidget::colorToggled, this, [this](QChar c, bool active) { - if (active) - activeColors.insert(c); - else - activeColors.remove(c); - doSearch(); - }); - } - - logicalAndCheck = new QCheckBox(tr("AND"), primaryToolbar); - logicalAndCheck->setToolTip(tr("Require ALL selected colors")); - - // Common search fields - nameField = new QLineEdit(primaryToolbar); - nameField->setPlaceholderText(tr("Deck name...")); - nameField->setMinimumWidth(150); - - ownerField = new QLineEdit(primaryToolbar); - ownerField->setPlaceholderText(tr("Owner...")); - ownerField->setMinimumWidth(120); - - // Filter by label - filterByLabel = new QLabel(primaryToolbar); - - // Package toggle - packagesCheck = new QCheckBox(tr("Packages"), primaryToolbar); - - // Search button - searchButton = new QPushButton(tr("Search"), primaryToolbar); - searchButton->setDefault(true); - - // Advanced filters toggle button - advancedFiltersButton = new QPushButton(tr("Advanced Filters"), primaryToolbar); - advancedFiltersButton->setCheckable(true); - advancedFiltersButton->setChecked(false); - - // Settings - settingsButton = new SettingsButtonWidget(primaryToolbar); - cardSizeSlider = new CardSizeWidget(primaryToolbar, nullptr, SettingsCache::instance().getArchidektPreviewSize()); - settingsButton->addSettingsWidget(cardSizeSlider); - - // Assemble primary toolbar - primaryToolbarLayout->addWidget(sortByLabel); - primaryToolbarLayout->addWidget(orderByCombo); - primaryToolbarLayout->addWidget(orderDirButton); - - // Add separator/spacing - primaryToolbarLayout->addSpacing(12); - - primaryToolbarLayout->addWidget(filterByLabel); - primaryToolbarLayout->addWidget(colorWidget); - primaryToolbarLayout->addWidget(logicalAndCheck); - primaryToolbarLayout->addWidget(nameField, 1); - primaryToolbarLayout->addWidget(ownerField, 1); - primaryToolbarLayout->addWidget(packagesCheck); - primaryToolbarLayout->addWidget(searchButton, 1); - primaryToolbarLayout->addWidget(advancedFiltersButton); - primaryToolbarLayout->addWidget(settingsButton); - - // Secondary toolbar (advanced filters - initially hidden) - secondaryToolbar = new QWidget(container); - secondaryToolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - secondaryToolbar->setVisible(false); // Start hidden - secondaryToolbarLayout = new QHBoxLayout(secondaryToolbar); - secondaryToolbarLayout->setContentsMargins(6, 3, 6, 6); - secondaryToolbarLayout->setSpacing(6); - - // Scrollable results area - scrollArea = new QScrollArea(container); - scrollArea->setWidgetResizable(true); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - - resultsContainer = new QWidget(); - resultsLayout = new QVBoxLayout(resultsContainer); - resultsLayout->setContentsMargins(0, 0, 0, 0); - resultsLayout->setSpacing(0); - - scrollArea->setWidget(resultsContainer); - - scrollArea->viewport()->installEventFilter(this); - - mainLayout->addWidget(primaryToolbar); - mainLayout->addWidget(secondaryToolbar); - mainLayout->addWidget(scrollArea); - - setCentralWidget(container); -} - -bool TabArchidekt::eventFilter(QObject *obj, QEvent *event) -{ - if (obj == scrollArea->viewport() && event->type() == QEvent::Wheel) { - auto *wheelEvent = static_cast(event); - - if (wheelEvent->angleDelta().y() < 0 && !isLoadingMore && isListMode) { - loadNextPage(); - wheelEvent->accept(); - return false; // allow scrolling - } - } - - // Always pass the event to the parent to handle normal scrolling - return QWidget::eventFilter(obj, event); -} - -void TabArchidekt::setupFilterWidgets() -{ - // Advanced filters (in secondary toolbar) - - // EDH Bracket - auto *bracketLabel = new QLabel(tr("Bracket:"), secondaryToolbar); - edhBracketCombo = new QComboBox(secondaryToolbar); - edhBracketCombo->addItem(tr("Any")); - edhBracketCombo->addItems({"1", "2", "3", "4", "5"}); - edhBracketCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); - - // Format filter (collapsible) - formatButton = new SettingsButtonWidget(secondaryToolbar); - formatButton->setButtonText(tr("Formats")); - formatButton->setButtonIcon(QPixmap("theme:icons/scale_balanced")); - - QWidget *formatContainer = new QWidget(secondaryToolbar); - QGridLayout *formatLayout = new QGridLayout(formatContainer); - formatLayout->setContentsMargins(4, 4, 4, 4); - - QStringList formatNames = {"Standard", "Modern", "Commander", "Legacy", "Vintage", - "Pauper", "Custom", "Frontier", "Future Std", "Penny Dreadful", - "1v1 Commander", "Dual Commander", "Brawl"}; - - int row = 0, col = 0; - for (const QString &formatName : formatNames) { - auto *formatCheckBox = new QCheckBox(formatName, formatContainer); - formatChecks << formatCheckBox; - formatLayout->addWidget(formatCheckBox, row, col); - connect(formatCheckBox, &QCheckBox::clicked, this, &TabArchidekt::doSearch); - - col++; - if (col >= 3) { - col = 0; - row++; - } - } - - formatButton->addSettingsWidget(formatContainer); - - cardsField = new QLineEdit(secondaryToolbar); - cardsField->setPlaceholderText(tr("Contains card...")); - cardsField->setMinimumWidth(140); - - commandersField = new QLineEdit(secondaryToolbar); - commandersField->setPlaceholderText(tr("Commander...")); - commandersField->setMinimumWidth(140); - - deckTagNameField = new QLineEdit(secondaryToolbar); - deckTagNameField->setPlaceholderText(tr("Tag...")); - deckTagNameField->setMinimumWidth(100); - - // Deck size filter (collapsible) - deckSizeButton = new SettingsButtonWidget(secondaryToolbar); - deckSizeButton->setButtonText(tr("Deck Size")); - - QWidget *sizeContainer = new QWidget(secondaryToolbar); - QHBoxLayout *sizeLayout = new QHBoxLayout(sizeContainer); - sizeLayout->setContentsMargins(4, 4, 4, 4); - - minDeckSizeSpin = new QSpinBox(sizeContainer); - minDeckSizeSpin->setSpecialValueText(tr("Any")); - minDeckSizeSpin->setRange(0, 200); - minDeckSizeSpin->setValue(0); - - minDeckSizeLogicCombo = new QComboBox(sizeContainer); - minDeckSizeLogicCombo->addItems({"Exact", "≥", "≤"}); - minDeckSizeLogicCombo->setCurrentIndex(1); - - sizeLayout->addWidget(new QLabel(tr("Cards:"), sizeContainer)); - sizeLayout->addWidget(minDeckSizeSpin); - sizeLayout->addWidget(minDeckSizeLogicCombo); - - deckSizeButton->addSettingsWidget(sizeContainer); - - // Setup card name autocomplete - auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this); - auto displayModel = new CardDatabaseDisplayModel(this); - displayModel->setSourceModel(cardDatabaseModel); - auto *searchModel = new CardSearchModel(displayModel, this); - - auto *proxyModel = new CardCompleterProxyModel(this); - proxyModel->setSourceModel(searchModel); - proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - proxyModel->setFilterRole(Qt::DisplayRole); - - auto *completer = new QCompleter(proxyModel, this); - completer->setCompletionRole(Qt::DisplayRole); - completer->setCompletionMode(QCompleter::PopupCompletion); - completer->setCaseSensitivity(Qt::CaseInsensitive); - completer->setFilterMode(Qt::MatchContains); - completer->setMaxVisibleItems(10); - - cardsField->setCompleter(completer); - commandersField->setCompleter(completer); - - // Keep autocomplete working for both fields - connect(cardsField, &QLineEdit::textChanged, this, [=](const QString &text) { - searchModel->updateSearchResults(text); - QString pattern = ".*" + QRegularExpression::escape(text) + ".*"; - proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); - if (!text.isEmpty()) - completer->complete(); - }); - - connect(commandersField, &QLineEdit::textChanged, this, [=](const QString &text) { - searchModel->updateSearchResults(text); - QString pattern = ".*" + QRegularExpression::escape(text) + ".*"; - proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); - if (!text.isEmpty()) - completer->complete(); - }); - - // Assemble secondary toolbar - secondaryToolbarLayout->addWidget(bracketLabel); - secondaryToolbarLayout->addWidget(edhBracketCombo); - secondaryToolbarLayout->addWidget(formatButton); - secondaryToolbarLayout->addWidget(cardsField); - secondaryToolbarLayout->addWidget(commandersField); - secondaryToolbarLayout->addWidget(deckTagNameField); - secondaryToolbarLayout->addWidget(deckSizeButton); - secondaryToolbarLayout->addStretch(); -} - -void TabArchidekt::connectSignals() -{ - // Advanced filters toggle - connect(advancedFiltersButton, &QPushButton::clicked, this, - [this](bool checked) { secondaryToolbar->setVisible(checked); }); - - // These trigger immediate search (no debounce needed) - connect(orderByCombo, &QComboBox::currentTextChanged, this, &TabArchidekt::doSearch); - connect(orderDirButton, &QPushButton::clicked, [this](bool checked) { - orderDirButton->setText(checked ? tr("Desc.") : tr("Asc.")); - doSearch(); - }); - - connect(cardSizeSlider, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(), - &SettingsCache::setArchidektPreviewCardSize); - - // Search button triggers immediate search - connect(searchButton, &QPushButton::clicked, this, &TabArchidekt::doSearchImmediate); - - // These trigger search (but not text fields) - connect(logicalAndCheck, &QCheckBox::clicked, this, &TabArchidekt::doSearch); - connect(packagesCheck, &QCheckBox::clicked, [this]() { - updatePackageModeState(packagesCheck->isChecked()); - doSearch(); - }); - - // Format filters trigger search - connect(edhBracketCombo, &QComboBox::currentTextChanged, this, &TabArchidekt::doSearch); - connect(minDeckSizeSpin, qOverload(&QSpinBox::valueChanged), this, &TabArchidekt::doSearch); - connect(minDeckSizeLogicCombo, &QComboBox::currentTextChanged, this, &TabArchidekt::doSearch); - - // Allow Enter key in text fields to trigger search - connect(nameField, &QLineEdit::returnPressed, this, &TabArchidekt::doSearchImmediate); - connect(ownerField, &QLineEdit::returnPressed, this, &TabArchidekt::doSearchImmediate); - connect(cardsField, &QLineEdit::returnPressed, this, &TabArchidekt::doSearchImmediate); - connect(commandersField, &QLineEdit::returnPressed, this, &TabArchidekt::doSearchImmediate); - connect(deckTagNameField, &QLineEdit::returnPressed, this, &TabArchidekt::doSearchImmediate); - - // Format checkboxes trigger search - for (auto *formatCheck : formatChecks) { - connect(formatCheck, &QCheckBox::clicked, this, &TabArchidekt::doSearch); - } -} - -void TabArchidekt::updatePackageModeState(bool isPackageMode) -{ - // Disable format-specific and commander-specific filters in package mode - for (auto *cb : formatChecks) { - cb->setEnabled(!isPackageMode); - } - - edhBracketCombo->setEnabled(!isPackageMode); - if (isPackageMode) { - edhBracketCombo->setCurrentIndex(0); - } - - commandersField->setEnabled(!isPackageMode); - deckTagNameField->setEnabled(!isPackageMode); -} - -void TabArchidekt::retranslateUi() -{ - sortByLabel->setText(tr("Sort by:")); - orderDirButton->setText(orderDirButton->isChecked() ? tr("Desc.") : tr("Asc.")); - - filterByLabel->setText(tr("Filter by:")); - - logicalAndCheck->setText(tr("AND")); - logicalAndCheck->setToolTip(tr("Require ALL selected colors")); - - nameField->setPlaceholderText(tr("Deck name...")); - ownerField->setPlaceholderText(tr("Owner...")); - packagesCheck->setText(tr("Packages")); - advancedFiltersButton->setText(tr("Advanced Filters")); - - cardsField->setPlaceholderText(tr("Contains card...")); - commandersField->setPlaceholderText(tr("Commander...")); - deckTagNameField->setPlaceholderText(tr("Tag...")); - - formatButton->setButtonText(tr("Formats")); - deckSizeButton->setButtonText(tr("Deck Size")); - - searchButton->setText(tr("Search")); - - settingsButton->setToolTip(tr("Display Settings")); -} - -QString TabArchidekt::buildSearchUrl() -{ - QUrlQuery query; - - // orderBy (field + direction) - QString field = orderByCombo->currentText(); - if (!field.isEmpty()) { - bool desc = orderDirButton->isChecked(); - QString final = desc ? "-" + field : field; - query.addQueryItem("orderBy", final); - } - - // Colors - QStringList selectedColors; - for (QChar c : activeColors) { - selectedColors.append(c); - } - if (!selectedColors.isEmpty()) { - query.addQueryItem("colors", selectedColors.join(",")); - } - - // logicalAnd - if (logicalAndCheck->isChecked()) { - query.addQueryItem("logicalAnd", "true"); - } - - // Formats (disabled in package mode) - if (!packagesCheck->isChecked()) { - QStringList formatIds; - for (int i = 0; i < formatChecks.size(); ++i) { - if (formatChecks[i]->isChecked()) { - formatIds << QString::number(i + 1); - } - } - - if (!formatIds.isEmpty()) { - query.addQueryItem("deckFormat", formatIds.join(",")); - } - - // edhBracket - if (edhBracketCombo->currentIndex() > 0) { - query.addQueryItem("edhBracket", edhBracketCombo->currentText()); - } - } - - // Package mode - if (packagesCheck->isChecked()) { - query.addQueryItem("packages", "true"); - } - - // Name - if (!nameField->text().isEmpty()) { - query.addQueryItem("name", nameField->text()); - } - - // Owner - if (!ownerField->text().isEmpty()) { - query.addQueryItem("ownerUsername", ownerField->text()); - } - - // Cards - if (!cardsField->text().isEmpty()) { - query.addQueryItem("cards", cardsField->text()); - } - - // Commander (disabled in package mode) - if (!packagesCheck->isChecked() && !commandersField->text().isEmpty()) { - query.addQueryItem("commanderName", commandersField->text()); - } - - // Deck tag (disabled in package mode) - if (!packagesCheck->isChecked() && !deckTagNameField->text().isEmpty()) { - query.addQueryItem("deckTagName", deckTagNameField->text()); - } - - // Page number (for infinite scroll) - query.addQueryItem("page", QString::number(currentPage)); - - // Min deck size - if (minDeckSizeSpin->value() != 0) { - query.addQueryItem("size", QString::number(minDeckSizeSpin->value())); - - QString logic = "GTE"; - QString selected = minDeckSizeLogicCombo->currentText(); - if (selected == "≥") - logic = "GTE"; - else if (selected == "≤") - logic = "LTE"; - else - logic = ""; - - if (!logic.isEmpty()) { - query.addQueryItem("sizeLogic", logic); - } - } - - QUrl url("https://archidekt.com/api/decks/v3/"); - url.setQuery(query); - - return url.toString(); -} - -void TabArchidekt::doSearch() -{ - // Reset to first page on new search - currentPage = 1; - // We're searching, so we'll be in list mode - isListMode = true; - // Don't debounce - only called by explicit user actions now - doSearchImmediate(); -} - -void TabArchidekt::doSearchImmediate() -{ - QString url = buildSearchUrl(); - QNetworkRequest req{QUrl(url)}; - req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - networkManager->get(req); -} - -void TabArchidekt::loadNextPage() -{ - if (isLoadingMore) { - return; - } - - isLoadingMore = true; - currentPage++; - - QString url = buildSearchUrl(); - QNetworkRequest req{QUrl(url)}; - req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - networkManager->get(req); -} - -void TabArchidekt::actNavigatePage(QString url) -{ - QNetworkRequest request{QUrl(url)}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - networkManager->get(request); -} - -void TabArchidekt::getTopDecks() -{ - currentPage = 1; - QNetworkRequest request{QUrl(buildSearchUrl())}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - networkManager->get(request); -} - -void TabArchidekt::processApiJson(QNetworkReply *reply) -{ - if (reply->error() != QNetworkReply::NoError) { - isLoadingMore = false; - reply->deleteLater(); - return; - } - - QByteArray responseData = reply->readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData); - - if (!jsonDoc.isObject()) { - isLoadingMore = false; - reply->deleteLater(); - return; - } - - QJsonObject jsonObj = jsonDoc.object(); - QString responseUrl = reply->url().toString(); - - if (responseUrl.startsWith("https://archidekt.com/api/decks/v3/")) { - processTopDecksResponse(jsonObj); - } else if (responseUrl.startsWith("https://archidekt.com/api/decks/")) { - processDeckResponse(jsonObj); - } else { - prettyPrintJson(jsonObj, 4); - } - - isLoadingMore = false; - reply->deleteLater(); -} - -void TabArchidekt::processTopDecksResponse(QJsonObject reply) -{ - ArchidektDeckListingApiResponse deckData; - deckData.fromJson(reply); - - // New search → clear everything - if (currentPage == 1) { - QLayoutItem *item; - while ((item = resultsLayout->takeAt(0)) != nullptr) { - delete item->widget(); - delete item; - } - - listingsWidget = new ArchidektApiResponseDeckListingsDisplayWidget(resultsContainer, deckData, cardSizeSlider); - - connect(listingsWidget, &ArchidektApiResponseDeckListingsDisplayWidget::requestNavigation, this, - &TabArchidekt::actNavigatePage); - - resultsLayout->addWidget(listingsWidget); - return; - } - - // Infinite scroll → append - if (listingsWidget) { - listingsWidget->append(deckData); - } -} - -void TabArchidekt::processDeckResponse(QJsonObject reply) -{ - ArchidektApiResponseDeck deckData; - deckData.fromJson(reply); - - // We're in single deck mode - disable infinite scroll - isListMode = false; - - // Clear existing results for single deck view - QLayoutItem *item; - while ((item = resultsLayout->takeAt(0)) != nullptr) { - delete item->widget(); - delete item; - } - - auto display = new ArchidektApiResponseDeckDisplayWidget(resultsContainer, deckData, cardSizeSlider); - connect(display, &ArchidektApiResponseDeckDisplayWidget::requestNavigation, this, &TabArchidekt::actNavigatePage); - connect(display, &ArchidektApiResponseDeckDisplayWidget::requestSearch, this, &TabArchidekt::doSearchImmediate); - connect(display, &ArchidektApiResponseDeckDisplayWidget::openInDeckEditor, tabSupervisor, - &TabSupervisor::openDeckInNewTab); - resultsLayout->addWidget(display); -} - -void TabArchidekt::prettyPrintJson(const QJsonValue &value, int indentLevel) -{ - const QString indent(indentLevel * 2, ' '); - - if (value.isObject()) { - QJsonObject obj = value.toObject(); - for (auto it = obj.begin(); it != obj.end(); ++it) { - qInfo().noquote() << indent + it.key() + ":"; - prettyPrintJson(it.value(), indentLevel + 1); - } - } else if (value.isArray()) { - QJsonArray array = value.toArray(); - for (int i = 0; i < array.size(); ++i) { - qInfo().noquote() << indent + QString("[%1]:").arg(i); - prettyPrintJson(array[i], indentLevel + 1); - } - } else if (value.isString()) { - qInfo().noquote() << indent + "\"" + value.toString() + "\""; - } else if (value.isDouble()) { - qInfo().noquote() << indent + QString::number(value.toDouble()); - } else if (value.isBool()) { - qInfo().noquote() << indent + (value.toBool() ? "true" : "false"); - } else if (value.isNull()) { - qInfo().noquote() << indent + "null"; - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.h deleted file mode 100644 index e837e672b..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/archidekt/tab_archidekt.h +++ /dev/null @@ -1,294 +0,0 @@ -#ifndef COCKATRICE_TAB_ARCHIDEKT_H -#define COCKATRICE_TAB_ARCHIDEKT_H - -#include "../../interface/widgets/cards/card_size_widget.h" -#include "../../interface/widgets/quick_settings/settings_button_widget.h" -#include "../../tab.h" -#include "display/archidekt_api_response_deck_listings_display_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** Base API link for Archidekt deck search */ -inline QString archidektApiLink = "https://archidekt.com/api/decks/v3/?name="; - -class ManaSymbolWidget; - -/** - * @brief Tab for browsing, searching, and filtering Archidekt decks. - * - * This class provides a comprehensive interface for querying decks from the Archidekt API. - * Users can filter decks by name, owner, included cards, commanders, deck tags, colors, EDH bracket, - * and formats. It supports infinite scroll pagination for seamless browsing. - */ -class TabArchidekt : public Tab -{ - Q_OBJECT -public: - /** - * @brief Construct a new TabArchidekt object - * @param _tabSupervisor Parent tab supervisor responsible for tab management and callbacks - * - * Initializes the network manager, creates all UI components, sets up layouts, - * connects signals and slots, and triggers an initial fetch of top decks. - */ - explicit TabArchidekt(TabSupervisor *_tabSupervisor); - - /** - * @brief Update all UI text to reflect the current language or translation - * - * This function re-applies translations to all labels, buttons, and placeholders. - * It should be called after a language change. - */ - void retranslateUi() override; - - /** - * @brief Construct the search URL from all current filters - * @return QString Fully constructed URL including all query parameters - * - * The search URL is dynamically built using the state of all filter widgets. - * Parameters included: - * - Deck name - * - Owner - * - Included cards - * - Commander cards - * - Deck tag - * - Colors and logical AND requirement - * - Formats - * - EDH bracket - * - Packages toggle - * - Sorting field and direction - * - Minimum amount of cards in the deck - * - Current page (for infinite scroll) - */ - QString buildSearchUrl(); - - /** - * @brief Retrieve the tab display text - * @return QString Human-readable title for the tab - * - * If a card is pre-selected (cardToQuery), its name is appended to the tab title. - */ - QString getTabText() const override - { - auto cardName = cardToQuery.isNull() ? QString() : cardToQuery->getName(); - return tr("Archidekt: ") + cardName; - } - - /** - * @brief Get the card size slider widget - * @return CardSizeWidget* Pointer to the card size adjustment slider - * - * Allows external code to read or manipulate the current card size or hook up the sliders signals. - */ - CardSizeWidget *getCardSizeSlider() - { - return cardSizeSlider; - } - -public slots: - /** - * @brief Trigger a debounced search using the current filters - * - * Resets to page 1 and starts the debounce timer. The actual search will execute - * after 300ms of inactivity. - */ - void doSearch(); - - /** - * @brief Immediately trigger a search using the current filters - * - * Sends a network request to the Archidekt API using the URL generated by buildSearchUrl(). - * Updates the results display asynchronously. - */ - void doSearchImmediate(); - - /** - * @brief Load the next page of results for infinite scroll - * - * Increments the current page and fetches additional results, which are appended - * to the existing results display. - */ - void loadNextPage(); - - /** - * @brief Process a network reply containing JSON data - * @param reply QNetworkReply object with the API response - * - * Determines whether the response corresponds to a deck listing or a single deck, - * and dispatches it to the appropriate handler. - */ - void processApiJson(QNetworkReply *reply); - - /** - * @brief Handle a JSON response containing multiple decks - * @param reply QJsonObject containing deck listings - * - * If this is page 1, clears previous results. Appends new results to the display. - */ - void processTopDecksResponse(QJsonObject reply); - - /** - * @brief Handle a JSON response for a single deck - * @param reply QJsonObject containing deck data - * - * Clears the results area and displays the single deck details. - */ - void processDeckResponse(QJsonObject reply); - - /** - * @brief Pretty-print a QJsonValue for debugging - * @param value The JSON value to print - * @param indentLevel The indentation depth (number of levels) - */ - void prettyPrintJson(const QJsonValue &value, int indentLevel); - - /** - * @brief Navigate to a specified page URL - * @param url The URL to request - * - * Typically called when a deck card is clicked in the listing. - */ - void actNavigatePage(QString url); - - /** - * @brief Fetch top decks from the Archidekt API - * - * Called on initialization to populate the initial results display. - */ - void getTopDecks(); - -protected: - /** - * @brief Event filter to catch wheel events for infinite scroll - * @param obj The object that received the event - * @param event The event to filter - * @return bool Whether the event was handled - */ - bool eventFilter(QObject *obj, QEvent *event) override; - -private: - /** - * @brief Initialize the main UI layout and toolbars - * - * Creates the container, main layout, primary toolbar (sort, colors, name, owner, packages), - * secondary toolbar (advanced filters), and scrollable results area. - */ - void initializeUi(); - - /** - * @brief Set up all filter widgets - * - * Creates filter widgets for: - * - Card search with autocomplete - * - Commander search with autocomplete - * - Deck tags - * - Format selection (collapsible) - * - Deck size filter (collapsible) - */ - void setupFilterWidgets(); - - /** - * @brief Connect all signals and slots for UI interactions - * - * Links all widget signals to their appropriate handlers, including - * search triggers, filter changes, package mode toggling, and infinite scroll. - */ - void connectSignals(); - - /** - * @brief Update UI state when package mode is toggled - * @param isPackageMode Whether package mode is currently enabled - * - * Disables format-specific and commander-specific filters when searching - * for card packages instead of full decks. - */ - void updatePackageModeState(bool isPackageMode); - - // --------------------------------------------------------------------- - // Network & Timing - // --------------------------------------------------------------------- - - QNetworkAccessManager *networkManager; ///< Network manager for handling API requests - QTimer *searchDebounceTimer; ///< Timer to debounce search requests - int currentPage; ///< Current page number for infinite scroll - bool isLoadingMore; ///< Flag to prevent multiple simultaneous page loads - bool isListMode; - ArchidektApiResponseDeckListingsDisplayWidget *listingsWidget = nullptr; - - // --------------------------------------------------------------------- - // Layout Containers - // --------------------------------------------------------------------- - - QWidget *container; ///< Root container for the entire tab - QVBoxLayout *mainLayout; ///< Outer vertical layout containing toolbars and results - - QWidget *primaryToolbar; ///< Primary toolbar with most important filters - QHBoxLayout *primaryToolbarLayout; ///< Layout for primary toolbar - - QWidget *secondaryToolbar; ///< Secondary toolbar with advanced filters - QHBoxLayout *secondaryToolbarLayout; ///< Layout for secondary toolbar - - QScrollArea *scrollArea; ///< Scrollable area for results (enables infinite scroll) - QWidget *resultsContainer; ///< Container widget inside scroll area - QVBoxLayout *resultsLayout; ///< Layout for results (decks appended here) - - // --------------------------------------------------------------------- - // Primary Toolbar Controls (Most Important) - // --------------------------------------------------------------------- - - QLabel *sortByLabel; ///< Label for sort controls - QComboBox *orderByCombo; ///< Dropdown for selecting the sort field - QPushButton *orderDirButton; ///< Toggle button for ascending/descending sort - - QLabel *filterByLabel; ///< Label for filter controls - QList colorSymbols; ///< Mana symbol toggle buttons - QSet activeColors; ///< Set of currently active mana colors - QCheckBox *logicalAndCheck; ///< Require ALL selected colors instead of ANY - - QLineEdit *nameField; ///< Input for deck name filter - QLineEdit *ownerField; ///< Input for owner name filter - QCheckBox *packagesCheck; ///< Toggle for searching card packages instead of full decks - QPushButton *searchButton; ///< Button to trigger search - QPushButton *advancedFiltersButton; ///< Button to show/hide advanced filters - - SettingsButtonWidget *settingsButton; ///< Container for card size settings - CardSizeWidget *cardSizeSlider; ///< Slider to adjust card size in results - - // --------------------------------------------------------------------- - // Secondary Toolbar Controls (Advanced Filters) - // --------------------------------------------------------------------- - - QLineEdit *cardsField; ///< Input for cards included in the deck - QLineEdit *commandersField; ///< Input for commander cards - QLineEdit *deckTagNameField; ///< Input for deck tag filtering - - SettingsButtonWidget *formatButton; ///< Collapsible button for format filters - QVector formatChecks; ///< Individual checkboxes for each format - QComboBox *edhBracketCombo; ///< Dropdown for EDH bracket selection - - SettingsButtonWidget *deckSizeButton; ///< Collapsible button for deck size filter - QSpinBox *minDeckSizeSpin; ///< Spinner to select minimum deck size - QComboBox *minDeckSizeLogicCombo; ///< Combo box for size comparison logic - - // --------------------------------------------------------------------- - // Optional Context - // --------------------------------------------------------------------- - - CardInfoPtr cardToQuery; ///< Optional pre-selected card for initial filtering -}; - -#endif // COCKATRICE_TAB_ARCHIDEKT_H \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp deleted file mode 100644 index 145a3fca0..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "edhrec_api_response_archidekt_links.h" - -#include -#include -#include - -void EdhrecApiResponseArchidektLink::fromJson(const QJsonObject &json) -{ - c = json.value("c").toString(); - f = json.value("f").toInt(0); - q = json.value("q").toInt(0); - u = json.value("u").toString(); -} - -void EdhrecApiResponseArchidektLink::debugPrint() const -{ - qDebug() << " C:" << c; - qDebug() << " F:" << f; - qDebug() << " Q:" << q; - qDebug() << " U:" << u; -} - -void EdhrecCommanderApiResponseArchidektLinks::fromJson(const QJsonArray &json) -{ - entries.clear(); - for (const QJsonValue &value : json) { - if (value.isObject()) { - QJsonObject entryJson = value.toObject(); - EdhrecApiResponseArchidektLink entry; - entry.fromJson(entryJson); - entries.append(entry); - } - } -} - -void EdhrecCommanderApiResponseArchidektLinks::debugPrint() const -{ - qDebug() << "Archidekt Entries:"; - for (const auto &entry : entries) { - entry.debugPrint(); - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.h deleted file mode 100644 index d265c164d..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef ARCHIDEKTENTRY_H -#define ARCHIDEKTENTRY_H - -#include -#include -#include - -/** - * @class EdhrecApiResponseArchidektLink - * @ingroup ApiResponses - * @brief Represents a single Archidekt entry - */ -class EdhrecApiResponseArchidektLink -{ -public: - QString c; - int f = 0; - int q = 0; - QString u; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -/** - * @class EdhrecCommanderApiResponseArchidektLinks - * @ingroup ApiResponses - * @brief Represents the Archidekt section as a list of entries - */ -class EdhrecCommanderApiResponseArchidektLinks -{ -public: - QVector entries; - - void fromJson(const QJsonArray &json); - void debugPrint() const; -}; - -#endif // ARCHIDEKTENTRY_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp deleted file mode 100644 index 1297fc157..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "edhrec_average_deck_api_response.h" - -#include -#include - -void EdhrecAverageDeckApiResponse::fromJson(const QJsonObject &json) -{ - // Parse the collapsed DeckStatistics - deckStats.fromJson(json); - - // Parse Archidekt section - QJsonArray archidektJson = json.value("archidekt").toArray(); - archidekt.fromJson(archidektJson); - - // Parse other fields - similar = json.value("similar").toObject(); - header = json.value("header").toString(); - panels = json.value("panels").toObject(); - description = json.value("description").toString(); - QJsonObject containerJson = json.value("container").toObject(); - container.fromJson(containerJson); - QJsonArray cardsJson = json.value("deck").toArray(); - deck.fromJson(cardsJson); -} - -void EdhrecAverageDeckApiResponse::debugPrint() const -{ - qDebug() << "Deck Statistics:"; - qDebug() << " Creature:" << deckStats.creature; - qDebug() << " Instant:" << deckStats.instant; - qDebug() << " Sorcery:" << deckStats.sorcery; - qDebug() << " Artifact:" << deckStats.artifact; - qDebug() << " Enchantment:" << deckStats.enchantment; - qDebug() << " Battle:" << deckStats.battle; - qDebug() << " Planeswalker:" << deckStats.planeswalker; - qDebug() << " Land:" << deckStats.land; - qDebug() << " Basic:" << deckStats.basic; - qDebug() << " Nonbasic:" << deckStats.nonbasic; - - archidekt.debugPrint(); - - qDebug() << "Similar:" << similar; - qDebug() << "Header:" << header; - qDebug() << "Panels:" << panels; - qDebug() << "Description:" << description; - container.debugPrint(); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.h deleted file mode 100644 index 70d37cbae..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EDHREC_AVERAGE_DECK_API_RESPONSE_H -#define EDHREC_AVERAGE_DECK_API_RESPONSE_H - -#include "../archidekt_links/edhrec_api_response_archidekt_links.h" -#include "../cards/edhrec_api_response_card_container.h" -#include "../commander/edhrec_commander_api_response_average_deck_statistics.h" -#include "edhrec_deck_api_response.h" - -#include -#include - -/** - * @class EdhrecAverageDeckApiResponse - * @ingroup ApiResponses - * @brief Represents the main structure of the JSON - */ -class EdhrecAverageDeckApiResponse -{ -public: - EdhrecCommanderApiResponseAverageDeckStatistics deckStats; - EdhrecCommanderApiResponseArchidektLinks archidekt; - QJsonObject similar; - QString header; - QJsonObject panels; - QString description; - EdhrecApiResponseCardContainer container; - EdhrecDeckApiResponse deck; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -#endif // EDHREC_AVERAGE_DECK_API_RESPONSE_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp deleted file mode 100644 index 1cb070c30..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "edhrec_deck_api_response.h" - -#include -#include -#include -#include -#include - -void EdhrecDeckApiResponse::fromJson(const QJsonArray &json) -{ - QString deckList; - for (const QJsonValue &cardlistValue : json) { - deckList += cardlistValue.toString() + "\n"; - } - - QTextStream stream(&deckList); - deck.loadFromStream_Plain(stream, true, CardNameNormalizer()); -} - -void EdhrecDeckApiResponse::debugPrint() const -{ - qDebug() << "Breadcrumb:"; -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.h deleted file mode 100644 index cd4f9d99c..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @file edhrec_deck_api_response.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef EDHREC_DECK_API_RESPONSE_H -#define EDHREC_DECK_API_RESPONSE_H - -#include "../../../../../../deck_loader/deck_loader.h" - -class EdhrecDeckApiResponse -{ -public: - // Constructor - EdhrecDeckApiResponse() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonArray &json); - - // Debug method for logging - void debugPrint() const; - - DeckList deck; -}; - -#endif // EDHREC_DECK_API_RESPONSE_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp deleted file mode 100644 index 1231d147a..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "edhrec_api_response_card_prices.h" - -#include - -void CardPrices::fromJson(const QJsonObject &json) -{ - // Parse prices from various sources - cardhoarder = json.value("cardhoarder").toObject(); - cardkingdom = json.value("cardkingdom").toObject(); - cardmarket = json.value("cardmarket").toObject(); - face2face = json.value("face2face").toObject(); - manapool = json.value("manapool").toObject(); - mtgstocks = json.value("mtgstocks").toObject(); - scg = json.value("scg").toObject(); - tcgl = json.value("tcgl").toObject(); - tcgplayer = json.value("tcgplayer").toObject(); -} - -void CardPrices::debugPrint() const -{ - qInfo() << "Card Prices:"; - qInfo() << "Cardhoarder:" << cardhoarder; - qInfo() << "Cardkingdom:" << cardkingdom; - qInfo() << "Cardmarket:" << cardmarket; - qInfo() << "Face2Face:" << face2face; - qInfo() << "Manapool:" << manapool; - qInfo() << "Mtgstocks:" << mtgstocks; - qInfo() << "SCG:" << scg; - qInfo() << "TCGL:" << tcgl; - qInfo() << "Tcgplayer:" << tcgplayer; -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h deleted file mode 100644 index 66a407acd..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file edhrec_api_response_card_prices.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_CARD_PRICES_H -#define EDHREC_COMMANDER_API_RESPONSE_CARD_PRICES_H - -#include - -class CardPrices -{ -public: - // Constructor - CardPrices() = default; - - // Parse prices from JSON - void fromJson(const QJsonObject &json); - void debugPrint() const; - - // Getter methods for card prices - [[nodiscard]] const QJsonObject &getCardhoarder() const - { - return cardhoarder; - } - [[nodiscard]] const QJsonObject &getCardkingdom() const - { - return cardkingdom; - } - [[nodiscard]] const QJsonObject &getCardmarket() const - { - return cardmarket; - } - [[nodiscard]] const QJsonObject &getFace2face() const - { - return face2face; - } - [[nodiscard]] const QJsonObject &getManapool() const - { - return manapool; - } - [[nodiscard]] const QJsonObject &getMtgstocks() const - { - return mtgstocks; - } - [[nodiscard]] const QJsonObject &getScg() const - { - return scg; - } - [[nodiscard]] const QJsonObject &getTcgl() const - { - return tcgl; - } - [[nodiscard]] const QJsonObject &getTcgplayer() const - { - return tcgplayer; - } - -private: - QJsonObject cardhoarder; - QJsonObject cardkingdom; - QJsonObject cardmarket; - QJsonObject face2face; - QJsonObject manapool; - QJsonObject mtgstocks; - QJsonObject scg; - QJsonObject tcgl; - QJsonObject tcgplayer; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_CARD_PRICES_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp deleted file mode 100644 index 3fef8be34..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "edhrec_api_response_card_container.h" - -#include -#include -#include - -void EdhrecApiResponseCardContainer::fromJson(const QJsonObject &json) -{ - // Parse breadcrumb - QJsonArray breadcrumbArray = json.value("breadcrumb").toArray(); - for (const QJsonValue &breadcrumbValue : breadcrumbArray) { - breadcrumb.push_back(breadcrumbValue.toObject()); - } - - description = json.value("description").toString(); - QJsonObject jsonDict = json.value("json_dict").toObject(); - card.fromJson(jsonDict.value("card").toObject()); - QJsonArray cardlistsArray = jsonDict.value("cardlists").toArray(); - - for (const QJsonValue &cardlistValue : cardlistsArray) { - QJsonObject cardlistObj = cardlistValue.toObject(); - QJsonArray cardviewsArray = cardlistObj.value("cardviews").toArray(); - EdhrecApiResponseCardList cardView; - cardView.fromJson(cardlistValue.toObject()); - cardlists.push_back(cardView); - } - - keywords = json.value("keywords").toString(); - title = json.value("title").toString(); -} - -void EdhrecApiResponseCardContainer::debugPrint() const -{ - qDebug() << "Breadcrumb:"; - for (const auto &breadcrumbEntry : breadcrumb) { - qDebug() << breadcrumbEntry; - } - - qDebug() << "Description:" << description; - card.debugPrint(); - - qDebug() << "Cardlists:"; - for (const auto &cardlist : cardlists) { - cardlist.debugPrint(); - } - - qDebug() << "Keywords:" << keywords; - qDebug() << "Title:" << title; -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.h deleted file mode 100644 index 07b53dd97..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_container.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file edhrec_api_response_card_container.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef CONTAINER_ENTRY_H -#define CONTAINER_ENTRY_H - -#include "edhrec_api_response_card_list.h" -#include "edhrec_commander_api_response_commander_details.h" - -#include -#include -#include - -class EdhrecApiResponseCardContainer -{ -public: - // Constructor - EdhrecApiResponseCardContainer() = default; - - // Parse deck-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - // Getter methods for deck container - [[nodiscard]] const QString &getDescription() const - { - return description; - } - [[nodiscard]] const QVector &getBreadcrumb() const - { - return breadcrumb; - } - [[nodiscard]] const EdhrecCommanderApiResponseCommanderDetails &getCommanderDetails() const - { - return card; - } - [[nodiscard]] const QVector &getCardlists() const - { - return cardlists; - } - [[nodiscard]] const QString &getKeywords() const - { - return keywords; - } - [[nodiscard]] const QString &getTitle() const - { - return title; - } - -private: - QString description; - QVector breadcrumb; - EdhrecCommanderApiResponseCommanderDetails card; - QVector cardlists; - QString keywords; - QString title; -}; - -#endif // CONTAINER_ENTRY_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp deleted file mode 100644 index a4a746c61..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "edhrec_api_response_card_details.h" - -#include - -EdhrecApiResponseCardDetails::EdhrecApiResponseCardDetails() - : synergy(0.0), inclusion(0), numDecks(0), potentialDecks(0) -{ -} - -void EdhrecApiResponseCardDetails::fromJson(const QJsonObject &json) -{ - // Parse the fields from the JSON object - name = json.value("name").toString(); - sanitized = json.value("sanitized").toString(); - sanitizedWo = json.value("sanitized_wo").toString(); - url = json.value("url").toString(); - synergy = json.value("synergy").toDouble(0.0); - inclusion = json.value("inclusion").toInt(0); - label = json.value("label").toString(); - numDecks = json.value("num_decks").toInt(0); - potentialDecks = json.value("potential_decks").toInt(0); -} - -void EdhrecApiResponseCardDetails::debugPrint() const -{ - // Print out all the fields for debugging - qDebug() << "Name:" << name; - qDebug() << "Sanitized:" << sanitized; - qDebug() << "Sanitized Wo:" << sanitizedWo; - qDebug() << "URL:" << url; - qDebug() << "Synergy:" << synergy; - qDebug() << "Inclusion:" << inclusion; - qDebug() << "Label:" << label; - qDebug() << "Num Decks:" << numDecks; - qDebug() << "Potential Decks:" << potentialDecks; -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.h deleted file mode 100644 index 86d78c5e3..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_details.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file edhrec_api_response_card_details.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef CARD_VIEW_H -#define CARD_VIEW_H - -#include -#include - -class EdhrecApiResponseCardDetails -{ -public: - QString name; - QString sanitized; - QString sanitizedWo; - QString url; - double synergy; - int inclusion; - QString label; - int numDecks; - int potentialDecks; - - EdhrecApiResponseCardDetails(); - - // Method to populate the object from a JSON object - void fromJson(const QJsonObject &json); - - // Debug method to print out the data - void debugPrint() const; -}; - -#endif // CARD_VIEW_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp deleted file mode 100644 index 72d6fe2cc..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "edhrec_api_response_card_list.h" - -#include - -EdhrecApiResponseCardList::EdhrecApiResponseCardList() -{ -} - -void EdhrecApiResponseCardList::fromJson(const QJsonObject &json) -{ - // Parse the header from the JSON object - header = json.value("header").toString(); - - // Parse the cardviews array and populate cardViews - QJsonArray cardviewsArray = json.value("cardviews").toArray(); - for (const QJsonValue &value : cardviewsArray) { - QJsonObject cardviewObj = value.toObject(); - EdhrecApiResponseCardDetails cardView; - cardView.fromJson(cardviewObj); - cardViews.append(cardView); - } -} - -void EdhrecApiResponseCardList::debugPrint() const -{ - // Print out the header - qDebug() << "Header:" << header; - - // Print out all the CardView objects - for (const EdhrecApiResponseCardDetails &cardView : cardViews) { - cardView.debugPrint(); - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.h deleted file mode 100644 index 15691fbe4..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_api_response_card_list.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file edhrec_api_response_card_list.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef CARD_LIST_H -#define CARD_LIST_H - -#include "edhrec_api_response_card_details.h" - -#include -#include -#include - -class EdhrecApiResponseCardList -{ -public: - QString header; - QList cardViews; - - // Default constructor - EdhrecApiResponseCardList(); - - // Method to populate the object from a JSON object - void fromJson(const QJsonObject &json); - - // Debug method to print out the data - void debugPrint() const; -}; - -#endif // CARD_LIST_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp deleted file mode 100644 index 7b220603e..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "edhrec_commander_api_response_commander_details.h" - -#include - -void EdhrecCommanderApiResponseCommanderDetails::fromJson(const QJsonObject &json) -{ - // Parse card-related data - aetherhubUri = json.value("aetherhub_uri").toString(); - archidektUri = json.value("archidekt_uri").toString(); - cmc = json.value("cmc").toInt(0); - colorIdentity = json.value("color_identity").toArray(); - combos = json.value("combos").toBool(false); - deckstatsUri = json.value("deckstats_uri").toString(); - - // Parse image URIs - QJsonArray imageUrisArray = json.value("image_uris").toArray(); - for (const QJsonValue &imageValue : imageUrisArray) { - QJsonObject imageObject = imageValue.toObject(); - imageUris.push_back(imageObject.value("normal").toString()); - imageUris.push_back(imageObject.value("art_crop").toString()); - } - - inclusion = json.value("inclusion").toInt(0); - isCommander = json.value("is_commander").toBool(false); - label = json.value("label").toString(); - layout = json.value("layout").toString(); - legalCommander = json.value("legal_commander").toBool(false); - moxfieldUri = json.value("moxfield_uri").toString(); - mtggoldfishUri = json.value("mtggoldfish_uri").toString(); - name = json.value("name").toString(); - names = json.value("names").toArray(); - numDecks = json.value("num_decks").toInt(0); - potentialDecks = json.value("potential_decks").toInt(0); - precon = json.value("precon").toString(); - - // Parse prices - prices.fromJson(json.value("prices").toObject()); - - primaryType = json.value("primary_type").toString(); - rarity = json.value("rarity").toString(); - salt = json.value("salt").toDouble(0.0); - sanitized = json.value("sanitized").toString(); - sanitizedWo = json.value("sanitized_wo").toString(); - scryfallUri = json.value("scryfall_uri").toString(); - spellbookUri = json.value("spellbook_uri").toString(); - type = json.value("type").toString(); - url = json.value("url").toString(); -} - -void EdhrecCommanderApiResponseCommanderDetails::debugPrint() const -{ - qDebug() << "Card Data:"; - qDebug() << "Aetherhub URI:" << aetherhubUri; - qDebug() << "Archidekt URI:" << archidektUri; - qDebug() << "CMC:" << cmc; - qDebug() << "Color Identity:" << colorIdentity; - qDebug() << "Combos:" << combos; - qDebug() << "Deckstats URI:" << deckstatsUri; - - qDebug() << "Image URIs:"; - for (const auto &uri : imageUris) { - qDebug() << uri; - } - - qDebug() << "Inclusion:" << inclusion; - qDebug() << "Is Commander:" << isCommander; - qDebug() << "Label:" << label; - qDebug() << "Layout:" << layout; - qDebug() << "Legal Commander:" << legalCommander; - qDebug() << "Moxfield URI:" << moxfieldUri; - qDebug() << "MTGGoldfish URI:" << mtggoldfishUri; - qDebug() << "Name:" << name; - qDebug() << "Names:" << names; - qDebug() << "Number of Decks:" << numDecks; - qDebug() << "Potential Decks:" << potentialDecks; - qDebug() << "Precon:" << precon; - - // Print the prices using the debugPrint method from CardPrices - prices.debugPrint(); - - qDebug() << "Primary Type:" << primaryType; - qDebug() << "Rarity:" << rarity; - qDebug() << "Salt:" << salt; - qDebug() << "Sanitized:" << sanitized; - qDebug() << "Sanitized WO:" << sanitizedWo; - qDebug() << "Scryfall URI:" << scryfallUri; - qDebug() << "Spellbook URI:" << spellbookUri; - qDebug() << "Type:" << type; - qDebug() << "URL:" << url; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.h deleted file mode 100644 index 629eb8273..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/cards/edhrec_commander_api_response_commander_details.h +++ /dev/null @@ -1,178 +0,0 @@ -/** - * @file edhrec_commander_api_response_commander_details.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_H -#define EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_H - -#include "../card_prices/edhrec_api_response_card_prices.h" - -#include -#include -#include - -class EdhrecCommanderApiResponseCommanderDetails -{ -public: - // Constructor - EdhrecCommanderApiResponseCommanderDetails() = default; - - // Parse card-related data from JSON - void fromJson(const QJsonObject &json); - - // Debug method for logging - void debugPrint() const; - - // Getters for the card data - [[nodiscard]] const QString &getAetherhubUri() const - { - return aetherhubUri; - } - [[nodiscard]] const QString &getArchidektUri() const - { - return archidektUri; - } - [[nodiscard]] int getCmc() const - { - return cmc; - } - [[nodiscard]] const QJsonArray &getColorIdentity() const - { - return colorIdentity; - } - [[nodiscard]] bool isCombos() const - { - return combos; - } - [[nodiscard]] const QString &getDeckstatsUri() const - { - return deckstatsUri; - } - [[nodiscard]] const QVector &getImageUris() const - { - return imageUris; - } - [[nodiscard]] int getInclusion() const - { - return inclusion; - } - [[nodiscard]] bool getIsCommander() const - { - return isCommander; - } - [[nodiscard]] const QString &getLabel() const - { - return label; - } - [[nodiscard]] const QString &getLayout() const - { - return layout; - } - [[nodiscard]] bool getLegalCommander() const - { - return legalCommander; - } - [[nodiscard]] const QString &getMoxfieldUri() const - { - return moxfieldUri; - } - [[nodiscard]] const QString &getMtggoldfishUri() const - { - return mtggoldfishUri; - } - [[nodiscard]] const QString &getName() const - { - return name; - } - [[nodiscard]] const QJsonArray &getNames() const - { - return names; - } - [[nodiscard]] int getNumDecks() const - { - return numDecks; - } - [[nodiscard]] int getPotentialDecks() const - { - return potentialDecks; - } - [[nodiscard]] const QString &getPrecon() const - { - return precon; - } - [[nodiscard]] const CardPrices &getPrices() const - { - return prices; - } - [[nodiscard]] const QString &getPrimaryType() const - { - return primaryType; - } - [[nodiscard]] const QString &getRarity() const - { - return rarity; - } - [[nodiscard]] double getSalt() const - { - return salt; - } - [[nodiscard]] const QString &getSanitized() const - { - return sanitized; - } - [[nodiscard]] const QString &getSanitizedWo() const - { - return sanitizedWo; - } - [[nodiscard]] const QString &getScryfallUri() const - { - return scryfallUri; - } - [[nodiscard]] const QString &getSpellbookUri() const - { - return spellbookUri; - } - [[nodiscard]] const QString &getType() const - { - return type; - } - [[nodiscard]] const QString &getUrl() const - { - return url; - } - -private: - QString aetherhubUri; - QString archidektUri; - int cmc = 0; - QJsonArray colorIdentity; - bool combos = false; - QString deckstatsUri; - QVector imageUris; - int inclusion = 0; - bool isCommander = false; - QString label; - QString layout; - bool legalCommander = false; - QString moxfieldUri; - QString mtggoldfishUri; - QString name; - QJsonArray names; - int numDecks = 0; - int potentialDecks = 0; - QString precon; - CardPrices prices; - QString primaryType; - QString rarity; - double salt = 0.0; - QString sanitized; - QString sanitizedWo; - QString scryfallUri; - QString spellbookUri; - QString type; - QString url; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp deleted file mode 100644 index da2a9c052..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "edhrec_commander_api_response.h" - -#include -#include - -void EdhrecCommanderApiResponse::fromJson(const QJsonObject &json) -{ - // Parse the collapsed DeckStatistics - deckStats.fromJson(json); - - // Parse Archidekt section - QJsonArray archidektJson = json.value("archidekt").toArray(); - archidekt.fromJson(archidektJson); - - // Parse other fields - similar = json.value("similar").toObject(); - header = json.value("header").toString(); - panels = json.value("panels").toObject(); - description = json.value("description").toString(); - QJsonObject containerJson = json.value("container").toObject(); - container.fromJson(containerJson); -} - -void EdhrecCommanderApiResponse::debugPrint() const -{ - qDebug() << "Deck Statistics:"; - qDebug() << " Creature:" << deckStats.creature; - qDebug() << " Instant:" << deckStats.instant; - qDebug() << " Sorcery:" << deckStats.sorcery; - qDebug() << " Artifact:" << deckStats.artifact; - qDebug() << " Enchantment:" << deckStats.enchantment; - qDebug() << " Battle:" << deckStats.battle; - qDebug() << " Planeswalker:" << deckStats.planeswalker; - qDebug() << " Land:" << deckStats.land; - qDebug() << " Basic:" << deckStats.basic; - qDebug() << " Nonbasic:" << deckStats.nonbasic; - - archidekt.debugPrint(); - - qDebug() << "Similar:" << similar; - qDebug() << "Header:" << header; - qDebug() << "Panels:" << panels; - qDebug() << "Description:" << description; - container.debugPrint(); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.h deleted file mode 100644 index 64f2fd7cd..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef DECKDATA_H -#define DECKDATA_H - -#include "../archidekt_links/edhrec_api_response_archidekt_links.h" -#include "../cards/edhrec_api_response_card_container.h" -#include "edhrec_commander_api_response_average_deck_statistics.h" - -#include -#include - -/** - * @class EdhrecCommanderApiResponse - * @ingroup ApiResponses - * @brief Represents the main structure of the JSON - */ -class EdhrecCommanderApiResponse -{ -public: - EdhrecCommanderApiResponseAverageDeckStatistics deckStats; - EdhrecCommanderApiResponseArchidektLinks archidekt; - QJsonObject similar; - QString header; - QJsonObject panels; - QString description; - EdhrecApiResponseCardContainer container; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -#endif // DECKDATA_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp deleted file mode 100644 index 74cce5322..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "edhrec_commander_api_response_average_deck_statistics.h" - -void EdhrecCommanderApiResponseAverageDeckStatistics::fromJson(const QJsonObject &json) -{ - creature = json.value("creature").toInt(0); - instant = json.value("instant").toInt(0); - sorcery = json.value("sorcery").toInt(0); - artifact = json.value("artifact").toInt(0); - enchantment = json.value("enchantment").toInt(0); - battle = json.value("battle").toInt(0); - planeswalker = json.value("planeswalker").toInt(0); - land = json.value("land").toInt(0); - basic = json.value("basic").toInt(0); - nonbasic = json.value("nonbasic").toInt(0); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.h deleted file mode 100644 index 5d9980220..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/commander/edhrec_commander_api_response_average_deck_statistics.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef AVERAGE_DECK_STATISTICS_H -#define AVERAGE_DECK_STATISTICS_H - -#include - -/** - * @struct EdhrecCommanderApiResponseAverageDeckStatistics - * @ingroup ApiResponses - * @brief Represents the typical deck statistics (collapsed section) - */ -struct EdhrecCommanderApiResponseAverageDeckStatistics -{ - int creature = 0; - int instant = 0; - int sorcery = 0; - int artifact = 0; - int enchantment = 0; - int battle = 0; - int planeswalker = 0; - int land = 0; - int basic = 0; - int nonbasic = 0; - - void fromJson(const QJsonObject &json); -}; -#endif // AVERAGE_DECK_STATISTICS_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp deleted file mode 100644 index 26122ce89..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "edhrec_top_cards_api_response.h" - -#include -#include - -void EdhrecTopCardsApiResponse::fromJson(const QJsonObject &json) -{ - header = json.value("header").toString(); - description = json.value("description").toString(); - QJsonObject containerJson = json.value("container").toObject(); - container.fromJson(containerJson); -} - -void EdhrecTopCardsApiResponse::debugPrint() const -{ - qDebug() << "Header:" << header; - qDebug() << "Description:" << description; - container.debugPrint(); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.h deleted file mode 100644 index fb89c0b12..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_cards/edhrec_top_cards_api_response.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file edhrec_top_cards_api_response.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef EDHREC_TOP_CARDS_API_RESPONSE_H -#define EDHREC_TOP_CARDS_API_RESPONSE_H - -#include "../cards/edhrec_api_response_card_container.h" - -#include - -class EdhrecTopCardsApiResponse -{ -public: - QString header; - QString description; - EdhrecApiResponseCardContainer container; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -#endif // EDHREC_TOP_CARDS_API_RESPONSE_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp deleted file mode 100644 index 83b10c9e5..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "edhrec_top_commanders_api_response.h" - -#include -#include - -void EdhrecTopCommandersApiResponse::fromJson(const QJsonObject &json) -{ - header = json.value("header").toString(); - description = json.value("description").toString(); - QJsonObject containerJson = json.value("container").toObject(); - container.fromJson(containerJson); -} - -void EdhrecTopCommandersApiResponse::debugPrint() const -{ - qDebug() << "Header:" << header; - qDebug() << "Description:" << description; - container.debugPrint(); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.h deleted file mode 100644 index 26c5afedb..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_commanders/edhrec_top_commanders_api_response.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file edhrec_top_commanders_api_response.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef EDHREC_TOP_COMMANDERS_API_RESPONSE_H -#define EDHREC_TOP_COMMANDERS_API_RESPONSE_H - -#include "../cards/edhrec_api_response_card_container.h" - -#include - -class EdhrecTopCommandersApiResponse -{ -public: - QString header; - QString description; - EdhrecApiResponseCardContainer container; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -#endif // EDHREC_TOP_COMMANDERS_API_RESPONSE_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp deleted file mode 100644 index 56eb4fa4f..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "edhrec_top_tags_api_response.h" - -#include -#include - -void EdhrecTopTagsApiResponse::fromJson(const QJsonObject &json) -{ - header = json.value("header").toString(); - description = json.value("description").toString(); - QJsonObject containerJson = json.value("container").toObject(); - container.fromJson(containerJson); -} - -void EdhrecTopTagsApiResponse::debugPrint() const -{ - qDebug() << "Header:" << header; - qDebug() << "Description:" << description; - container.debugPrint(); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.h deleted file mode 100644 index 48219893a..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/top_tags/edhrec_top_tags_api_response.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @file edhrec_top_tags_api_response.h - * @ingroup ApiResponses - * @brief TODO: Document this. - */ - -#ifndef EDHREC_TOP_TAGS_API_RESPONSE_H -#define EDHREC_TOP_TAGS_API_RESPONSE_H - -#include "../cards/edhrec_api_response_card_container.h" - -#include - -class EdhrecTopTagsApiResponse -{ -public: - QString header; - QString description; - EdhrecApiResponseCardContainer container; - - void fromJson(const QJsonObject &json); - void debugPrint() const; -}; - -#endif // EDHREC_TOP_TAGS_API_RESPONSE_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp deleted file mode 100644 index 75902daad..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "edhrec_api_response_card_prices_display_widget.h" - -EdhrecApiResponseCardPricesDisplayWidget::EdhrecApiResponseCardPricesDisplayWidget(QWidget *parent, - const CardPrices &_cardPrices) - : QWidget(parent), cardPrices(_cardPrices) -{ - layout = new QGridLayout(this); - setLayout(layout); - - cardHoarderLabel = new QLabel(this); - cardHoarderPrice = new QLabel(QString::number(cardPrices.getCardhoarder().value("price").toDouble()), this); - cardKingdomLabel = new QLabel(this); - cardKingdomPrice = new QLabel(QString::number(cardPrices.getCardkingdom().value("price").toDouble()), this); - cardMarketLabel = new QLabel(this); - cardMarketPrice = new QLabel(QString::number(cardPrices.getCardmarket().value("price").toDouble()), this); - face2faceLabel = new QLabel(this); - face2facePrice = new QLabel(QString::number(cardPrices.getFace2face().value("price").toDouble()), this); - manaPoolLabel = new QLabel(this); - manaPoolPrice = new QLabel(QString::number(cardPrices.getManapool().value("price").toDouble()), this); - mtgStocksLabel = new QLabel(this); - mtgStocksPrice = new QLabel(QString::number(cardPrices.getMtgstocks().value("price").toDouble()), this); - scgLabel = new QLabel(this); - scgPrice = new QLabel(QString::number(cardPrices.getScg().value("price").toDouble()), this); - tcglLabel = new QLabel(this); - tcglPrice = new QLabel(QString::number(cardPrices.getTcgl().value("price").toDouble()), this); - tcgplayerLabel = new QLabel(this); - tcgplayerPrice = new QLabel(QString::number(cardPrices.getTcgplayer().value("price").toDouble()), this); - - layout->addWidget(cardHoarderLabel, 0, 0); - layout->addWidget(cardHoarderPrice, 0, 1); - layout->addWidget(cardKingdomLabel, 0, 2); - layout->addWidget(cardKingdomPrice, 0, 3); - - layout->addWidget(cardMarketLabel, 1, 0); - layout->addWidget(cardMarketPrice, 1, 1); - layout->addWidget(face2faceLabel, 1, 2); - layout->addWidget(face2facePrice, 1, 3); - - layout->addWidget(manaPoolLabel, 2, 0); - layout->addWidget(manaPoolPrice, 2, 1); - layout->addWidget(mtgStocksLabel, 2, 2); - layout->addWidget(mtgStocksPrice, 2, 3); - - layout->addWidget(scgLabel, 3, 0); - layout->addWidget(scgPrice, 3, 1); - layout->addWidget(tcglLabel, 3, 2); - layout->addWidget(tcglPrice, 3, 3); - - layout->addWidget(tcgplayerLabel, 4, 0); - layout->addWidget(tcgplayerPrice, 4, 1); - - retranslateUi(); -} - -void EdhrecApiResponseCardPricesDisplayWidget::retranslateUi() -{ - cardHoarderLabel->setText(tr("Card Hoarder")); - cardKingdomLabel->setText(tr("Card Kingdom")); - cardMarketLabel->setText(tr("Card Market")); - face2faceLabel->setText(tr("Face 2-Face")); - manaPoolLabel->setText(tr("Mana Pool")); - mtgStocksLabel->setText(tr("MTG Stocks")); - scgLabel->setText(tr("Scg")); - tcglLabel->setText(tr("Tcgl")); - tcgplayerLabel->setText(tr("Tcgplayer")); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.h deleted file mode 100644 index 80d32a394..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/card_prices/edhrec_api_response_card_prices_display_widget.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file edhrec_api_response_card_prices_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_API_RESPONSE_CARD_PRICES_DISPLAY_WIDGET_H -#define EDHREC_API_RESPONSE_CARD_PRICES_DISPLAY_WIDGET_H - -#include "../../api_response/card_prices/edhrec_api_response_card_prices.h" - -#include -#include -#include - -class EdhrecApiResponseCardPricesDisplayWidget : public QWidget -{ - Q_OBJECT -public: - EdhrecApiResponseCardPricesDisplayWidget(QWidget *parent, const CardPrices &cardPrices); - -public slots: - void retranslateUi(); - -private: - CardPrices cardPrices; - QGridLayout *layout; - QLabel *cardHoarderLabel; - QLabel *cardHoarderPrice; - QLabel *cardKingdomLabel; - QLabel *cardKingdomPrice; - QLabel *cardMarketLabel; - QLabel *cardMarketPrice; - QLabel *face2faceLabel; - QLabel *face2facePrice; - QLabel *manaPoolLabel; - QLabel *manaPoolPrice; - QLabel *mtgStocksLabel; - QLabel *mtgStocksPrice; - QLabel *scgLabel; - QLabel *scgPrice; - QLabel *tcglLabel; - QLabel *tcglPrice; - QLabel *tcgplayerLabel; - QLabel *tcgplayerPrice; -}; - -#endif // EDHREC_API_RESPONSE_CARD_PRICES_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp deleted file mode 100644 index 9d45f254b..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "edhrec_api_response_card_details_display_widget.h" - -#include "../../../../../general/display/background_plate_widget.h" -#include "../../tab_edhrec_main.h" - -#include -#include - -EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWidget( - QWidget *parent, - const EdhrecApiResponseCardDetails &_toDisplay) - : QWidget(parent), toDisplay(_toDisplay) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - cardPictureWidget = new CardInfoPictureWidget(this); - cardPictureWidget->setCard(CardDatabaseManager::query()->guessCard({toDisplay.sanitized})); - - nameLabel = new QLabel(this); - nameLabel->setText(toDisplay.name); - nameLabel->setAlignment(Qt::AlignHCenter); - nameLabel->setStyleSheet("font-size: 20px; font-weight: bold"); - - inclusionDisplayWidget = new EdhrecApiResponseCardInclusionDisplayWidget(this, toDisplay); - - synergyDisplayWidget = new EdhrecApiResponseCardSynergyDisplayWidget(this, toDisplay); - - backgroundPlateWidget = new BackgroundPlateWidget(this); - auto plateLayout = new QVBoxLayout(backgroundPlateWidget); - - plateLayout->addWidget(nameLabel); - plateLayout->addWidget(cardPictureWidget); - plateLayout->addWidget(inclusionDisplayWidget); - plateLayout->addWidget(synergyDisplayWidget); - - layout->addWidget(backgroundPlateWidget); - - QWidget *currentParent = parentWidget(); - TabEdhRecMain *parentTab = nullptr; - - while (currentParent) { - if ((parentTab = qobject_cast(currentParent))) { - break; - } - currentParent = currentParent->parentWidget(); - } - - if (parentTab) { - cardPictureWidget->setScaleFactor(parentTab->getCardSizeSlider()->getSlider()->value()); - connect(cardPictureWidget, &CardInfoPictureWidget::cardClicked, this, - &EdhrecApiResponseCardDetailsDisplayWidget::mousePressEvent); - connect(parentTab->getCardSizeSlider()->getSlider(), &QSlider::valueChanged, cardPictureWidget, - &CardInfoPictureWidget::setScaleFactor); - connect(this, &EdhrecApiResponseCardDetailsDisplayWidget::requestUrl, parentTab, - &TabEdhRecMain::actNavigatePage); - } -} - -void EdhrecApiResponseCardDetailsDisplayWidget::mousePressEvent(QMouseEvent *event) -{ - QWidget::mousePressEvent(event); - if (event->button() == Qt::LeftButton) { - actRequestPageNavigation(); - } -} - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -void EdhrecApiResponseCardDetailsDisplayWidget::enterEvent(QEnterEvent *event) -#else -void EdhrecApiResponseCardDetailsDisplayWidget::enterEvent(QEvent *event) -#endif -{ - QWidget::enterEvent(event); - backgroundPlateWidget->setFocused(true); -} - -void EdhrecApiResponseCardDetailsDisplayWidget::leaveEvent(QEvent *event) -{ - QWidget::leaveEvent(event); - backgroundPlateWidget->setFocused(false); -} - -void EdhrecApiResponseCardDetailsDisplayWidget::actRequestPageNavigation() -{ - emit requestUrl(toDisplay.url); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h deleted file mode 100644 index 82dcfb8b0..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_details_display_widget.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file edhrec_api_response_card_details_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_CARD_DETAILS_DISPLAY_WIDGET_H -#define EDHREC_COMMANDER_API_RESPONSE_CARD_DETAILS_DISPLAY_WIDGET_H - -#include "../../../../../cards/card_info_picture_widget.h" -#include "../../../../../general/display/background_plate_widget.h" -#include "../../api_response/cards/edhrec_api_response_card_details.h" -#include "edhrec_api_response_card_inclusion_display_widget.h" -#include "edhrec_api_response_card_synergy_display_widget.h" - -#include -#include -#include - -class EdhrecApiResponseCardDetailsDisplayWidget : public QWidget -{ - Q_OBJECT -public: - explicit EdhrecApiResponseCardDetailsDisplayWidget(QWidget *parent, const EdhrecApiResponseCardDetails &_toDisplay); -public slots: - void actRequestPageNavigation(); -signals: - void requestUrl(QString url); - -private: - EdhrecApiResponseCardDetails toDisplay; - QVBoxLayout *layout; - CardInfoPictureWidget *cardPictureWidget; - BackgroundPlateWidget *backgroundPlateWidget; ///< Plate for metadata labels - QLabel *nameLabel; - EdhrecApiResponseCardInclusionDisplayWidget *inclusionDisplayWidget; - EdhrecApiResponseCardSynergyDisplayWidget *synergyDisplayWidget; - -protected slots: - void mousePressEvent(QMouseEvent *event) override; - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - void enterEvent(QEnterEvent *event) override; ///< Qt6 hover enter -#else - void enterEvent(QEvent *event) override; ///< Qt5 hover enter -#endif - void leaveEvent(QEvent *event) override; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_CARD_DETAILS_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp deleted file mode 100644 index 8292b00ea..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "edhrec_api_response_card_inclusion_display_widget.h" - -EdhrecApiResponseCardInclusionDisplayWidget::EdhrecApiResponseCardInclusionDisplayWidget( - QWidget *parent, - const EdhrecApiResponseCardDetails &_toDisplay) - : QWidget(parent), toDisplay(_toDisplay) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - commanderLabel = new QLabel(this); - commanderLabel->setAlignment(Qt::AlignCenter); - amountLabel = new QLabel(this); - amountLabel->setAlignment(Qt::AlignCenter); - inclusionLabel = new QLabel(this); - inclusionLabel->setAlignment(Qt::AlignCenter); - percentBarWidget = new PercentBarWidget(this, toDisplay.inclusion / (toDisplay.potentialDecks / 100.0)); - - if (toDisplay.inclusion != 0 && toDisplay.potentialDecks != 0) { - layout->addWidget(amountLabel); - layout->addWidget(inclusionLabel); - layout->addWidget(percentBarWidget); - commanderLabel->hide(); - } else { - amountLabel->hide(); - inclusionLabel->hide(); - percentBarWidget->hide(); - layout->addWidget(commanderLabel); - } - - retranslateUi(); -} - -void EdhrecApiResponseCardInclusionDisplayWidget::retranslateUi() -{ - commanderLabel->setText(toDisplay.label); - amountLabel->setText(tr("In %1 decks").arg(QString::number(toDisplay.inclusion))); - inclusionLabel->setText(tr("%1% of %2 decks") - .arg(QString::number(toDisplay.inclusion / (toDisplay.potentialDecks / 100.0), 'f', 2), - QString::number(toDisplay.potentialDecks))); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h deleted file mode 100644 index 43baddb4c..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_inclusion_display_widget.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file edhrec_api_response_card_inclusion_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_API_RESPONSE_CARD_INCLUSION_DISPLAY_WIDGET_H -#define EDHREC_API_RESPONSE_CARD_INCLUSION_DISPLAY_WIDGET_H - -#include "../../../../../general/display/charts/bars/percent_bar_widget.h" -#include "../../api_response/cards/edhrec_api_response_card_details.h" - -#include -#include -#include - -class EdhrecApiResponseCardInclusionDisplayWidget : public QWidget -{ - Q_OBJECT -public: - EdhrecApiResponseCardInclusionDisplayWidget(QWidget *parent, const EdhrecApiResponseCardDetails &_toDisplay); - void retranslateUi(); - -private: - QVBoxLayout *layout; - EdhrecApiResponseCardDetails toDisplay; - QLabel *commanderLabel; - QLabel *amountLabel; - QLabel *inclusionLabel; - PercentBarWidget *percentBarWidget; -}; - -#endif // EDHREC_API_RESPONSE_CARD_INCLUSION_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp deleted file mode 100644 index 841ef315b..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "edhrec_api_response_card_list_display_widget.h" - -#include "../../../../../general/display/banner_widget.h" -#include "edhrec_api_response_card_details_display_widget.h" - -#include - -EdhrecApiResponseCardListDisplayWidget::EdhrecApiResponseCardListDisplayWidget(QWidget *parent, - EdhrecApiResponseCardList toDisplay) - : QWidget(parent) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - header = new BannerWidget(this, toDisplay.header); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff); - header->setBuddy(flowWidget); - - foreach (EdhrecApiResponseCardDetails card_detail, toDisplay.cardViews) { - auto widget = new EdhrecApiResponseCardDetailsDisplayWidget(flowWidget, card_detail); - flowWidget->addWidget(widget); - } - - layout->addWidget(header); - layout->addWidget(flowWidget); -} - -void EdhrecApiResponseCardListDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - qDebug() << event->size(); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.h deleted file mode 100644 index d34c3da34..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_list_display_widget.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file edhrec_api_response_card_list_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_CARD_LIST_DISPLAY_WIDGET_H -#define EDHREC_COMMANDER_API_RESPONSE_CARD_LIST_DISPLAY_WIDGET_H - -#include "../../../../../general/display/banner_widget.h" -#include "../../../../../general/layout_containers/flow_widget.h" -#include "../../api_response/cards/edhrec_api_response_card_list.h" - -#include -#include -#include - -class EdhrecApiResponseCardListDisplayWidget : public QWidget -{ - Q_OBJECT -public: - explicit EdhrecApiResponseCardListDisplayWidget(QWidget *parent, EdhrecApiResponseCardList toDisplay); - void resizeEvent(QResizeEvent *event) override; - [[nodiscard]] QString getBannerText() const - { - return header->getText(); - } - -private: - QVBoxLayout *layout; - BannerWidget *header; - FlowWidget *flowWidget; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_CARD_LIST_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp deleted file mode 100644 index 9d5571a8f..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "edhrec_api_response_card_synergy_display_widget.h" - -EdhrecApiResponseCardSynergyDisplayWidget::EdhrecApiResponseCardSynergyDisplayWidget( - QWidget *parent, - const EdhrecApiResponseCardDetails &_toDisplay) - : QWidget(parent), toDisplay(_toDisplay) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - label = new QLabel(this); - label->setAlignment(Qt::AlignCenter); - percentBarWidget = new PercentBarWidget(this, toDisplay.synergy * 100.0); - - if (toDisplay.synergy != 0) { - layout->addWidget(label); - layout->addWidget(percentBarWidget); - } else { - hide(); - } - - retranslateUi(); -} - -void EdhrecApiResponseCardSynergyDisplayWidget::retranslateUi() -{ - label->setText(tr("%1% Synergy").arg(QString::number(toDisplay.synergy * 100.0, 'f', 1))); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h deleted file mode 100644 index c2e1c018c..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/cards/edhrec_api_response_card_synergy_display_widget.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file edhrec_api_response_card_synergy_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_API_RESPONSE_CARD_SYNERGY_DISPLAY_WIDGET_H -#define EDHREC_API_RESPONSE_CARD_SYNERGY_DISPLAY_WIDGET_H - -#include "../../../../../general/display/charts/bars/percent_bar_widget.h" -#include "../../api_response/cards/edhrec_api_response_card_details.h" - -#include -#include -#include - -class EdhrecApiResponseCardSynergyDisplayWidget : public QWidget -{ - Q_OBJECT -public: - EdhrecApiResponseCardSynergyDisplayWidget(QWidget *parent, const EdhrecApiResponseCardDetails &_toDisplay); - void retranslateUi(); - -private: - QVBoxLayout *layout; - EdhrecApiResponseCardDetails toDisplay; - QLabel *label; - PercentBarWidget *percentBarWidget; -}; - -#endif // EDHREC_API_RESPONSE_CARD_SYNERGY_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp deleted file mode 100644 index 515475f3e..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "edhrec_api_response_commander_details_display_widget.h" - -#include "../../../../../cards/card_info_picture_widget.h" -#include "../../tab_edhrec_main.h" -#include "../card_prices/edhrec_api_response_card_prices_display_widget.h" -#include "edhrec_commander_api_response_bracket_navigation_widget.h" - -#include - -EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCommanderDetailsDisplayWidget( - QWidget *parent, - const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails, - QString baseUrl) - : QWidget(parent), commanderDetails(_commanderDetails) -{ - layout = new QHBoxLayout(this); - setLayout(layout); - - commanderLayout = new QHBoxLayout(); - commanderDetailsLayout = new QVBoxLayout(); - commanderDetailsLayout->setAlignment(Qt::AlignCenter); - navigationAndPricesLayout = new QVBoxLayout(); - - commanderPicture = new CardInfoPictureWidget(this); - commanderPicture->setCard(CardDatabaseManager::query()->getCard({commanderDetails.getName()})); - - QWidget *currentParent = parentWidget(); - TabEdhRecMain *parentTab = nullptr; - - while (currentParent) { - if ((parentTab = qobject_cast(currentParent))) { - break; - } - currentParent = currentParent->parentWidget(); - } - - if (parentTab) { - connect(parentTab->getCardSizeSlider()->getSlider(), &QSlider::valueChanged, commanderPicture, - &CardInfoPictureWidget::setScaleFactor); - commanderPicture->setScaleFactor(parentTab->getCardSizeSlider()->getSlider()->value()); - } - - commanderDetails.debugPrint(); - - commanderName = new QLabel(this); - commanderName->setText(commanderDetails.getName()); - commanderName->setAlignment(Qt::AlignCenter); - commanderName->setStyleSheet("font-size: 28px; font-weight: bold"); - - label = new QLabel(this); - label->setAlignment(Qt::AlignCenter); - label->setStyleSheet("font-size: 16px"); - - salt = new QLabel(this); - salt->setAlignment(Qt::AlignCenter); - salt->setStyleSheet("font-size: 16px"); - - cardPricesDisplayWidget = new EdhrecApiResponseCardPricesDisplayWidget(this, commanderDetails.getPrices()); - - navigationWidget = new EdhrecCommanderApiResponseNavigationWidget(this, commanderDetails, baseUrl); - - commanderLayout->addWidget(commanderPicture); - commanderDetailsLayout->addWidget(commanderName); - commanderDetailsLayout->addSpacing(1); - commanderDetailsLayout->addWidget(label); - commanderDetailsLayout->addWidget(salt); - commanderDetailsLayout->addWidget(cardPricesDisplayWidget); - commanderLayout->addLayout(commanderDetailsLayout); - navigationAndPricesLayout->addWidget(navigationWidget); - // navigationAndPricesLayout->addWidget(cardPricesDisplayWidget); - - layout->addLayout(commanderLayout); - layout->addLayout(navigationAndPricesLayout); - - retranslateUi(); -} - -void EdhrecCommanderResponseCommanderDetailsDisplayWidget::retranslateUi() -{ - label->setText(commanderDetails.getLabel()); - salt->setText(tr("Salt: ") + QString::number(commanderDetails.getSalt())); -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.h deleted file mode 100644 index 8e74588e2..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_api_response_commander_details_display_widget.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file edhrec_api_response_commander_details_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_DISPLAY_WIDGET_H -#define EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_DISPLAY_WIDGET_H - -#include "../../../../../cards/card_info_picture_widget.h" -#include "../../api_response/cards/edhrec_commander_api_response_commander_details.h" -#include "../card_prices/edhrec_api_response_card_prices_display_widget.h" -#include "edhrec_commander_api_response_navigation_widget.h" - -#include -#include -#include - -class EdhrecCommanderApiResponseNavigationWidget; -class EdhrecCommanderResponseCommanderDetailsDisplayWidget : public QWidget -{ - Q_OBJECT -public: - explicit EdhrecCommanderResponseCommanderDetailsDisplayWidget( - QWidget *parent, - const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails, - QString baseUrl); - void retranslateUi(); - -private: - EdhrecCommanderApiResponseCommanderDetails commanderDetails; - QHBoxLayout *layout; - QHBoxLayout *commanderLayout; - QVBoxLayout *commanderDetailsLayout; - QVBoxLayout *navigationAndPricesLayout; - CardInfoPictureWidget *commanderPicture; - QLabel *commanderName; - QLabel *label; - QLabel *salt; - EdhrecApiResponseCardPricesDisplayWidget *cardPricesDisplayWidget; - EdhrecCommanderApiResponseNavigationWidget *navigationWidget; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp deleted file mode 100644 index c3ab23e41..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "edhrec_commander_api_response_bracket_navigation_widget.h" - -#include - -EdhrecCommanderApiResponseBracketNavigationWidget::EdhrecCommanderApiResponseBracketNavigationWidget( - QWidget *parent, - const QString &baseUrl) - : QWidget(parent) -{ - layout = new QGridLayout(this); - setLayout(layout); - - gameChangerLabel = new QLabel(this); - - layout->addWidget(gameChangerLabel, 1, 0, 1, 2); - - for (int i = 0; i < gameChangerOptions.length(); i++) { - QString option = gameChangerOptions.at(i); - QString label = option.isEmpty() ? "All" : option.at(0).toUpper() + option.mid(1); - QPushButton *optionButton = new QPushButton(label, this); - optionButton->setMinimumHeight(84); - optionButton->setStyleSheet("font-size: 24px"); - gameChangerButtons[option] = optionButton; - layout->addWidget(optionButton, 2, i); - connect(optionButton, &QPushButton::clicked, this, [=, this]() { - selectedGameChanger = option; - updateOptionButtonSelection(gameChangerButtons, option); - emit requestNavigation(); - }); - } - - updateOptionButtonSelection(gameChangerButtons, ""); - - retranslateUi(); - applyOptionsFromUrl(baseUrl); -} - -void EdhrecCommanderApiResponseBracketNavigationWidget::retranslateUi() -{ - gameChangerLabel->setText(tr("Game Changers")); -} - -void EdhrecCommanderApiResponseBracketNavigationWidget::applyOptionsFromUrl(const QString &url) -{ - QString cleanedUrl = url; - - // Remove base and file extension - if (cleanedUrl.startsWith("https://json.edhrec.com/pages/")) { - cleanedUrl = cleanedUrl.mid(QString("https://json.edhrec.com/pages/").length()); - } - if (cleanedUrl.endsWith(".json")) { - cleanedUrl.chop(5); - } - - // Expecting something like: "commanders/the-ur-dragon/core/expensive" - QStringList parts = cleanedUrl.split('/', Qt::SkipEmptyParts); - - if (parts.size() < 2) { - return; - } - - QString commanderName = parts[1]; - QString gameChangerOpt; - - // Define valid sets - QSet validGameChangers = {"exhibition", "core", "upgraded", "optimized", "cedh"}; - - // Check remaining parts after commander - for (int i = 2; i < parts.size(); ++i) { - QString part = parts[i].toLower(); - if (validGameChangers.contains(part)) { - gameChangerOpt = part; - } - } - - // Validate and apply - if (!gameChangerButtons.contains(gameChangerOpt)) { - gameChangerOpt.clear(); - } - - selectedGameChanger = gameChangerOpt; - - updateOptionButtonSelection(gameChangerButtons, selectedGameChanger); -} - -void EdhrecCommanderApiResponseBracketNavigationWidget::updateOptionButtonSelection( - QMap &buttons, - const QString &selectedKey) -{ - for (auto it = buttons.begin(); it != buttons.end(); ++it) { - it.value()->setStyleSheet(it.key() == selectedKey - ? "background-color: lightblue; font-weight: bold; font-size: 24px;" - : "font-size: 24px"); - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h deleted file mode 100644 index 713ef2791..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H -#define COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H - -#include -#include -#include -#include -#include - -class EdhrecCommanderApiResponseBracketNavigationWidget : public QWidget -{ - Q_OBJECT -public: - explicit EdhrecCommanderApiResponseBracketNavigationWidget(QWidget *parent, const QString &baseUrl); - void retranslateUi(); - void applyOptionsFromUrl(const QString &url); - QString getSelectedGameChanger() const - { - return selectedGameChanger; - } - -signals: - void requestNavigation(); - -private: - QGridLayout *layout; - QLabel *gameChangerLabel; - - QStringList gameChangerOptions = {"", "exhibition", "core", "upgraded", "optimized", "cedh"}; - QString selectedGameChanger; - - QMap gameChangerButtons; - - void updateOptionButtonSelection(QMap &buttons, const QString &selectedKey); -}; - -#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp deleted file mode 100644 index 1845c020d..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "edhrec_commander_api_response_budget_navigation_widget.h" - -#include - -EdhrecCommanderApiResponseBudgetNavigationWidget::EdhrecCommanderApiResponseBudgetNavigationWidget( - QWidget *parent, - const QString &baseUrl) - : QWidget(parent) -{ - layout = new QGridLayout(this); - setLayout(layout); - - budgetLabel = new QLabel(this); - - layout->addWidget(budgetLabel, 3, 0, 1, 2); - - for (int i = 0; i < budgetOptions.length(); i++) { - QString option = budgetOptions.at(i); - QString label = option.isEmpty() ? "Any" : option.at(0).toUpper() + option.mid(1); - QPushButton *btn = new QPushButton(label, this); - btn->setMinimumHeight(84); - btn->setStyleSheet("font-size: 24px"); - budgetButtons[option] = btn; - layout->addWidget(btn, 4, i); - connect(btn, &QPushButton::clicked, this, [=, this]() { - selectedBudget = option; - updateOptionButtonSelection(budgetButtons, option); - emit requestNavigation(); - }); - } - - updateOptionButtonSelection(budgetButtons, ""); - - retranslateUi(); - applyOptionsFromUrl(baseUrl); -} - -void EdhrecCommanderApiResponseBudgetNavigationWidget::retranslateUi() -{ - budgetLabel->setText(tr("Budget")); -} - -void EdhrecCommanderApiResponseBudgetNavigationWidget::applyOptionsFromUrl(const QString &url) -{ - QString cleanedUrl = url; - - // Remove base and file extension - if (cleanedUrl.startsWith("https://json.edhrec.com/pages/")) { - cleanedUrl = cleanedUrl.mid(QString("https://json.edhrec.com/pages/").length()); - } - if (cleanedUrl.endsWith(".json")) { - cleanedUrl.chop(5); - } - - // Expecting something like: "commanders/the-ur-dragon/core/expensive" - QStringList parts = cleanedUrl.split('/', Qt::SkipEmptyParts); - - if (parts.size() < 2) { - return; - } - - QString commanderName = parts[1]; - QString gameChangerOpt, budgetOpt; - - // Define valid sets - QSet validGameChangers = {"exhibition", "core", "upgraded", "optimized", "cedh"}; - QSet validBudgets = {"budget", "expensive"}; - - // Check remaining parts after commander - for (int i = 2; i < parts.size(); ++i) { - QString part = parts[i].toLower(); - if (validGameChangers.contains(part)) { - gameChangerOpt = part; - } else if (validBudgets.contains(part)) { - budgetOpt = part; - } - } - - if (!budgetButtons.contains(budgetOpt)) { - budgetOpt.clear(); - } - - selectedBudget = budgetOpt; - - updateOptionButtonSelection(budgetButtons, selectedBudget); -} - -void EdhrecCommanderApiResponseBudgetNavigationWidget::updateOptionButtonSelection( - QMap &buttons, - const QString &selectedKey) -{ - for (auto it = buttons.begin(); it != buttons.end(); ++it) { - it.value()->setStyleSheet(it.key() == selectedKey - ? "background-color: lightblue; font-weight: bold; font-size: 24px;" - : "font-size: 24px"); - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h deleted file mode 100644 index 666edba16..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H -#define COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H - -#include -#include -#include -#include -#include - -class EdhrecCommanderApiResponseBudgetNavigationWidget : public QWidget -{ - Q_OBJECT -public: - explicit EdhrecCommanderApiResponseBudgetNavigationWidget(QWidget *parent, const QString &baseUrl); - void retranslateUi(); - void applyOptionsFromUrl(const QString &url); - QString getSelectedBudget() const - { - return selectedBudget; - } - -signals: - void requestNavigation(); - -private: - QGridLayout *layout; - QLabel *budgetLabel; - - QStringList budgetOptions = {"", "budget", "expensive"}; - QString selectedBudget; - - QMap budgetButtons; - - void updateOptionButtonSelection(QMap &buttons, const QString &selectedKey); -}; - -#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp deleted file mode 100644 index 230858d6c..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "edhrec_commander_api_response_display_widget.h" - -#include "../../../../../cards/card_info_picture_widget.h" -#include "../../api_response/commander/edhrec_commander_api_response.h" -#include "../cards/edhrec_api_response_card_list_display_widget.h" -#include "edhrec_api_response_commander_details_display_widget.h" - -#include -#include -#include -#include -#include - -EdhrecCommanderApiResponseDisplayWidget::EdhrecCommanderApiResponseDisplayWidget(QWidget *parent, - EdhrecCommanderApiResponse response, - QString baseUrl) - : QWidget(parent) -{ - layout = new QHBoxLayout(this); - setLayout(layout); - - cardDisplayLayout = new QVBoxLayout(this); - - // Create a QSplitter to hold the ListView and ScrollArea holding CardListdisplayWidgets side by side - auto splitter = new QSplitter(this); - splitter->setOrientation(Qt::Horizontal); - - auto listView = new QListView(splitter); - listView->setMinimumWidth(50); - listView->setMaximumWidth(150); - auto listModel = new QStringListModel(this); - QStringList widgetNames; - - // Add commander details - auto commanderPicture = new EdhrecCommanderResponseCommanderDetailsDisplayWidget( - this, response.container.getCommanderDetails(), baseUrl); - cardDisplayLayout->addWidget(commanderPicture); - widgetNames.append("Commander Details"); - - // Add card list widgets - auto edhrec_commander_api_response_card_lists = response.container.getCardlists(); - for (const EdhrecApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) { - auto cardListDisplayWidget = new EdhrecApiResponseCardListDisplayWidget(this, card_list); - cardDisplayLayout->addWidget(cardListDisplayWidget); - widgetNames.append(cardListDisplayWidget->getBannerText()); - } - - // Create a QScrollArea to hold the card display widgets - scrollArea = new QScrollArea(splitter); - scrollArea->setWidgetResizable(true); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - // Set the cardDisplayLayout inside the scroll area - auto scrollWidget = new QWidget(scrollArea); - scrollWidget->setLayout(cardDisplayLayout); - connect(splitter, &QSplitter::splitterMoved, this, &EdhrecCommanderApiResponseDisplayWidget::onSplitterChange); - scrollArea->setWidget(scrollWidget); - - // Configure the list view - listModel->setStringList(widgetNames); - listView->setModel(listModel); - listView->setEditTriggers(QAbstractItemView::NoEditTriggers); - - // Connect the list view to ensure the corresponding widget is visible - connect(listView, &QListView::clicked, this, [this](const QModelIndex &index) { - int widgetIndex = index.row(); - qDebug() << "clicked: " << widgetIndex; - auto targetWidget = cardDisplayLayout->itemAt(widgetIndex)->widget(); - if (targetWidget) { - qDebug() << "Found targetWidget" << targetWidget; - // Attempt to cast the parent to QScrollArea - auto scrollArea = qobject_cast(this->scrollArea); // Use the scroll area instance - if (scrollArea) { - qDebug() << "ScrollArea" << scrollArea; - scrollArea->ensureWidgetVisible(targetWidget); - } - } - }); - - // Add splitter to the main layout - splitter->addWidget(listView); - splitter->addWidget(scrollArea); - - layout->addWidget(splitter); -} - -void EdhrecCommanderApiResponseDisplayWidget::onSplitterChange() -{ - scrollArea->widget()->resize(scrollArea->size()); -} - -void EdhrecCommanderApiResponseDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - qDebug() << event->size(); - layout->invalidate(); - layout->activate(); - layout->update(); - if (scrollArea && scrollArea->widget()) { - scrollArea->widget()->resize(event->size()); - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.h deleted file mode 100644 index 1678e1380..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_display_widget.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file edhrec_commander_api_response_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_DISPLAY_WIDGET_H -#define EDHREC_COMMANDER_API_RESPONSE_DISPLAY_WIDGET_H - -#include "../../api_response/commander/edhrec_commander_api_response.h" - -#include -#include -#include - -class EdhrecCommanderApiResponseDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - explicit EdhrecCommanderApiResponseDisplayWidget(QWidget *parent, - EdhrecCommanderApiResponse response, - QString baseUrl); - void resizeEvent(QResizeEvent *event) override; - -public slots: - void onSplitterChange(); - -private: - QHBoxLayout *layout; - QVBoxLayout *cardDisplayLayout; - QScrollArea *scrollArea; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp deleted file mode 100644 index c42d2ed90..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "edhrec_commander_api_response_navigation_widget.h" - -#include "../../tab_edhrec_main.h" - -EdhrecCommanderApiResponseNavigationWidget::EdhrecCommanderApiResponseNavigationWidget( - QWidget *parent, - const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails, - QString baseUrl) - : QWidget(parent), commanderDetails(_commanderDetails) -{ - layout = new QGridLayout(this); - setLayout(layout); - - bracketNavigationWidget = new EdhrecCommanderApiResponseBracketNavigationWidget(this, baseUrl); - - connect(bracketNavigationWidget, &EdhrecCommanderApiResponseBracketNavigationWidget::requestNavigation, this, - &EdhrecCommanderApiResponseNavigationWidget::actRequestCommanderNavigation); - - budgetNavigationWidget = new EdhrecCommanderApiResponseBudgetNavigationWidget(this, baseUrl); - - connect(budgetNavigationWidget, &EdhrecCommanderApiResponseBudgetNavigationWidget::requestNavigation, this, - &EdhrecCommanderApiResponseNavigationWidget::actRequestCommanderNavigation); - - comboPushButton = new QPushButton(this); - comboPushButton->setMinimumHeight(84); - comboPushButton->setStyleSheet("font-size: 24px"); - averageDeckPushButton = new QPushButton(this); - averageDeckPushButton->setMinimumHeight(84); - averageDeckPushButton->setStyleSheet("font-size: 24px"); - - layout->addWidget(comboPushButton, 0, 0, 1, 1); - layout->addWidget(averageDeckPushButton, 0, 1, 1, 1); - - layout->addWidget(bracketNavigationWidget, 1, 0, 1, 2); - layout->addWidget(budgetNavigationWidget, 2, 0, 1, 2); - - QWidget *currentParent = parentWidget(); - TabEdhRecMain *parentTab = nullptr; - - while (currentParent) { - if ((parentTab = qobject_cast(currentParent))) { - break; - } - currentParent = currentParent->parentWidget(); - } - - if (parentTab) { - connect(comboPushButton, &QPushButton::clicked, this, - &EdhrecCommanderApiResponseNavigationWidget::actRequestComboNavigation); - connect(averageDeckPushButton, &QPushButton::clicked, this, - &EdhrecCommanderApiResponseNavigationWidget::actRequestAverageDeckNavigation); - connect(this, &EdhrecCommanderApiResponseNavigationWidget::requestUrl, parentTab, - &TabEdhRecMain::actNavigatePage); - } - - retranslateUi(); -} - -void EdhrecCommanderApiResponseNavigationWidget::retranslateUi() -{ - comboPushButton->setText(tr("Combos")); - averageDeckPushButton->setText(tr("Average Deck")); -} - -QString EdhrecCommanderApiResponseNavigationWidget::addNavigationOptionsToUrl(QString baseUrl) -{ - if (!bracketNavigationWidget->getSelectedGameChanger().isEmpty()) { - baseUrl += "/" + bracketNavigationWidget->getSelectedGameChanger(); - } - if (!budgetNavigationWidget->getSelectedBudget().isEmpty()) { - baseUrl += "/" + budgetNavigationWidget->getSelectedBudget(); - } - return baseUrl; -} - -void EdhrecCommanderApiResponseNavigationWidget::actRequestCommanderNavigation() -{ - emit requestUrl(addNavigationOptionsToUrl("/commanders/" + commanderDetails.getSanitized())); -} - -void EdhrecCommanderApiResponseNavigationWidget::actRequestComboNavigation() -{ - emit requestUrl("/combos/" + commanderDetails.getSanitized()); -} - -void EdhrecCommanderApiResponseNavigationWidget::actRequestAverageDeckNavigation() -{ - emit requestUrl(addNavigationOptionsToUrl("/average-decks/" + commanderDetails.getSanitized())); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.h deleted file mode 100644 index 10dfa8223..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_navigation_widget.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file edhrec_commander_api_response_navigation_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_COMMANDER_API_RESPONSE_NAVIGATION_WIDGET_H -#define EDHREC_COMMANDER_API_RESPONSE_NAVIGATION_WIDGET_H - -#include "edhrec_api_response_commander_details_display_widget.h" -#include "edhrec_commander_api_response_bracket_navigation_widget.h" -#include "edhrec_commander_api_response_budget_navigation_widget.h" - -#include -#include -#include -#include - -class EdhrecCommanderApiResponseNavigationWidget : public QWidget -{ - Q_OBJECT -public: - explicit EdhrecCommanderApiResponseNavigationWidget( - QWidget *parent, - const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails, - QString baseUrl); - void retranslateUi(); - -public slots: - void actRequestCommanderNavigation(); - void actRequestComboNavigation(); - void actRequestAverageDeckNavigation(); -signals: - void requestUrl(QString url); - -private: - QGridLayout *layout; - - EdhrecCommanderApiResponseBracketNavigationWidget *bracketNavigationWidget; - EdhrecCommanderApiResponseBudgetNavigationWidget *budgetNavigationWidget; - - QPushButton *comboPushButton; - QPushButton *averageDeckPushButton; - - EdhrecCommanderApiResponseCommanderDetails commanderDetails; - - QString addNavigationOptionsToUrl(QString baseUrl); - QString buildComboUrl() const; -}; - -#endif // EDHREC_COMMANDER_API_RESPONSE_NAVIGATION_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp deleted file mode 100644 index ae07c9dc8..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "edhrec_top_cards_api_response_display_widget.h" - -#include "../../api_response/top_cards/edhrec_top_cards_api_response.h" -#include "../cards/edhrec_api_response_card_list_display_widget.h" - -EdhrecTopCardsApiResponseDisplayWidget::EdhrecTopCardsApiResponseDisplayWidget(QWidget *parent, - EdhrecTopCardsApiResponse response) - : QWidget(parent) -{ - layout = new QHBoxLayout(this); - setLayout(layout); - - cardDisplayLayout = new QVBoxLayout(this); - - // Add card list widgets - auto edhrec_commander_api_response_card_lists = response.container.getCardlists(); - for (const EdhrecApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) { - auto cardListDisplayWidget = new EdhrecApiResponseCardListDisplayWidget(this, card_list); - cardDisplayLayout->addWidget(cardListDisplayWidget); - } - - // Create a QScrollArea to hold the card display widgets - scrollArea = new QScrollArea(this); - scrollArea->setWidgetResizable(true); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - // Set the cardDisplayLayout inside the scroll area - auto scrollWidget = new QWidget(scrollArea); - scrollWidget->setLayout(cardDisplayLayout); - scrollArea->setWidget(scrollWidget); - - layout->addWidget(scrollArea); -} - -void EdhrecTopCardsApiResponseDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - layout->invalidate(); - layout->activate(); - layout->update(); - if (scrollArea && scrollArea->widget()) { - scrollArea->widget()->resize(event->size()); - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.h deleted file mode 100644 index e2748bf10..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_cards/edhrec_top_cards_api_response_display_widget.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file edhrec_top_cards_api_response_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_TOP_CARDS_API_RESPONSE_DISPLAY_WIDGET_H -#define EDHREC_TOP_CARDS_API_RESPONSE_DISPLAY_WIDGET_H - -#include "../../api_response/top_cards/edhrec_top_cards_api_response.h" - -#include -#include -#include -#include - -class EdhrecTopCardsApiResponseDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - explicit EdhrecTopCardsApiResponseDisplayWidget(QWidget *parent, EdhrecTopCardsApiResponse response); - void resizeEvent(QResizeEvent *event) override; - -private: - QHBoxLayout *layout; - QVBoxLayout *cardDisplayLayout; - QScrollArea *scrollArea; -}; - -#endif // EDHREC_TOP_CARDS_API_RESPONSE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp deleted file mode 100644 index 13f54a979..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "edhrec_top_commanders_api_response_display_widget.h" - -#include "../../api_response/top_commanders/edhrec_top_commanders_api_response.h" -#include "../cards/edhrec_api_response_card_list_display_widget.h" - -EdhrecTopCommandersApiResponseDisplayWidget::EdhrecTopCommandersApiResponseDisplayWidget( - QWidget *parent, - EdhrecTopCommandersApiResponse response) - : QWidget(parent) -{ - layout = new QHBoxLayout(this); - setLayout(layout); - - cardDisplayLayout = new QVBoxLayout(this); - - // Add card list widgets - auto edhrec_commander_api_response_card_lists = response.container.getCardlists(); - for (const EdhrecApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) { - auto cardListDisplayWidget = new EdhrecApiResponseCardListDisplayWidget(this, card_list); - cardDisplayLayout->addWidget(cardListDisplayWidget); - } - - // Create a QScrollArea to hold the card display widgets - scrollArea = new QScrollArea(this); - scrollArea->setWidgetResizable(true); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - // Set the cardDisplayLayout inside the scroll area - auto scrollWidget = new QWidget(scrollArea); - scrollWidget->setLayout(cardDisplayLayout); - scrollArea->setWidget(scrollWidget); - - layout->addWidget(scrollArea); -} - -void EdhrecTopCommandersApiResponseDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - qDebug() << event->size(); - layout->invalidate(); - layout->activate(); - layout->update(); - if (scrollArea && scrollArea->widget()) { - scrollArea->widget()->resize(event->size()); - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.h deleted file mode 100644 index 766518c02..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_commander/edhrec_top_commanders_api_response_display_widget.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file edhrec_top_commanders_api_response_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_TOP_COMMANDERS_API_RESPONSE_DISPLAY_WIDGET_H -#define EDHREC_TOP_COMMANDERS_API_RESPONSE_DISPLAY_WIDGET_H - -#include "../../api_response/top_commanders/edhrec_top_commanders_api_response.h" - -#include -#include -#include -#include - -class EdhrecTopCommandersApiResponseDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - explicit EdhrecTopCommandersApiResponseDisplayWidget(QWidget *parent, EdhrecTopCommandersApiResponse response); - void resizeEvent(QResizeEvent *event) override; - -private: - QHBoxLayout *layout; - QVBoxLayout *cardDisplayLayout; - QScrollArea *scrollArea; -}; - -#endif // EDHREC_TOP_COMMANDERS_API_RESPONSE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp deleted file mode 100644 index 91a1ce3fa..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "edhrec_top_tags_api_response_display_widget.h" - -#include "../../api_response/top_tags/edhrec_top_tags_api_response.h" -#include "../cards/edhrec_api_response_card_list_display_widget.h" - -EdhrecTopTagsApiResponseDisplayWidget::EdhrecTopTagsApiResponseDisplayWidget(QWidget *parent, - EdhrecTopTagsApiResponse response) - : QWidget(parent) -{ - layout = new QHBoxLayout(this); - setLayout(layout); - - cardDisplayLayout = new QVBoxLayout(this); - - // Add card list widgets - auto edhrec_commander_api_response_card_lists = response.container.getCardlists(); - for (const EdhrecApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) { - auto cardListDisplayWidget = new EdhrecApiResponseCardListDisplayWidget(this, card_list); - cardDisplayLayout->addWidget(cardListDisplayWidget); - } - - // Create a QScrollArea to hold the card display widgets - scrollArea = new QScrollArea(this); - scrollArea->setWidgetResizable(true); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - // Set the cardDisplayLayout inside the scroll area - auto scrollWidget = new QWidget(scrollArea); - scrollWidget->setLayout(cardDisplayLayout); - scrollArea->setWidget(scrollWidget); - - layout->addWidget(scrollArea); -} - -void EdhrecTopTagsApiResponseDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - layout->invalidate(); - layout->activate(); - layout->update(); - if (scrollArea && scrollArea->widget()) { - scrollArea->widget()->resize(event->size()); - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.h deleted file mode 100644 index 64228b85d..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file edhrec_top_tags_api_response_display_widget.h - * @ingroup ApiResponseDisplayWidgets - * @brief TODO: Document this. - */ - -#ifndef EDHREC_TOP_TAGS_API_RESPONSE_DISPLAY_WIDGET_H -#define EDHREC_TOP_TAGS_API_RESPONSE_DISPLAY_WIDGET_H - -#include "../../api_response/top_tags/edhrec_top_tags_api_response.h" - -#include -#include -#include - -class EdhrecTopTagsApiResponseDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - explicit EdhrecTopTagsApiResponseDisplayWidget(QWidget *parent, EdhrecTopTagsApiResponse response); - void resizeEvent(QResizeEvent *event) override; - -private: - QHBoxLayout *layout; - QVBoxLayout *cardDisplayLayout; - QScrollArea *scrollArea; -}; - -#endif // EDHREC_TOP_TAGS_API_RESPONSE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp deleted file mode 100644 index 10389f4eb..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "tab_edhrec.h" - -#include "api_response/commander/edhrec_commander_api_response.h" -#include "display/commander/edhrec_commander_api_response_display_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -TabEdhRec::TabEdhRec(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor) -{ - networkManager = new QNetworkAccessManager(this); - networkManager->setTransferTimeout(); // Use Qt's default timeout - networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy); - connect(networkManager, &QNetworkAccessManager::finished, this, &TabEdhRec::processApiJson); -} - -void TabEdhRec::retranslateUi() -{ -} - -void TabEdhRec::setCard(CardInfoPtr _cardToQuery, bool isCommander) -{ - cardToQuery = _cardToQuery; - - if (!cardToQuery) { - qDebug() << "Invalid card information provided."; - return; - } - - QString cardName = cardToQuery->getName(); - QString formattedName = cardName.toLower().replace(" ", "-").remove(QRegularExpression("[^a-z0-9\\-]")); - - QString url; - if (isCommander) { - url = QString("https://json.edhrec.com/pages/commanders/%1.json").arg(formattedName); - } else { - url = QString("https://json.edhrec.com/pages/card/%1.json").arg(formattedName); - } - - QNetworkRequest request{QUrl(url)}; - - networkManager->get(request); -} - -void TabEdhRec::processApiJson(QNetworkReply *reply) -{ - if (reply->error() != QNetworkReply::NoError) { - qDebug() << "Network error occurred:" << reply->errorString(); - reply->deleteLater(); - return; - } - - QByteArray responseData = reply->readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData); - - if (!jsonDoc.isObject()) { - qDebug() << "Invalid JSON response received."; - reply->deleteLater(); - return; - } - - QJsonObject jsonObj = jsonDoc.object(); - - // qDebug() << jsonObj; - - EdhrecCommanderApiResponse deckData; - deckData.fromJson(jsonObj); - - displayWidget = new EdhrecCommanderApiResponseDisplayWidget(this, deckData, reply->url().toString()); - // flowWidget->addWidget(displayWidget); - setCentralWidget(displayWidget); - - reply->deleteLater(); - update(); -} - -void TabEdhRec::prettyPrintJson(const QJsonValue &value, int indentLevel) -{ - const QString indent(indentLevel * 2, ' '); // Adjust spacing as needed for pretty printing - - if (value.isObject()) { - QJsonObject obj = value.toObject(); - for (auto it = obj.begin(); it != obj.end(); ++it) { - qDebug().noquote() << indent + it.key() + ":"; - prettyPrintJson(it.value(), indentLevel + 1); - } - } else if (value.isArray()) { - QJsonArray array = value.toArray(); - for (int i = 0; i < array.size(); ++i) { - qDebug().noquote() << indent + QString("[%1]:").arg(i); - prettyPrintJson(array[i], indentLevel + 1); - } - } else if (value.isString()) { - qDebug().noquote() << indent + "\"" + value.toString() + "\""; - } else if (value.isDouble()) { - qDebug().noquote() << indent + QString::number(value.toDouble()); - } else if (value.isBool()) { - qDebug().noquote() << indent + (value.toBool() ? "true" : "false"); - } else if (value.isNull()) { - qDebug().noquote() << indent + "null"; - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h deleted file mode 100644 index b5ee8d2ca..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file tab_edhrec.h - * @ingroup Tabs - * @brief TODO: Document this. - */ - -#ifndef TAB_EDHREC_H -#define TAB_EDHREC_H - -#include "../../tab.h" -#include "display/commander/edhrec_commander_api_response_display_widget.h" - -#include -#include - -class TabEdhRec : public Tab -{ - Q_OBJECT -public: - explicit TabEdhRec(TabSupervisor *_tabSupervisor); - - void retranslateUi() override; - [[nodiscard]] QString getTabText() const override - { - auto cardName = cardToQuery.isNull() ? QString() : cardToQuery->getName(); - return tr("EDHREC: ") + cardName; - } - - QNetworkAccessManager *networkManager; - -public slots: - void processApiJson(QNetworkReply *reply); - void prettyPrintJson(const QJsonValue &value, int indentLevel); - void setCard(CardInfoPtr _cardToQuery, bool isCommander = false); - -private: - CardInfoPtr cardToQuery; - EdhrecCommanderApiResponseDisplayWidget *displayWidget; -}; - -#endif // TAB_EDHREC_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp deleted file mode 100644 index f861d8afd..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp +++ /dev/null @@ -1,391 +0,0 @@ -#include "tab_edhrec_main.h" - -#include "../../../../../client/settings/cache_settings.h" -#include "../../tab_supervisor.h" -#include "api_response/average_deck/edhrec_average_deck_api_response.h" -#include "api_response/commander/edhrec_commander_api_response.h" -#include "api_response/top_cards/edhrec_top_cards_api_response.h" -#include "api_response/top_commanders/edhrec_top_commanders_api_response.h" -#include "api_response/top_tags/edhrec_top_tags_api_response.h" -#include "display/commander/edhrec_commander_api_response_display_widget.h" -#include "display/top_cards/edhrec_top_cards_api_response_display_widget.h" -#include "display/top_commander/edhrec_top_commanders_api_response_display_widget.h" -#include "display/top_tags/edhrec_top_tags_api_response_display_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool canBeCommander(const CardInfoPtr &cardInfo) -{ - return ((cardInfo->getCardType().contains("Legendary", Qt::CaseInsensitive) && - cardInfo->getCardType().contains("Creature", Qt::CaseInsensitive))) || - cardInfo->getText().contains("can be your commander", Qt::CaseInsensitive); -} - -TabEdhRecMain::TabEdhRecMain(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor) -{ - networkManager = new QNetworkAccessManager(this); - networkManager->setTransferTimeout(); // Use Qt's default timeout - networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy); - connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *))); - - container = new QWidget(this); - mainLayout = new QVBoxLayout(container); - container->setLayout(mainLayout); - - navigationContainer = new QWidget(container); - navigationContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - navigationLayout = new QHBoxLayout(navigationContainer); - navigationLayout->setSpacing(5); - navigationContainer->setLayout(navigationLayout); - - cardsPushButton = new QPushButton(navigationContainer); - connect(cardsPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopCards); - topCommandersPushButton = new QPushButton(navigationContainer); - connect(topCommandersPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopCommanders); - tagsPushButton = new QPushButton(navigationContainer); - connect(tagsPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopTags); - - searchBar = new QLineEdit(this); - auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this); - auto displayModel = new CardDatabaseDisplayModel(this); - displayModel->setSourceModel(cardDatabaseModel); - auto *searchModel = new CardSearchModel(displayModel, this); - - auto *proxyModel = new CardCompleterProxyModel(this); - proxyModel->setSourceModel(searchModel); - proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - proxyModel->setFilterRole(Qt::DisplayRole); - - auto *completer = new QCompleter(proxyModel, this); - completer->setCompletionRole(Qt::DisplayRole); - completer->setCompletionMode(QCompleter::PopupCompletion); - completer->setCaseSensitivity(Qt::CaseInsensitive); - completer->setFilterMode(Qt::MatchContains); - completer->setMaxVisibleItems(10); - searchBar->setCompleter(completer); - - // Update suggestions dynamically - connect(searchBar, &QLineEdit::textChanged, searchModel, &CardSearchModel::updateSearchResults); - connect(searchBar, &QLineEdit::textChanged, this, [=](const QString &text) { - // Ensure substring matching - QString pattern = ".*" + QRegularExpression::escape(text) + ".*"; - proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); - - if (!text.isEmpty()) { - completer->complete(); // Force the dropdown to appear - } - }); - - searchPushButton = new QPushButton(navigationContainer); - connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { doSearch(); }); - - settingsButton = new SettingsButtonWidget(this); - - cardSizeSlider = new CardSizeWidget(this, nullptr, SettingsCache::instance().getEDHRecCardSize()); - connect(cardSizeSlider, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(), - &SettingsCache::setEDHRecCardSize); - - settingsButton->addSettingsWidget(cardSizeSlider); - - navigationLayout->addWidget(cardsPushButton); - navigationLayout->addWidget(topCommandersPushButton); - navigationLayout->addWidget(tagsPushButton); - navigationLayout->addWidget(searchBar); - navigationLayout->addWidget(searchPushButton); - navigationLayout->addWidget(settingsButton); - - currentPageDisplay = new QWidget(container); - currentPageLayout = new QVBoxLayout(currentPageDisplay); - currentPageDisplay->setLayout(currentPageLayout); - - mainLayout->addWidget(navigationContainer); - mainLayout->addWidget(currentPageDisplay); - - // Ensure navigation stays at the top and currentPageDisplay takes remaining space - mainLayout->setStretch(0, 0); // navigationContainer gets minimum space - mainLayout->setStretch(1, 1); // currentPageDisplay expands as much as possible - - setCentralWidget(container); - - TabEdhRecMain::retranslateUi(); - - getTopCards(); -} - -void TabEdhRecMain::retranslateUi() -{ - cardsPushButton->setText(tr("&Cards")); - topCommandersPushButton->setText(tr("Top Commanders")); - tagsPushButton->setText(tr("Tags")); - searchBar->setPlaceholderText(tr("Search for a card ...")); - searchPushButton->setText(tr("Search")); -} - -void TabEdhRecMain::doSearch() -{ - CardInfoPtr searchedCard = CardDatabaseManager::query()->getCardInfo(searchBar->text()); - if (!searchedCard) { - return; - } - - setCard(searchedCard, canBeCommander(searchedCard)); -} - -void TabEdhRecMain::setCard(CardInfoPtr _cardToQuery, bool isCommander) -{ - cardToQuery = _cardToQuery; - - if (!cardToQuery) { - qDebug() << "Invalid card information provided."; - return; - } - - QString cardName = cardToQuery->getName(); - QString formattedName = cardName.toLower().replace(" ", "-").remove(QRegularExpression("[^a-z0-9\\-]")); - - QString url; - if (isCommander) { - url = QString("https://json.edhrec.com/pages/commanders/%1.json").arg(formattedName); - } else { - url = QString("https://json.edhrec.com/pages/cards/%1.json").arg(formattedName); - } - - QNetworkRequest request{QUrl(url)}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - - networkManager->get(request); -} - -void TabEdhRecMain::actNavigatePage(QString url) -{ - QNetworkRequest request{QUrl("https://json.edhrec.com/pages" + url + ".json")}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - - networkManager->get(request); -} - -void TabEdhRecMain::getTopCards() -{ - QNetworkRequest request{QUrl("https://json.edhrec.com/pages/top/year.json")}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - - networkManager->get(request); -} - -void TabEdhRecMain::getTopCommanders() -{ - QNetworkRequest request{QUrl("https://json.edhrec.com/pages/commanders/year.json")}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - - networkManager->get(request); -} - -void TabEdhRecMain::getTopTags() -{ - QNetworkRequest request{QUrl("https://json.edhrec.com/pages/tags.json")}; - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING)); - networkManager->get(request); -} - -void TabEdhRecMain::processApiJson(QNetworkReply *reply) -{ - if (reply->error() != QNetworkReply::NoError) { - qDebug() << "Network error occurred:" << reply->errorString(); - reply->deleteLater(); - return; - } - - QByteArray responseData = reply->readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData); - - if (!jsonDoc.isObject()) { - qDebug() << "Invalid JSON response received."; - reply->deleteLater(); - return; - } - - QJsonObject jsonObj = jsonDoc.object(); - - // Get the actual URL from the reply - QString responseUrl = reply->url().toString(); - - // Check if the response URL matches a commander request - if (responseUrl.startsWith("https://json.edhrec.com/pages/commanders/year.json")) { - processTopCommandersResponse(jsonObj); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/commanders/")) { - qInfo() << "Received top kek"; - processCommanderResponse(jsonObj, responseUrl); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/cards/")) { - processCommanderResponse(jsonObj); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/tags/")) { - processCommanderResponse(jsonObj); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/tags.json")) { - processTopTagsResponse(jsonObj); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/top/year.json")) { - processTopCardsResponse(jsonObj); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/combos/")) { - qInfo() << "Received combos"; - processCommanderResponse(jsonObj); - } else if (responseUrl.startsWith("https://json.edhrec.com/pages/average-decks/")) { - processAverageDeckResponse(jsonObj); - } else { - prettyPrintJson(jsonObj, 4); - } - - reply->deleteLater(); -} - -void TabEdhRecMain::processTopCardsResponse(QJsonObject reply) -{ - EdhrecTopCardsApiResponse deckData; - deckData.fromJson(reply); - - // **Remove previous page display to prevent stacking** - if (currentPageDisplay) { - mainLayout->removeWidget(currentPageDisplay); - delete currentPageDisplay; - currentPageDisplay = nullptr; - } - - // **Create new currentPageDisplay** - currentPageDisplay = new QWidget(container); - currentPageLayout = new QVBoxLayout(currentPageDisplay); - currentPageDisplay->setLayout(currentPageLayout); - - auto display = new EdhrecTopCardsApiResponseDisplayWidget(currentPageDisplay, deckData); - currentPageLayout->addWidget(display); - - mainLayout->addWidget(currentPageDisplay); - - // **Ensure layout stays correct** - mainLayout->setStretch(0, 0); // Keep navigationContainer at the top - mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space -} - -void TabEdhRecMain::processTopTagsResponse(QJsonObject reply) -{ - EdhrecTopTagsApiResponse deckData; - deckData.fromJson(reply); - - // **Remove previous page display to prevent stacking** - if (currentPageDisplay) { - mainLayout->removeWidget(currentPageDisplay); - delete currentPageDisplay; - currentPageDisplay = nullptr; - } - - // **Create new currentPageDisplay** - currentPageDisplay = new QWidget(container); - currentPageLayout = new QVBoxLayout(currentPageDisplay); - currentPageDisplay->setLayout(currentPageLayout); - - auto display = new EdhrecTopTagsApiResponseDisplayWidget(currentPageDisplay, deckData); - currentPageLayout->addWidget(display); - - mainLayout->addWidget(currentPageDisplay); - - // **Ensure layout stays correct** - mainLayout->setStretch(0, 0); // Keep navigationContainer at the top - mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space -} - -void TabEdhRecMain::processTopCommandersResponse(QJsonObject reply) -{ - EdhrecTopCommandersApiResponse deckData; - deckData.fromJson(reply); - - // **Remove previous page display to prevent stacking** - if (currentPageDisplay) { - mainLayout->removeWidget(currentPageDisplay); - delete currentPageDisplay; - currentPageDisplay = nullptr; - } - - // **Create new currentPageDisplay** - currentPageDisplay = new QWidget(container); - currentPageLayout = new QVBoxLayout(currentPageDisplay); - currentPageDisplay->setLayout(currentPageLayout); - - auto display = new EdhrecTopCommandersApiResponseDisplayWidget(currentPageDisplay, deckData); - currentPageLayout->addWidget(display); - - mainLayout->addWidget(currentPageDisplay); - - // **Ensure layout stays correct** - mainLayout->setStretch(0, 0); // Keep navigationContainer at the top - mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space -} - -void TabEdhRecMain::processCommanderResponse(QJsonObject reply, QString responseUrl) -{ - EdhrecCommanderApiResponse deckData; - deckData.fromJson(reply); - - // **Remove previous page display to prevent stacking** - if (currentPageDisplay) { - mainLayout->removeWidget(currentPageDisplay); - delete currentPageDisplay; - currentPageDisplay = nullptr; - } - - // **Create new currentPageDisplay** - currentPageDisplay = new QWidget(container); - currentPageLayout = new QVBoxLayout(currentPageDisplay); - currentPageDisplay->setLayout(currentPageLayout); - - auto display = new EdhrecCommanderApiResponseDisplayWidget(currentPageDisplay, deckData, responseUrl); - currentPageLayout->addWidget(display); - - mainLayout->addWidget(currentPageDisplay); - - // **Ensure layout stays correct** - mainLayout->setStretch(0, 0); // Keep navigationContainer at the top - mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space -} - -void TabEdhRecMain::processAverageDeckResponse(QJsonObject reply) -{ - EdhrecAverageDeckApiResponse deckData; - deckData.fromJson(reply); - tabSupervisor->openDeckInNewTab({deckData.deck.deck, {}}); -} - -void TabEdhRecMain::prettyPrintJson(const QJsonValue &value, int indentLevel) -{ - const QString indent(indentLevel * 2, ' '); // Adjust spacing as needed for pretty printing - - if (value.isObject()) { - QJsonObject obj = value.toObject(); - for (auto it = obj.begin(); it != obj.end(); ++it) { - qDebug().noquote() << indent + it.key() + ":"; - prettyPrintJson(it.value(), indentLevel + 1); - } - } else if (value.isArray()) { - QJsonArray array = value.toArray(); - for (int i = 0; i < array.size(); ++i) { - qDebug().noquote() << indent + QString("[%1]:").arg(i); - prettyPrintJson(array[i], indentLevel + 1); - } - } else if (value.isString()) { - qDebug().noquote() << indent + "\"" + value.toString() + "\""; - } else if (value.isDouble()) { - qDebug().noquote() << indent + QString::number(value.toDouble()); - } else if (value.isBool()) { - qDebug().noquote() << indent + (value.toBool() ? "true" : "false"); - } else if (value.isNull()) { - qDebug().noquote() << indent + "null"; - } -} diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.h deleted file mode 100644 index 04cf03fc1..000000000 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file tab_edhrec_main.h - * @ingroup Tabs - * @brief TODO: Document this. - */ - -#ifndef TAB_EDHREC_MAIN_H -#define TAB_EDHREC_MAIN_H - -#include "../../interface/widgets/cards/card_size_widget.h" -#include "../../interface/widgets/quick_settings/settings_button_widget.h" -#include "../../tab.h" -#include "display/commander/edhrec_commander_api_response_display_widget.h" - -#include -#include -#include -#include -#include - -class TabEdhRecMain : public Tab -{ - Q_OBJECT -public: - explicit TabEdhRecMain(TabSupervisor *_tabSupervisor); - - void retranslateUi() override; - void doSearch(); - [[nodiscard]] QString getTabText() const override - { - auto cardName = cardToQuery.isNull() ? QString() : cardToQuery->getName(); - return tr("EDHRec: ") + cardName; - } - - CardSizeWidget *getCardSizeSlider() const - { - return cardSizeSlider; - } - - QNetworkAccessManager *networkManager; - -public slots: - void processApiJson(QNetworkReply *reply); - void processCommanderResponse(QJsonObject reply, QString responseUrl = ""); - void processTopCardsResponse(QJsonObject reply); - void processTopTagsResponse(QJsonObject reply); - void processTopCommandersResponse(QJsonObject reply); - void processAverageDeckResponse(QJsonObject reply); - void prettyPrintJson(const QJsonValue &value, int indentLevel); - void setCard(CardInfoPtr _cardToQuery, bool isCommander = false); - void actNavigatePage(QString url); - void getTopCards(); - void getTopCommanders(); - void getTopTags(); - -private: - QWidget *container; - QWidget *navigationContainer; - QWidget *currentPageDisplay; - QVBoxLayout *mainLayout; - QHBoxLayout *navigationLayout; - QVBoxLayout *currentPageLayout; - QPushButton *cardsPushButton; - QPushButton *topCommandersPushButton; - QPushButton *tagsPushButton; - QLineEdit *searchBar; - QPushButton *searchPushButton; - SettingsButtonWidget *settingsButton; - CardSizeWidget *cardSizeSlider; - CardInfoPtr cardToQuery; - EdhrecCommanderApiResponseDisplayWidget *displayWidget; -}; - -#endif // TAB_EDHREC_MAIN_H diff --git a/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h b/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h index ab7a0bfc5..acd51e5cd 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h +++ b/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h @@ -2,7 +2,6 @@ #define WINDOW_DECKEDITOR_H #include "../../key_signals.h" -#include "../interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "abstract_tab_deck_editor.h" #include diff --git a/cockatrice/src/interface/widgets/tabs/tab_home.cpp b/cockatrice/src/interface/widgets/tabs/tab_home.cpp deleted file mode 100644 index 7a79b1785..000000000 --- a/cockatrice/src/interface/widgets/tabs/tab_home.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "tab_home.h" - -TabHome::TabHome(TabSupervisor *_tabSupervisor, AbstractClient *_client) : Tab(_tabSupervisor), client(_client) -{ - homeWidget = new HomeWidget(this, tabSupervisor); - setCentralWidget(homeWidget); -} - -void TabHome::retranslateUi() -{ -} diff --git a/cockatrice/src/interface/widgets/tabs/tab_home.h b/cockatrice/src/interface/widgets/tabs/tab_home.h deleted file mode 100644 index c40dfc269..000000000 --- a/cockatrice/src/interface/widgets/tabs/tab_home.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file tab_home.h - * @ingroup Tabs - * @brief TODO: Document this. - */ - -#ifndef TAB_HOME_H -#define TAB_HOME_H - -#include "../interface/widgets/general/home_widget.h" -#include "tab.h" - -#include - -class AbstractClient; - -class TabHome : public Tab -{ - Q_OBJECT -private: - AbstractClient *client; - HomeWidget *homeWidget; - -public: - TabHome(TabSupervisor *_tabSupervisor, AbstractClient *_client); - void retranslateUi() override; - [[nodiscard]] QString getTabText() const override - { - return tr("Home"); - } -}; - -#endif // TAB_HOME_H diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp index b10d615ff..57b252904 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp @@ -5,23 +5,16 @@ #include "../interface/widgets/server/user/user_list_manager.h" #include "../interface/widgets/server/user/user_list_widget.h" #include "../main.h" -#include "api/archidekt/tab_archidekt.h" -#include "api/edhrec/tab_edhrec_main.h" #include "tab_account.h" #include "tab_admin.h" #include "tab_deck_editor.h" #include "tab_deck_storage.h" #include "tab_game.h" -#include "tab_home.h" #include "tab_logs.h" #include "tab_message.h" #include "tab_replays.h" #include "tab_room.h" #include "tab_server.h" -#include "tab_visual_database_display.h" -#include "visual_deck_editor/tab_deck_editor_visual.h" -#include "visual_deck_editor/tab_deck_editor_visual_tab_widget.h" -#include "visual_deck_storage/tab_deck_storage_visual.h" #include #include @@ -104,9 +97,9 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/) } TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *parent) - : QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabVisualDeckStorage(nullptr), - tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr), tabReplays(nullptr), tabAdmin(nullptr), - tabLog(nullptr), isLocalGame(false) + : QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabServer(nullptr), + tabAccount(nullptr), tabDeckStorage(nullptr), tabReplays(nullptr), tabAdmin(nullptr), tabLog(nullptr), + isLocalGame(false) { setElideMode(Qt::ElideRight); setMovable(true); @@ -135,26 +128,6 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget * aTabDeckEditor = new QAction(this); connect(aTabDeckEditor, &QAction::triggered, this, [this] { addDeckEditorTab(LoadedDeck()); }); - aTabVisualDeckEditor = new QAction(this); - connect(aTabVisualDeckEditor, &QAction::triggered, this, [this] { addVisualDeckEditorTab(LoadedDeck()); }); - - aTabEdhRec = new QAction(this); - connect(aTabEdhRec, &QAction::triggered, this, [this] { addEdhrecMainTab(); }); - - aTabArchidekt = new QAction(this); - connect(aTabArchidekt, &QAction::triggered, this, [this] { addArchidektTab(); }); - - aTabHome = new QAction(this); - aTabHome->setCheckable(true); - connect(aTabHome, &QAction::triggered, this, &TabSupervisor::actTabHome); - - aTabVisualDeckStorage = new QAction(this); - aTabVisualDeckStorage->setCheckable(true); - connect(aTabVisualDeckStorage, &QAction::triggered, this, &TabSupervisor::actTabVisualDeckStorage); - - aTabVisualDatabaseDisplay = new QAction(this); - connect(aTabVisualDatabaseDisplay, &QAction::triggered, this, [this] { addVisualDatabaseDisplayTab(); }); - aTabServer = new QAction(this); aTabServer->setCheckable(true); connect(aTabServer, &QAction::triggered, this, &TabSupervisor::actTabServer); @@ -206,12 +179,6 @@ void TabSupervisor::retranslateUi() { // tab menu actions aTabDeckEditor->setText(tr("Deck Editor")); - aTabVisualDeckEditor->setText(tr("Visual Deck Editor")); - aTabEdhRec->setText(tr("EDHRec")); - aTabArchidekt->setText(tr("Archidekt")); - aTabHome->setText(tr("Home")); - aTabVisualDeckStorage->setText(tr("&Visual Deck Storage")); - aTabVisualDatabaseDisplay->setText(tr("Visual Database Display")); aTabServer->setText(tr("Server")); aTabAccount->setText(tr("Account")); aTabDeckStorage->setText(tr("Deck Storage")); @@ -258,10 +225,6 @@ void TabSupervisor::refreshShortcuts() { ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts(); aTabDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabDeckEditor")); - aTabVisualDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckEditor")); - - aTabHome->setShortcuts(shortcuts.getShortcut("Tabs/aTabHome")); - aTabVisualDeckStorage->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckStorage")); aTabServer->setShortcuts(shortcuts.getShortcut("Tabs/aTabServer")); aTabAccount->setShortcuts(shortcuts.getShortcut("Tabs/aTabAccount")); aTabDeckStorage->setShortcuts(shortcuts.getShortcut("Tabs/aTabDeckStorage")); @@ -324,12 +287,8 @@ static void checkAndTrigger(QAction *checkableAction, bool checked) */ void TabSupervisor::initStartupTabs() { - openTabHome(); - setCurrentWidget(tabHome); + openDeckInNewTab(LoadedDeck()); - if (SettingsCache::instance().getTabVisualDeckStorageOpen()) { - openTabVisualDeckStorage(); - } if (SettingsCache::instance().getTabDeckStorageOpen()) { openTabDeckStorage(); } @@ -389,13 +348,6 @@ void TabSupervisor::resetTabsMenu() { tabsMenu->clear(); tabsMenu->addAction(aTabDeckEditor); - tabsMenu->addAction(aTabVisualDeckEditor); - tabsMenu->addAction(aTabEdhRec); - tabsMenu->addAction(aTabArchidekt); - tabsMenu->addSeparator(); - tabsMenu->addAction(aTabHome); - tabsMenu->addAction(aTabVisualDeckStorage); - tabsMenu->addAction(aTabVisualDatabaseDisplay); tabsMenu->addAction(aTabDeckStorage); tabsMenu->addAction(aTabReplays); } @@ -506,51 +458,6 @@ void TabSupervisor::stop() userInfo = nullptr; } -void TabSupervisor::actTabHome(bool checked) -{ - if (checked && !tabHome) { - openTabHome(); - setCurrentWidget(tabHome); - } else if (!checked && tabHome) { - tabHome->closeRequest(); - } -} - -void TabSupervisor::openTabHome() -{ - tabHome = new TabHome(this, client); - myAddTab(tabHome, aTabHome); - connect(tabHome, &QObject::destroyed, this, [this] { - tabHome = nullptr; - aTabHome->setChecked(false); - }); - aTabHome->setChecked(true); -} - -void TabSupervisor::actTabVisualDeckStorage(bool checked) -{ - SettingsCache::instance().setTabVisualDeckStorageOpen(checked); - if (checked && !tabVisualDeckStorage) { - openTabVisualDeckStorage(); - setCurrentWidget(tabVisualDeckStorage); - } else if (checked && tabVisualDeckStorage) { - setCurrentWidget(tabVisualDeckStorage); - } else if (!checked && tabVisualDeckStorage) { - tabVisualDeckStorage->closeRequest(); - } -} - -void TabSupervisor::openTabVisualDeckStorage() -{ - tabVisualDeckStorage = new TabDeckStorageVisual(this); - myAddTab(tabVisualDeckStorage, aTabVisualDeckStorage); - connect(tabVisualDeckStorage, &QObject::destroyed, this, [this] { - tabVisualDeckStorage = nullptr; - aTabVisualDeckStorage->setChecked(false); - }); - aTabVisualDeckStorage->setChecked(true); -} - void TabSupervisor::actTabServer(bool checked) { SettingsCache::instance().setTabServerOpen(checked); @@ -850,20 +757,7 @@ void TabSupervisor::talkLeft(TabMessage *tab) */ void TabSupervisor::openDeckInNewTab(const LoadedDeck &deckToOpen) { - int type = SettingsCache::instance().getDefaultDeckEditorType(); - switch (type) { - case ClassicDeckEditor: - addDeckEditorTab(deckToOpen); - break; - case VisualDeckEditor: - addVisualDeckEditorTab(deckToOpen); - break; - default: - qCWarning(TabSupervisorLog) << "Unknown DeckEditorType [" << type - << "]; opening ClassicDeckEditor as fallback"; - addDeckEditorTab(deckToOpen); - break; - } + addDeckEditorTab(deckToOpen); } /** @@ -882,56 +776,6 @@ TabDeckEditor *TabSupervisor::addDeckEditorTab(const LoadedDeck &deckToOpen) return tab; } -TabDeckEditorVisual *TabSupervisor::addVisualDeckEditorTab(const LoadedDeck &deckToOpen) -{ - auto *tab = new TabDeckEditorVisual(this); - tab->openDeck(deckToOpen); - connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed); - connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addVisualDeckEditorTab); - myAddTab(tab); - deckEditorTabs.append(tab); - setCurrentWidget(tab); - return tab; -} - -TabEdhRecMain *TabSupervisor::addEdhrecMainTab() -{ - auto *tab = new TabEdhRecMain(this); - - myAddTab(tab); - setCurrentWidget(tab); - return tab; -} - -TabArchidekt *TabSupervisor::addArchidektTab() -{ - auto *tab = new TabArchidekt(this); - - myAddTab(tab); - setCurrentWidget(tab); - return tab; -} - -TabVisualDatabaseDisplay *TabSupervisor::addVisualDatabaseDisplayTab() -{ - auto *tab = new TabVisualDatabaseDisplay(this); - myAddTab(tab); - setCurrentWidget(tab); - return tab; -} - -TabEdhRec *TabSupervisor::addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander) -{ - auto *tab = new TabEdhRec(this); - if (cardToQuery) { - tab->setCard(cardToQuery, isCommander); - } - - myAddTab(tab); - setCurrentWidget(tab); - return tab; -} - void TabSupervisor::deckEditorClosed(AbstractTabDeckEditor *tab) { if (tab == currentWidget()) diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h index 0c4428f83..b8dff1c86 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h @@ -11,12 +11,6 @@ #include "../../deck_loader/deck_loader.h" #include "../interface/widgets/server/user/user_list_proxy.h" #include "abstract_tab_deck_editor.h" -#include "api/archidekt/tab_archidekt.h" -#include "api/edhrec/tab_edhrec.h" -#include "api/edhrec/tab_edhrec_main.h" -#include "tab_visual_database_display.h" -#include "visual_deck_editor/tab_deck_editor_visual.h" -#include "visual_deck_storage/tab_deck_storage_visual.h" #include #include @@ -97,7 +91,6 @@ private: QList localClients; QMenu *tabsMenu; TabHome *tabHome; - TabDeckStorageVisual *tabVisualDeckStorage; TabServer *tabServer; TabAccount *tabAccount; TabDeckStorage *tabDeckStorage; @@ -111,8 +104,7 @@ private: QList deckEditorTabs; bool isLocalGame; - QAction *aTabHome, *aTabDeckEditor, *aTabVisualDeckEditor, *aTabEdhRec, *aTabArchidekt, *aTabVisualDeckStorage, - *aTabVisualDatabaseDisplay, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog; + QAction *aTabDeckEditor, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog; int myAddTab(Tab *tab, QAction *manager = nullptr); void addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager); @@ -170,28 +162,19 @@ signals: public slots: void openDeckInNewTab(const LoadedDeck &deckToOpen); TabDeckEditor *addDeckEditorTab(const LoadedDeck &deckToOpen); - TabDeckEditorVisual *addVisualDeckEditorTab(const LoadedDeck &deckToOpen); - TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab(); - TabEdhRecMain *addEdhrecMainTab(); - TabArchidekt *addArchidektTab(); - TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false); void openReplay(GameReplay *replay); void switchToFirstAvailableNetworkTab(); void maximizeMainWindow(); - void actTabVisualDeckStorage(bool checked); void actTabReplays(bool checked); private slots: void refreshShortcuts(); - void actTabHome(bool checked); void actTabServer(bool checked); void actTabAccount(bool checked); void actTabDeckStorage(bool checked); void actTabAdmin(bool checked); void actTabLog(bool checked); - void openTabVisualDeckStorage(); - void openTabHome(); void openTabServer(); void openTabAccount(); void openTabDeckStorage(); diff --git a/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.cpp b/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.cpp deleted file mode 100644 index 5e8fb8670..000000000 --- a/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "tab_visual_database_display.h" - -#include "tab_deck_editor.h" - -TabVisualDatabaseDisplay::TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor) -{ - deckEditor = new TabDeckEditor(_tabSupervisor); - deckEditor->setHidden(true); - visualDatabaseDisplayWidget = new VisualDatabaseDisplayWidget( - this, deckEditor, deckEditor->cardDatabaseDockWidget->databaseDisplayWidget->databaseModel, - deckEditor->cardDatabaseDockWidget->databaseDisplayWidget->databaseDisplayModel); - - setCentralWidget(visualDatabaseDisplayWidget); - - TabVisualDatabaseDisplay::retranslateUi(); -} - -void TabVisualDatabaseDisplay::retranslateUi() -{ -} diff --git a/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h b/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h deleted file mode 100644 index 4fe4d3e8f..000000000 --- a/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file tab_visual_database_display.h - * @ingroup Tabs - * @brief TODO: Document this. - */ - -#ifndef TAB_VISUAL_DATABASE_DISPLAY_H -#define TAB_VISUAL_DATABASE_DISPLAY_H - -#include "../interface/widgets/visual_database_display/visual_database_display_widget.h" -#include "tab.h" - -class TabVisualDatabaseDisplay : public Tab -{ - Q_OBJECT - -private: - TabDeckEditor *deckEditor; - VisualDatabaseDisplayWidget *visualDatabaseDisplayWidget; - -public: - TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor); - void retranslateUi() override; - [[nodiscard]] QString getTabText() const override - { - return visualDatabaseDisplayWidget->isVisualDisplayMode() ? tr("Visual Database Display") - : tr("Database Display"); - } -}; - -#endif // TAB_VISUAL_DATABASE_DISPLAY_H diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp deleted file mode 100644 index d03ac483b..000000000 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.cpp +++ /dev/null @@ -1,331 +0,0 @@ -#include "tab_deck_editor_visual.h" - -#include "../../../../client/settings/cache_settings.h" -#include "../../deck_editor/deck_state_manager.h" -#include "../../filters/filter_builder.h" -#include "../../interface/pixel_map_generator.h" -#include "../../interface/widgets/cards/card_info_frame_widget.h" -#include "../../interface/widgets/deck_analytics/deck_analytics_widget.h" -#include "../../interface/widgets/visual_deck_editor/visual_deck_editor_widget.h" -#include "../tab_deck_editor.h" -#include "../tab_supervisor.h" -#include "tab_deck_editor_visual_tab_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @brief Constructs the TabDeckEditorVisual instance. - * - * Sets up the central widget, tab container, menus, shortcuts, - * and restores the saved layout. - * @param _tabSupervisor Parent tab supervisor managing this tab. - */ -TabDeckEditorVisual::TabDeckEditorVisual(TabSupervisor *_tabSupervisor) : AbstractTabDeckEditor(_tabSupervisor) -{ - setObjectName("TabDeckEditorVisual"); - - createCentralFrame(); - createMenus(); - - installEventFilter(this); - - retranslateUi(); - connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts())); - refreshShortcuts(); - - loadLayout(); - cardDatabaseDockWidget->setHidden(true); -} - -/** @brief Creates the central frame containing the tab container. */ -void TabDeckEditorVisual::createCentralFrame() -{ - centralWidget = new QWidget(this); - centralWidget->setObjectName("centralWidget"); - - centralFrame = new QVBoxLayout; - centralWidget->setLayout(centralFrame); - - tabContainer = new TabDeckEditorVisualTabWidget( - centralWidget, this, deckStateManager->getModel(), cardDatabaseDockWidget->databaseDisplayWidget->databaseModel, - cardDatabaseDockWidget->databaseDisplayWidget->databaseDisplayModel); - - connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChanged, this, - &TabDeckEditorVisual::changeModelIndexAndCardInfo); - connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChangedDatabaseDisplay, this, - &AbstractTabDeckEditor::updateCard); - connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClicked, this, - &TabDeckEditorVisual::processMainboardCardClick); - connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClickedDatabaseDisplay, this, - &TabDeckEditorVisual::processCardClickDatabaseDisplay); - - centralFrame->addWidget(tabContainer); - setCentralWidget(centralWidget); - setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks); -} - -/** @brief Updates the visual deck, analytics, and sample hand after a deck change. */ -void TabDeckEditorVisual::onDeckChanged() -{ - AbstractTabDeckEditor::onDeckModified(); - tabContainer->visualDeckView->constructZoneWidgetsFromDeckListModel(); - tabContainer->deckAnalytics->updateDisplays(); - tabContainer->sampleHandWidget->setDeckModel(deckStateManager->getModel()); -} - -/** @brief Creates menus for deck editing and view options, including dock actions. */ -void TabDeckEditorVisual::createMenus() -{ - deckMenu = new DeckEditorMenu(this); - addTabMenu(deckMenu); - - viewMenu = new QMenu(this); - - registerDockWidget(viewMenu, cardInfoDockWidget, {250, 500}); - registerDockWidget(viewMenu, deckDockWidget, {250, 360}); - registerDockWidget(viewMenu, filterDockWidget, {250, 250}); - registerDockWidget(viewMenu, printingSelectorDockWidget, {525, 250}); - - viewMenu->addSeparator(); - - aResetLayout = viewMenu->addAction(QString()); - connect(aResetLayout, SIGNAL(triggered()), this, SLOT(restartLayout())); - viewMenu->addAction(aResetLayout); - - deckMenu->setSaveStatus(false); - addTabMenu(viewMenu); -} - -/** @brief Returns the tab text, prepending a mark if the deck has unsaved changes. */ -QString TabDeckEditorVisual::getTabText() const -{ - QString result = tr("Visual Deck: %1").arg(deckStateManager->getSimpleDeckName()); - if (deckStateManager->isModified()) - result.prepend("* "); - return result; -} - -/** @brief Updates card info and highlights the corresponding card in the deck view. */ -void TabDeckEditorVisual::changeModelIndexAndCardInfo(const ExactCard &activeCard) -{ - updateCard(activeCard); - changeModelIndexToCard(activeCard); -} - -/** @brief Selects the given card in the deck view, checking main and side zones. */ -void TabDeckEditorVisual::changeModelIndexToCard(const ExactCard &activeCard) -{ - QString cardName = activeCard.getName(); - QModelIndex index = deckStateManager->getModel()->findCard(cardName, DECK_ZONE_MAIN); - if (!index.isValid()) { - index = deckStateManager->getModel()->findCard(cardName, DECK_ZONE_SIDE); - } - if (!deckDockWidget->getSelectionModel()->hasSelection()) { - deckDockWidget->getSelectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); - } -} - -void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event, - CardInfoPictureWithTextOverlayWidget *instance, - const QString &zoneName) -{ - auto card = instance->getCard(); - - // Get the model index for the card - QModelIndex idx = deckStateManager->getModel()->findCard(card.getName(), zoneName); - if (!idx.isValid()) { - return; - } - - QItemSelectionModel *sel = deckDockWidget->getSelectionModel(); - - // Double click = swap - if (event->type() == QEvent::MouseButtonDblClick && event->button() == Qt::LeftButton && - !event->modifiers().testFlag(Qt::AltModifier)) { - deckStateManager->swapCardAtIndex(idx); - idx = deckStateManager->getModel()->findCard(card.getName(), zoneName); - sel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); - return; - } - - // Alt + Right-click = decrement - if (event->button() == Qt::RightButton && event->modifiers().testFlag(Qt::AltModifier)) { - if (zoneName == DECK_ZONE_MAIN) { - actDecrementCard(card); - } else { - actDecrementCardFromSideboard(card); - } - // Keep selection intact. - return; - } - - // Alt + Left click = increment - if (event->button() == Qt::LeftButton && event->modifiers().testFlag(Qt::AltModifier)) { - if (zoneName == DECK_ZONE_MAIN) { - actAddCard(card); - } else { - actAddCardToSideboard(card); - } - // Keep selection intact. - return; - } - - // Normal selection behavior - if (event->button() == Qt::LeftButton) { - Qt::KeyboardModifiers mods = event->modifiers(); - QItemSelectionModel::SelectionFlags flags; - - if (mods.testFlag(Qt::ControlModifier)) { - // CTRL + click = toggle selection - flags = QItemSelectionModel::Toggle; - } else if (mods.testFlag(Qt::ShiftModifier)) { - // SHIFT + click = select range - QModelIndex anchor = sel->currentIndex(); - if (!anchor.isValid()) { - anchor = idx; - } - - QItemSelection range(anchor, idx); - sel->select(range, QItemSelectionModel::SelectCurrent); - sel->setCurrentIndex(idx, QItemSelectionModel::NoUpdate); - return; - } else { - // Normal click = clear selection, select this, set current - deckDockWidget->deckView->setCurrentIndex(idx); - deckDockWidget->deckView->scrollTo(idx); - return; - } - - sel->setCurrentIndex(idx, flags); - } -} - -/** @brief Handles clicks on cards in the database display. */ -void TabDeckEditorVisual::processCardClickDatabaseDisplay(QMouseEvent *event, - CardInfoPictureWithTextOverlayWidget *instance) -{ - if (event->button() == Qt::LeftButton) { - actAddCard(instance->getCard()); - } else if (event->button() == Qt::RightButton) { - actDecrementCard(instance->getCard()); - } else if (event->button() == Qt::MiddleButton) { - deckDockWidget->actRemoveCard(); - } -} - -/** @brief Performs "Save Deck As..." while temporarily disabling the search bar. */ -bool TabDeckEditorVisual::actSaveDeckAs() -{ - tabContainer->visualDeckView->searchBar->setEnabled(false); - auto result = AbstractTabDeckEditor::actSaveDeckAs(); - tabContainer->visualDeckView->searchBar->setEnabled(true); - return result; -} - -/** @brief Shows the printing selector dock and updates it with the current card. */ -void TabDeckEditorVisual::showPrintingSelector() -{ - printingSelectorDockWidget->printingSelector->setCard(cardInfoDockWidget->cardInfo->getCard().getCardPtr()); - printingSelectorDockWidget->printingSelector->updateDisplay(); - printingSelectorDockWidget->setVisible(true); -} - -/** @brief Refreshes keyboard shortcuts for this tab from settings. */ -void TabDeckEditorVisual::refreshShortcuts() -{ - ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts(); - aResetLayout->setShortcuts(shortcuts.getShortcut("TabDeckEditorVisual/aResetLayout")); -} - -/** @brief Loads the saved layout or resets to default if no layout exists. */ -void TabDeckEditorVisual::loadLayout() -{ - LayoutsSettings &layouts = SettingsCache::instance().layouts(); - auto layoutState = layouts.getVisualDeckEditorLayoutState(); - if (layoutState.isNull()) { - restartLayout(); - } else { - restoreState(layoutState); - restoreGeometry(layouts.getVisualDeckEditorGeometry()); - } -} - -/** @brief Resets the layout to default positions and dock states. */ -void TabDeckEditorVisual::restartLayout() -{ - for (auto dockWidget : dockToActions.keys()) { - dockWidget->setFloating(false); - } - - deckDockWidget->setVisible(true); - cardInfoDockWidget->setVisible(true); - filterDockWidget->setVisible(false); - printingSelectorDockWidget->setVisible(true); - - setCentralWidget(centralWidget); - addDockWidget(Qt::RightDockWidgetArea, deckDockWidget); - addDockWidget(Qt::RightDockWidgetArea, cardInfoDockWidget); - addDockWidget(Qt::RightDockWidgetArea, filterDockWidget); - addDockWidget(Qt::RightDockWidgetArea, printingSelectorDockWidget); - - splitDockWidget(cardInfoDockWidget, printingSelectorDockWidget, Qt::Vertical); - splitDockWidget(cardInfoDockWidget, deckDockWidget, Qt::Horizontal); - splitDockWidget(cardInfoDockWidget, filterDockWidget, Qt::Horizontal); - - QTimer::singleShot(100, this, SLOT(freeDocksSize())); -} - -/** @brief Retranslates UI elements for localization. */ -void TabDeckEditorVisual::retranslateUi() -{ - deckMenu->setTitle(tr("&Visual Deck Editor")); - - cardInfoDockWidget->setWindowTitle(tr("Card Info")); - deckDockWidget->setWindowTitle(tr("Deck")); - filterDockWidget->setWindowTitle(tr("Filters")); - - viewMenu->setTitle(tr("&View")); - - dockToActions[cardInfoDockWidget].menu->setTitle(tr("Card Info")); - dockToActions[deckDockWidget].menu->setTitle(tr("Deck")); - dockToActions[filterDockWidget].menu->setTitle(tr("Filters")); - dockToActions[printingSelectorDockWidget].menu->setTitle(tr("Printing")); - - for (auto &actions : dockToActions.values()) { - actions.aVisible->setText(tr("Visible")); - actions.aFloating->setText(tr("Floating")); - } - - aResetLayout->setText(tr("Reset layout")); -} - -/** - * @brief Handles dock visibility, floating, and layout saving events. - * - * Keeps dock state in sync with menu items and saves layout when hidden. - */ -bool TabDeckEditorVisual::eventFilter(QObject *o, QEvent *e) -{ - if (o == this && e->type() == QEvent::Hide) { - LayoutsSettings &layouts = SettingsCache::instance().layouts(); - layouts.setVisualDeckEditorLayoutState(saveState()); - layouts.setVisualDeckEditorGeometry(saveGeometry()); - } - return false; -} diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h deleted file mode 100644 index 8a0677c9d..000000000 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef WINDOW_DECKEDITORVISUAL_H -#define WINDOW_DECKEDITORVISUAL_H - -#include "../tab.h" -#include "tab_deck_editor_visual_tab_widget.h" - -/** - * @class TabDeckEditorVisual - * @ingroup DeckEditorTabs - * @brief TabDeckEditorVisual provides a fully-featured deck editor tab with an enhanced visual interface. It extends - * AbstractTabDeckEditor. - * - * **Description:** - * TabDeckEditorVisual is a fully-featured deck editor tab with an enhanced visual interface. It extends - * AbstractTabDeckEditor and integrates multiple visual components such as a visual deck view, database display, - * deck analytics, and sample hand preview. - * - * **Purpose:** - * - * - Provides an intuitive, visual interface for deck editing. - * - Combines visual deck representation, card database browsing, and analytics into one tab. - * - Supports card interactions via clicks, hover events, and drag-and-drop-like behavior (not yet). - * - * **Dock Widgets and Components:** - * - * - TabDeckEditorVisualTabWidget — Container for visual sub-tabs (further described in @ref - * code_client_tabs_deck_editor_visual_tab). - * - VisualDeckEditorWidget — Displays and interacts with the deck visually. - * - VisualDatabaseDisplayWidget — Allows adding cards from the database visually. - * - DeckAnalyticsWidget — Displays deck statistics and analytics. - * - VisualDeckEditorSampleHandWidget — Simulates a sample hand from the deck. - * - DeckEditorCardInfoDockWidget — Shows detailed card info for hovered/selected cards. - * - DeckEditorDeckDockWidget — Displays deck zones and cards in a tree-view. - * - DeckEditorFilterDockWidget — Provides filtering options for card searches. - * - DeckEditorPrintingSelectorDockWidget — Selects specific card printings. - * - * **Key Methods:** - * - * - createCentralFrame() — Sets up the central widget and visual sub-tabs. - * - onDeckChanged() — Refreshes visual widgets when the deck is modified. - * - changeModelIndexAndCardInfo(const ExactCard &card) — Updates deck model selection and card info. - * - changeModelIndexToCard(const ExactCard &card) — Selects the card in the deck view. - * - processMainboardCardClick(QMouseEvent *event, ...) — Handles clicks on mainboard cards. - * - processCardClickDatabaseDisplay(QMouseEvent *event, ...) — Handles clicks on database cards. - * - actSaveDeckAs() — Overrides save action with temporary UI adjustments. - * - showPrintingSelector() — Opens the printing selector dock for the current card. - * - freeDocksSize() — Frees constraints on dock widget sizes. - * - refreshShortcuts() — Updates tab-specific shortcuts from settings. - * - loadLayout() — Loads saved layout or applies default if none exists. - * - restartLayout() — Resets dock positions, visibility, and floating states. - * - retranslateUi() — Updates text/UI elements for localization. - * - eventFilter(QObject *o, QEvent *e) — Syncs dock states with menu actions and saves layout. - */ -class TabDeckEditorVisual : public AbstractTabDeckEditor -{ - Q_OBJECT - -protected slots: - /** - * @brief Load the editor layout from settings. - */ - void loadLayout() override; - - /** - * @brief Reset and restart the layout to default. - */ - void restartLayout() override; - - /** - * @brief Refresh keyboard shortcuts for this tab. - */ - void refreshShortcuts() override; - - /** - * @brief Synchronize dock state with menu items. - * @param o The object sending the event. - * @param e The event being filtered. - * @return true if the event is handled, false otherwise. - */ - bool eventFilter(QObject *o, QEvent *e) override; - -protected: - TabDeckEditorVisualTabWidget *tabContainer; ///< Tab container holding different visual widgets. - - QVBoxLayout *centralFrame; ///< Layout for central widgets. - QVBoxLayout *searchAndDatabaseFrame; ///< Layout for search and database display. - QHBoxLayout *searchLayout; ///< Layout for search bar. - QDockWidget *searchAndDatabaseDock; ///< Dock widget for search/database display. - QWidget *centralWidget; ///< Central widget of the editor. - -public: - /** - * @brief Constructs a visual deck editor tab. - * @param _tabSupervisor Pointer to the tab supervisor managing this tab. - */ - explicit TabDeckEditorVisual(TabSupervisor *_tabSupervisor); - - /** - * @brief Retranslate UI strings (for i18n support). - */ - void retranslateUi() override; - - /** - * @brief Get the display text for the tab. - * @return Tab text with optional modification indicator. - */ - [[nodiscard]] QString getTabText() const override; - - /** - * @brief Update the currently selected card in the deck and UI. - * @param activeCard Card to display. - */ - void changeModelIndexAndCardInfo(const ExactCard &activeCard); - - /** - * @brief Change the deck view selection to a specific card. - * @param activeCard Card to select in the deck view. - */ - void changeModelIndexToCard(const ExactCard &activeCard); - - /** - * @brief Create the deck analytics dock widget. - */ - void createDeckAnalyticsDock(); - - /** - * @brief Setup menus for this visual deck editor. - */ - void createMenus() override; - - /** - * @brief Create search and database display frame. - */ - void createSearchAndDatabaseFrame(); - - /** - * @brief Create central frame for visual widgets. - */ - void createCentralFrame(); - -public slots: - /** - * @brief Refresh UI when the deck changes. - */ - void onDeckChanged() override; - - /** - * @brief Show the printing selector dock for the currently active card. - */ - void showPrintingSelector() override; - - /** - * @brief Handle card clicks in the mainboard visual deck. - * @param event Mouse event triggering the action. - * @param instance Widget representing the clicked card. - * @param zoneName Deck zone of the card. - */ - void processMainboardCardClick(QMouseEvent *event, - CardInfoPictureWithTextOverlayWidget *instance, - const QString &zoneName); - - /** - * @brief Handle card clicks in the database visual display. - * @param event Mouse event triggering the action. - * @param instance Widget representing the clicked card. - */ - void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance); - - /** - * @brief Save the deck under a new name. - * @return true if successful, false otherwise. - */ - bool actSaveDeckAs() override; -}; - -#endif diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp deleted file mode 100644 index 8a4d5903d..000000000 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "tab_deck_editor_visual_tab_widget.h" - -#include "../../interface/widgets/visual_database_display/visual_database_display_widget.h" -#include "../abstract_tab_deck_editor.h" - -/** - * @brief Constructs the TabDeckEditorVisualTabWidget. - * @param parent The parent QWidget. - * @param _deckEditor Pointer to the associated deck editor. - * @param _deckModel Pointer to the deck list model. - * @param _cardDatabaseModel Pointer to the card database model. - * @param _cardDatabaseDisplayModel Pointer to the card database display model. - * - * Initializes all sub-widgets (visual deck view, database display, deck analytics, - * sample hand) and sets up the tab layout and signal connections. - */ -TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent, - AbstractTabDeckEditor *_deckEditor, - DeckListModel *_deckModel, - CardDatabaseModel *_cardDatabaseModel, - CardDatabaseDisplayModel *_cardDatabaseDisplayModel) - : QTabWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), cardDatabaseModel(_cardDatabaseModel), - cardDatabaseDisplayModel(_cardDatabaseDisplayModel) -{ - this->setTabsClosable(true); // Enable tab closing - connect(this, &QTabWidget::tabCloseRequested, this, &TabDeckEditorVisualTabWidget::handleTabClose); - - layout = new QVBoxLayout(this); - setLayout(layout); - - visualDeckView = new VisualDeckEditorWidget(this, deckModel, _deckEditor->deckDockWidget->getSelectionModel()); - visualDeckView->setObjectName("visualDeckView"); - connect(visualDeckView, &VisualDeckEditorWidget::activeCardChanged, this, - &TabDeckEditorVisualTabWidget::onCardChanged); - connect(visualDeckView, &VisualDeckEditorWidget::cardClicked, this, - &TabDeckEditorVisualTabWidget::onCardClickedDeckEditor); - connect(visualDeckView, &VisualDeckEditorWidget::cardAdditionRequested, deckEditor, - &AbstractTabDeckEditor::actAddCard); - - visualDatabaseDisplay = - new VisualDatabaseDisplayWidget(this, deckEditor, _cardDatabaseModel, _cardDatabaseDisplayModel); - visualDatabaseDisplay->setObjectName("visualDatabaseView"); - connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardHoveredDatabaseDisplay, this, - &TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay); - connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardClickedDatabaseDisplay, this, - &TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay); - - statsAnalyzer = new DeckListStatisticsAnalyzer(this, deckModel); - statsAnalyzer->analyze(); - - deckAnalytics = new DeckAnalyticsWidget(this, statsAnalyzer); - deckAnalytics->setObjectName("deckAnalytics"); - - sampleHandWidget = new VisualDeckEditorSampleHandWidget(this, deckModel, statsAnalyzer); - - this->addNewTab(visualDeckView, tr("Visual Deck View")); - this->addNewTab(visualDatabaseDisplay, tr("Visual Database Display")); - this->addNewTab(deckAnalytics, tr("Deck Analytics")); - this->addNewTab(sampleHandWidget, tr("Sample Hand")); - - setTabsClosable(false); -} - -/** - * @brief Emits the cardChanged signal when a card is activated in the visual deck view. - * @param activeCard The card that was activated. - */ -void TabDeckEditorVisualTabWidget::onCardChanged(const ExactCard &activeCard) -{ - emit cardChanged(activeCard); -} - -/** - * @brief Emits the cardChangedDatabaseDisplay signal when a card is hovered in the database display. - * @param activeCard The card that was hovered. - */ -void TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay(const ExactCard &activeCard) -{ - emit cardChangedDatabaseDisplay(activeCard); -} - -/** - * @brief Emits the cardClicked signal when a card is clicked in the visual deck view. - * @param event The mouse event. - * @param instance The widget instance of the clicked card. - * @param zoneName The zone of the deck where the card is located. - */ -void TabDeckEditorVisualTabWidget::onCardClickedDeckEditor(QMouseEvent *event, - CardInfoPictureWithTextOverlayWidget *instance, - QString zoneName) -{ - emit cardClicked(event, instance, zoneName); -} - -/** - * @brief Emits the cardClickedDatabaseDisplay signal when a card is clicked in the database display. - * @param event The mouse event. - * @param instance The widget instance of the clicked card. - */ -void TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay(QMouseEvent *event, - CardInfoPictureWithTextOverlayWidget *instance) -{ - emit cardClickedDatabaseDisplay(event, instance); -} - -/** - * @brief Adds a new tab with the given widget and title. - * @param widget The widget to add. - * @param title The title of the tab. - */ -void TabDeckEditorVisualTabWidget::addNewTab(QWidget *widget, const QString &title) -{ - this->addTab(widget, title); -} - -/** - * @brief Removes the currently selected tab. - */ -void TabDeckEditorVisualTabWidget::removeCurrentTab() -{ - int currentIndex = this->currentIndex(); - if (currentIndex != -1) { - this->removeTab(currentIndex); - } -} - -/** - * @brief Sets the title of a tab at a given index. - * @param index The index of the tab. - * @param title The new title. - */ -void TabDeckEditorVisualTabWidget::setTabTitle(int index, const QString &title) -{ - if (index >= 0 && index < this->count()) { - this->setTabText(index, title); - } -} - -/** - * @brief Returns the currently selected tab widget. - * @return Pointer to the current tab widget. - */ -QWidget *TabDeckEditorVisualTabWidget::getCurrentTab() const -{ - return this->currentWidget(); -} - -/** - * @brief Returns the number of tabs in the tab widget. - * @return Number of tabs. - */ -int TabDeckEditorVisualTabWidget::getTabCount() const -{ - return this->count(); -} - -/** - * @brief Handles the closing of a tab. - * @param index The index of the tab to close. - * - * Removes the tab and deletes the widget to free memory. - */ -void TabDeckEditorVisualTabWidget::handleTabClose(int index) -{ - QWidget *tab = this->widget(index); - this->removeTab(index); - delete tab; -} diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h deleted file mode 100644 index 9468df425..000000000 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H -#define TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H - -#include "../../interface/widgets/deck_analytics/deck_analytics_widget.h" -#include "../../interface/widgets/printing_selector/printing_selector.h" -#include "../../interface/widgets/visual_database_display/visual_database_display_widget.h" -#include "../../interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h" -#include "../../interface/widgets/visual_deck_editor/visual_deck_editor_widget.h" -#include "../abstract_tab_deck_editor.h" - -#include -#include -#include - -/** - * @class TabDeckEditorVisualTabWidget - * @ingroup DeckEditorWidgets - * @brief Tab container for the visual deck editor. - * - * **Description:** - * TabDeckEditorVisualTabWidget is a QTabWidget container for visual deck editing sub-tabs. It organizes the visual - * deck, database display, deck analytics, and sample hand preview into separate tabs. - * - * **Purpose:** - * - Provides a tabbed interface for multiple visual components of the deck editor. - * - Handles forwarding of card events (hover, click, selection) to TabDeckEditorVisual. - * - Manages dynamic tab addition, removal, and title updates. - * - * **Contained Sub-Tabs and Widgets:** - * - VisualDeckEditorWidget — Visual deck interface with card interactions. - * - VisualDatabaseDisplayWidget — Displays card database visually and supports interactions. - * - DeckAnalyticsWidget — Shows deck statistics and metrics. - * - VisualDeckEditorSampleHandWidget — Simulates and displays sample hands. - * - * **Key Methods:** - * - addNewTab(QWidget *widget, const QString &title) — Adds a new tab to the container. - * - removeCurrentTab() — Removes the currently selected tab. - * - setTabTitle(int index, const QString &title) — Sets the title of a specific tab. - * - getCurrentTab() const — Returns the currently active tab widget. - * - getTabCount() const — Returns the number of tabs. - * - handleTabClose(int index) — Handles tab close requests and deletes the widget. - * - onCardChanged(const ExactCard &activeCard) — Emits card change signal from visual deck. - * - onCardChangedDatabaseDisplay(const ExactCard &activeCard) — Emits card change signal from database display. - * - onCardClickedDeckEditor(QMouseEvent *event, ...) — Emits click events from deck editor visual tab. - * - onCardClickedDatabaseDisplay(QMouseEvent *event, ...) — Emits click events from database display tab. - */ -class TabDeckEditorVisualTabWidget : public QTabWidget -{ - Q_OBJECT - -public: - /** - * @brief Construct the tab widget with required models. - * @param parent Parent widget. - * @param _deckEditor Pointer to the deck editor instance. - * @param _deckModel Deck list model. - * @param _cardDatabaseModel Card database model. - * @param _cardDatabaseDisplayModel Database display model. - */ - explicit TabDeckEditorVisualTabWidget(QWidget *parent, - AbstractTabDeckEditor *_deckEditor, - DeckListModel *_deckModel, - CardDatabaseModel *_cardDatabaseModel, - CardDatabaseDisplayModel *_cardDatabaseDisplayModel); - - /// Add a new tab with a widget and title. - void addNewTab(QWidget *widget, const QString &title); - - /// Remove the currently active tab. - void removeCurrentTab(); - - /// Set the title of a specific tab. - void setTabTitle(int index, const QString &title); - - /// Get the currently active tab widget. - [[nodiscard]] QWidget *getCurrentTab() const; - - /// Get the total number of tabs. - [[nodiscard]] int getTabCount() const; - - VisualDeckEditorWidget *visualDeckView; ///< Visual deck editor widget. - DeckListStatisticsAnalyzer *statsAnalyzer; - DeckAnalyticsWidget *deckAnalytics; ///< Deck analytics widget. - VisualDatabaseDisplayWidget *visualDatabaseDisplay; ///< Database display widget. - PrintingSelector *printingSelector; ///< Printing selector widget. - VisualDeckEditorSampleHandWidget *sampleHandWidget; ///< Sample hand simulation widget. - -public slots: - /** - * @brief Emitted when the active card changes in the deck view. - * @param activeCard New active card. - */ - void onCardChanged(const ExactCard &activeCard); - - /** - * @brief Emitted when the active card changes in the database display. - * @param activeCard New active card. - */ - void onCardChangedDatabaseDisplay(const ExactCard &activeCard); - - /** - * @brief Emitted when a card is clicked in the deck view. - * @param event Mouse event. - * @param instance Widget representing the clicked card. - * @param zoneName Deck zone of the card. - */ - void onCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName); - - /** - * @brief Emitted when a card is clicked in the database display. - * @param event Mouse event. - * @param instance Widget representing the clicked card. - */ - void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance); - -signals: - void cardChanged(const ExactCard &activeCard); - void cardChangedDatabaseDisplay(const ExactCard &activeCard); - void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName); - void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance); - -private: - QVBoxLayout *layout; ///< Layout for tabs and controls. - AbstractTabDeckEditor *deckEditor; ///< Reference to the deck editor. - DeckListModel *deckModel; ///< Deck list model. - CardDatabaseModel *cardDatabaseModel; ///< Card database model. - CardDatabaseDisplayModel *cardDatabaseDisplayModel; ///< Card database display model. - -private slots: - /** - * @brief Handle closing of a tab at a given index. - * @param index Index of the tab to close. - */ - void handleTabClose(int index); -}; - -#endif // TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp b/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp deleted file mode 100644 index 0cbcb641a..000000000 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "tab_deck_storage_visual.h" - -#include "../../interface/widgets/visual_deck_storage/visual_deck_storage_widget.h" -#include "../tab_supervisor.h" - -#include -#include - -TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor) - : Tab(_tabSupervisor), visualDeckStorageWidget(new VisualDeckStorageWidget(this)) -{ - connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::openDeckInNewTab); - connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this, - &TabDeckStorageVisual::actOpenLocalDeck); - connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, this, - &TabDeckStorageVisual::openDeckEditor); - - auto *widget = new QWidget(this); - auto *layout = new QVBoxLayout(widget); - widget->setLayout(layout); - this->setCentralWidget(widget); - layout->addWidget(visualDeckStorageWidget); -} - -void TabDeckStorageVisual::actOpenLocalDeck(const QString &filePath) -{ - std::optional deckOpt = - DeckLoader::loadFromFile(filePath, DeckFileFormat::getFormatFromName(filePath), true); - if (!deckOpt) { - QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(filePath)); - return; - } - - emit openDeckEditor(deckOpt.value()); -} diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.h b/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.h deleted file mode 100644 index ccf752e67..000000000 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file tab_deck_storage_visual.h - * @ingroup Tabs - * @brief TODO: Document this. - */ - -#ifndef TAB_DECK_STORAGE_VISUAL_H -#define TAB_DECK_STORAGE_VISUAL_H - -#include "../tab.h" - -struct LoadedDeck; -class AbstractClient; -class CommandContainer; -class DeckPreviewWidget; -class QFileSystemModel; -class QGroupBox; -class QToolBar; -class QTreeView; -class QTreeWidget; -class QTreeWidgetItem; -class Response; -class VisualDeckStorageWidget; - -class TabDeckStorageVisual final : public Tab -{ - Q_OBJECT -public: - explicit TabDeckStorageVisual(TabSupervisor *_tabSupervisor); - void retranslateUi() override - { - } - [[nodiscard]] QString getTabText() const override - { - return tr("Visual Deck Storage"); - } - -public slots: - void actOpenLocalDeck(const QString &filePath); - -signals: - void openDeckEditor(const LoadedDeck &deck); - -private: - VisualDeckStorageWidget *visualDeckStorageWidget; -}; - -#endif diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp deleted file mode 100644 index 57c6da762..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp +++ /dev/null @@ -1,252 +0,0 @@ -#include "visual_database_display_color_filter_widget.h" - -#include "../cards/additional_info/mana_symbol_widget.h" - -#include -#include - -/** - * This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter - * model. - * @param parent The Qt Widget that this widget will parent to - * @param _filterModel The filter model that this widget will manipulate - */ -VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(QWidget *parent, - FilterTreeModel *_filterModel) - : QWidget(parent), filterModel(_filterModel), layout(new QHBoxLayout(this)) -{ - setLayout(layout); - layout->setSpacing(5); - layout->setContentsMargins(0, 0, 0, 0); - - QString fullColorIdentity = "WUBRG"; - for (const QChar &color : fullColorIdentity) { - auto *manaSymbol = new ManaSymbolWidget(this, color, false, true); - manaSymbol->setFixedWidth(25); - - layout->addWidget(manaSymbol); - - // Connect the color toggled signal - connect(manaSymbol, &ManaSymbolWidget::colorToggled, this, - &VisualDatabaseDisplayColorFilterWidget::handleColorToggled); - } - - modeComboBox = new QComboBox(this); - layout->addWidget(modeComboBox); - - connect(modeComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, - &VisualDatabaseDisplayColorFilterWidget::updateFilterMode); - - connect(filterModel, &FilterTreeModel::layoutChanged, this, - [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel); }); - - // Call retranslateUi to set the initial text - retranslateUi(); -} - -void VisualDatabaseDisplayColorFilterWidget::retranslateUi() -{ - modeComboBox->blockSignals(true); - modeComboBox->clear(); - - modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch)); - modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes)); - modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude)); - - modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter")); - - // Restore current mode - const int index = modeComboBox->findData(QVariant::fromValue(currentMode)); - if (index >= 0) { - modeComboBox->setCurrentIndex(index); - } - - modeComboBox->blockSignals(false); -} - -void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active) -{ - if (active) { - addFilter(color); - } else { - removeFilter(color); - } -} - -void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color) -{ - QString colorString = color; - QString typeStr; - - // Remove previous filters - - QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); - QList matchingFilters; - - for (const CardFilter *filter : allColorFilters) { - if (filter->term() == color) { - matchingFilters.append(filter); - } - } - - for (const CardFilter *filter : matchingFilters) { - filterModel->removeFilter(filter); - } - - // Add actual filter - - switch (currentMode) { - case FilterMode::ExactMatch: - filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor)); - break; - - case FilterMode::Includes: - filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor)); - break; - - case FilterMode::IncludeExclude: - filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor)); - break; - } -} - -void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color) -{ - QString colorString = color; - - // Remove inclusion filters - QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); - QList matchingFilters; - - for (const CardFilter *filter : allColorFilters) { - if (filter->term() == color) { - matchingFilters.append(filter); - } - } - - for (const CardFilter *filter : matchingFilters) { - filterModel->removeFilter(filter); - } - - // Add exclusion filters if the mode demands it - switch (currentMode) { - case FilterMode::ExactMatch: - filterModel->addFilter( - new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor)); - break; - - case FilterMode::IncludeExclude: - filterModel->addFilter( - new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor)); - break; - - case FilterMode::Includes: - // No exclusion in Includes mode - break; - } -} - -void VisualDatabaseDisplayColorFilterWidget::updateFilterMode() -{ - const QVariant data = modeComboBox->currentData(); - if (!data.isValid()) { - return; - } - - currentMode = data.value(); - - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - - filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor); - - const QList manaSymbolWidgets = findChildren(); - - for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { - handleColorToggled(manaSymbolWidget->getSymbolChar(), manaSymbolWidget->isColorActive()); - } - - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); - emit filterModeChanged(currentMode); -} - -void VisualDatabaseDisplayColorFilterWidget::setManaSymbolActive(QChar color, bool active) -{ - QList manaSymbolWidgets = findChildren(); - - for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { - if (manaSymbolWidget->getSymbolChar() == color) { - manaSymbolWidget->setColorActive(active); - } - } -} - -QList VisualDatabaseDisplayColorFilterWidget::getActiveColors() -{ - QList activeColors; - QList manaSymbolWidgets = findChildren(); - - for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { - if (manaSymbolWidget->isColorActive()) { - activeColors.append(manaSymbolWidget->getSymbolChar()); - } - } - - return activeColors; -} - -void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel() -{ - QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); - - QList manaSymbolWidgets = findChildren(); - - for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { - bool found = false; - for (const CardFilter *filter : allColorFilters) { - if (manaSymbolWidget->getSymbolChar() == filter->term()) { - switch (currentMode) { - case FilterMode::ExactMatch: - switch (filter->type()) { - case CardFilter::Type::TypeAnd: - setManaSymbolActive(filter->term().at(0), true); - break; - default: - setManaSymbolActive(filter->term().at(0), false); - break; - } - break; - case FilterMode::Includes: - switch (filter->type()) { - case CardFilter::Type::TypeOr: - setManaSymbolActive(filter->term().at(0), true); - break; - default: - setManaSymbolActive(filter->term().at(0), false); - break; - } - break; - case FilterMode::IncludeExclude: - switch (filter->type()) { - case CardFilter::Type::TypeOr: - setManaSymbolActive(filter->term().at(0), true); - break; - default: - setManaSymbolActive(filter->term().at(0), false); - break; - } - break; - } - found = true; - } - } - - if (!found) { - setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false); - } - } -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h deleted file mode 100644 index 698ea9e97..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file visual_database_display_color_filter_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H - -#include "../../../filters/filter_tree_model.h" - -#include -#include -#include - -class VisualDatabaseDisplayColorFilterCircleWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDatabaseDisplayColorFilterCircleWidget(QChar color, QWidget *parent = nullptr); - void setColorActive(bool active); - bool isColorActive() const; - QChar getColorChar() const; - -signals: - void colorToggled(QChar color, bool active); - -private: - QChar colorChar; - bool isActive; - int circleDiameter; -}; - -enum class FilterMode -{ - ExactMatch, // Only selected colors are included, all others are excluded. - Includes, // Include selected colors (OR condition). - IncludeExclude // Include selected colors (OR) and exclude unselected colors (AND NOT). -}; - -Q_DECLARE_METATYPE(FilterMode) - -class VisualDatabaseDisplayColorFilterWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDatabaseDisplayColorFilterWidget(QWidget *parent, FilterTreeModel *filterModel); - void retranslateUi(); - -signals: - void filterModeChanged(FilterMode filterMode); - -private slots: - void handleColorToggled(QChar color, bool active); - void addFilter(QChar color); - void removeFilter(QChar color); - void updateFilterMode(); - void setManaSymbolActive(QChar color, bool active); - QList getActiveColors(); - void syncWithFilterModel(); - -private: - FilterTreeModel *filterModel; - QHBoxLayout *layout; - QComboBox *modeComboBox; - FilterMode currentMode = FilterMode::Includes; // Default mode -}; - -#endif // VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h deleted file mode 100644 index 5d9f7f944..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_button.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_BUTTON_H -#define COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_BUTTON_H - -#include - -const QString visualDatabaseDisplayFilterButtonStyle = QString(R"( - QPushButton { - background-color: palette(button); - color: palette(button-text); - padding: 5px 10px; - border-radius: 4px; - border: 1px solid palette(dark); - } - QPushButton:checked { - background-color: palette(highlight); - color: palette(highlighted-text); - border: 1px solid palette(shadow); - } -)"); - -#endif // COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_BUTTON_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp deleted file mode 100644 index 44b275afd..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "visual_database_display_filter_save_load_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "visual_database_filter_display_widget.h" - -#include -#include -#include -#include - -VisualDatabaseDisplayFilterSaveLoadWidget::VisualDatabaseDisplayFilterSaveLoadWidget(QWidget *parent, - FilterTreeModel *_filterModel) - : QWidget(parent), filterModel(_filterModel) -{ - setMinimumWidth(300); - setMaximumHeight(300); - - layout = new QVBoxLayout(this); - setLayout(layout); - - // Filter search input - searchInput = new QLineEdit(this); - layout->addWidget(searchInput); - - connect(searchInput, &QLineEdit::textChanged, this, &VisualDatabaseDisplayFilterSaveLoadWidget::applySearchFilter); - - // File list container - fileListWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - layout->addWidget(fileListWidget); - - // Input for filter filename - filenameInput = new QLineEdit(this); - layout->addWidget(filenameInput); - - // Save button - saveButton = new QPushButton(this); - layout->addWidget(saveButton); - // Disable save if empty - saveButton->setEnabled(false); - connect(filenameInput, &QLineEdit::textChanged, this, - [this](const QString &text) { saveButton->setEnabled(!text.trimmed().isEmpty()); }); - - connect(saveButton, &QPushButton::clicked, this, &VisualDatabaseDisplayFilterSaveLoadWidget::saveFilter); - - refreshFilterList(); // Populate the file list on startup - retranslateUi(); -} - -void VisualDatabaseDisplayFilterSaveLoadWidget::retranslateUi() -{ - searchInput->setPlaceholderText(tr("Search filter...")); - saveButton->setText(tr("Save Filter")); - saveButton->setToolTip(tr("Save all currently applied filters to a file")); - filenameInput->setPlaceholderText(tr("Enter filename...")); -} - -void VisualDatabaseDisplayFilterSaveLoadWidget::saveFilter() -{ - QString filename = filenameInput->text().trimmed(); - if (filename.isEmpty()) - return; - - QString filePath = SettingsCache::instance().getFiltersPath() + QDir::separator() + filename + ".json"; - - // Serialize the filter model to JSON - QJsonArray filtersArray; - QList cardFilters = filterModel->allFilters(); - - for (const CardFilter *filter : cardFilters) { - filtersArray.append(filter->toJson()); - } - - QJsonObject root; - root["filters"] = filtersArray; - - QFile file(filePath); - if (file.open(QIODevice::WriteOnly)) { - file.write(QJsonDocument(root).toJson(QJsonDocument::Indented)); - file.close(); - } - - filenameInput->clear(); - refreshFilterList(); // Update the file list -} - -void VisualDatabaseDisplayFilterSaveLoadWidget::loadFilter(const QString &filename) -{ - QString filePath = SettingsCache::instance().getFiltersPath() + QDir::separator() + filename; - - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) - return; - - QByteArray jsonData = file.readAll(); - file.close(); - - QJsonDocument doc = QJsonDocument::fromJson(jsonData); - if (!doc.isObject()) - return; - - QJsonObject root = doc.object(); - if (!root.contains("filters") || !root["filters"].isArray()) - return; - - QJsonArray filtersArray = root["filters"].toArray(); - - filterModel->clear(); - - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - for (const QJsonValue &value : filtersArray) { - if (value.isObject()) { - QJsonObject filterObj = value.toObject(); - CardFilter *filter = CardFilter::fromJson(filterObj); - if (filter) { - filterModel->addFilter(filter); - } - } - } - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); -} - -void VisualDatabaseDisplayFilterSaveLoadWidget::applySearchFilter(const QString &text) -{ - fileListWidget->clearLayout(); - - QString filter = text.trimmed(); - QStringList filtered = allFilterFiles; - - if (!filter.isEmpty()) { - filtered = filtered.filter(QRegularExpression(filter, QRegularExpression::CaseInsensitiveOption)); - } - - for (const QString &filename : filtered) { - FilterDisplayWidget *filterWidget = new FilterDisplayWidget(this, filename, filterModel); - fileListWidget->addWidget(filterWidget); - - connect(filterWidget, &FilterDisplayWidget::filterLoadRequested, this, - &VisualDatabaseDisplayFilterSaveLoadWidget::loadFilter); - - connect(filterWidget, &FilterDisplayWidget::filterDeleted, this, - &VisualDatabaseDisplayFilterSaveLoadWidget::refreshFilterList); - } -} - -void VisualDatabaseDisplayFilterSaveLoadWidget::refreshFilterList() -{ - fileListWidget->clearLayout(); - fileButtons.clear(); - - QDir dir(SettingsCache::instance().getFiltersPath()); - allFilterFiles = dir.entryList({"*.json"}, QDir::Files, QDir::Name); - - applySearchFilter(searchInput->text()); -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.h deleted file mode 100644 index bb5921a02..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file visual_database_display_filter_save_load_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_FILTER_SAVE_LOAD_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_FILTER_SAVE_LOAD_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -class VisualDatabaseDisplayFilterSaveLoadWidget : public QWidget -{ - Q_OBJECT -public: - explicit VisualDatabaseDisplayFilterSaveLoadWidget(QWidget *parent, FilterTreeModel *filterModel); - - void saveFilter(); - void loadFilter(const QString &filename); - void applySearchFilter(const QString &text); - void refreshFilterList(); - void deleteFilter(const QString &filename, QPushButton *deleteButton); - -public slots: - void retranslateUi(); - -private: - FilterTreeModel *filterModel; - - QVBoxLayout *layout; - QLineEdit *searchInput; - FlowWidget *fileListWidget; - QLineEdit *filenameInput; - QPushButton *saveButton; - QStringList allFilterFiles; - - QMap> fileButtons; -}; - -#endif // VISUAL_DATABASE_DISPLAY_FILTER_SAVE_LOAD_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp deleted file mode 100644 index 790ac771a..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp +++ /dev/null @@ -1,158 +0,0 @@ -#include "visual_database_display_filter_toolbar_widget.h" - -#include "visual_database_display_widget.h" - -#include - -VisualDatabaseDisplayFilterToolbarWidget::VisualDatabaseDisplayFilterToolbarWidget(VisualDatabaseDisplayWidget *_parent) - : QWidget(_parent), visualDatabaseDisplay(_parent) -{ - filterContainerLayout = new QHBoxLayout(this); - filterContainerLayout->setContentsMargins(11, 0, 11, 0); - filterContainerLayout->setSpacing(2); - setLayout(filterContainerLayout); - filterContainerLayout->setAlignment(Qt::AlignLeft); - - setMaximumHeight(80); - - connect(this, &VisualDatabaseDisplayFilterToolbarWidget::searchModelChanged, visualDatabaseDisplay, - &VisualDatabaseDisplayWidget::onSearchModelChanged); - - sortGroupBox = new QGroupBox(this); - filterGroupBox = new QGroupBox(this); - - auto scalePixmap = [](const QString &fileName) { return QIcon(QPixmap(fileName)).pixmap({20, 20}); }; - - sortByLabel = new QLabel(this); - sortByLabel->setPixmap(scalePixmap("theme:icons/sort_arrow_down")); - - filterByLabel = new QLabel(this); - filterByLabel->setPixmap(scalePixmap("theme:icons/filter")); - - sortColumnCombo = new QComboBox(this); - sortColumnCombo->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); - sortOrderCombo = new QComboBox(this); - sortOrderCombo->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents); - - sortOrderCombo->addItem("Ascending", Qt::AscendingOrder); - sortOrderCombo->addItem("Descending", Qt::DescendingOrder); - sortOrderCombo->view()->setMinimumWidth(sortOrderCombo->view()->sizeHintForColumn(0)); - sortOrderCombo->adjustSize(); - - // Populate columns dynamically from the model - for (int i = 0; i < visualDatabaseDisplay->getDatabaseDisplayModel()->columnCount(); ++i) { - QString header = visualDatabaseDisplay->getDatabaseDisplayModel()->headerData(i, Qt::Horizontal).toString(); - sortColumnCombo->addItem(header, i); - } - - sortColumnCombo->view()->setMinimumWidth(sortColumnCombo->view()->sizeHintForColumn(0)); - sortColumnCombo->adjustSize(); - - connect(sortColumnCombo, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { - int column = sortColumnCombo->currentData().toInt(); - Qt::SortOrder order = static_cast(sortOrderCombo->currentData().toInt()); - visualDatabaseDisplay->getDatabaseView()->sortByColumn(column, order); - - emit searchModelChanged(); - }); - - connect(sortOrderCombo, QOverload::of(&QComboBox::currentIndexChanged), this, [this]() { - int column = sortColumnCombo->currentData().toInt(); - Qt::SortOrder order = static_cast(sortOrderCombo->currentData().toInt()); - visualDatabaseDisplay->getDatabaseView()->sortByColumn(column, order); - - emit searchModelChanged(); - }); - - quickFilterSaveLoadWidget = new SettingsButtonWidget(this); - quickFilterSaveLoadWidget->setButtonIcon(QPixmap("theme:icons/floppy_disk")); - - quickFilterNameWidget = new SettingsButtonWidget(this); - quickFilterNameWidget->setButtonIcon(QPixmap("theme:icons/pen_to_square")); - - quickFilterMainTypeWidget = new SettingsButtonWidget(this); - quickFilterMainTypeWidget->setButtonIcon(QPixmap("theme:icons/circle_half_stroke")); - - quickFilterSubTypeWidget = new SettingsButtonWidget(this); - quickFilterSubTypeWidget->setButtonIcon(QPixmap("theme:icons/dragon")); - - quickFilterSetWidget = new SettingsButtonWidget(this); - quickFilterSetWidget->setButtonIcon(QPixmap("theme:icons/scroll")); - - quickFilterFormatLegalityWidget = new SettingsButtonWidget(this); - quickFilterFormatLegalityWidget->setButtonIcon(QPixmap("theme:icons/scale_balanced")); - - retranslateUi(); -} - -void VisualDatabaseDisplayFilterToolbarWidget::initialize() -{ - // create groupbox layouts - auto sortLayout = new QHBoxLayout(this); - sortLayout->setContentsMargins(0, 0, 0, 0); - sortLayout->setSpacing(0); - sortGroupBox->setLayout(sortLayout); - sortLayout->setAlignment(Qt::AlignLeft); - - auto filterLayout = new QHBoxLayout(this); - filterLayout->setContentsMargins(0, 0, 0, 0); - filterLayout->setSpacing(2); - filterGroupBox->setLayout(filterLayout); - filterLayout->setAlignment(Qt::AlignLeft); - - // create settings widgets - auto filterModel = visualDatabaseDisplay->getFilterModel(); - - saveLoadWidget = new VisualDatabaseDisplayFilterSaveLoadWidget(this, filterModel); - nameFilterWidget = - new VisualDatabaseDisplayNameFilterWidget(this, visualDatabaseDisplay->getDeckEditor(), filterModel); - mainTypeFilterWidget = new VisualDatabaseDisplayMainTypeFilterWidget(this, filterModel); - formatLegalityWidget = new VisualDatabaseDisplayFormatLegalityFilterWidget(this, filterModel); - subTypeFilterWidget = new VisualDatabaseDisplaySubTypeFilterWidget(this, filterModel); - setFilterWidget = new VisualDatabaseDisplaySetFilterWidget(this, filterModel); - - quickFilterSaveLoadWidget->addSettingsWidget(saveLoadWidget); - quickFilterNameWidget->addSettingsWidget(nameFilterWidget); - quickFilterMainTypeWidget->addSettingsWidget(mainTypeFilterWidget); - quickFilterSubTypeWidget->addSettingsWidget(subTypeFilterWidget); - quickFilterSetWidget->addSettingsWidget(setFilterWidget); - quickFilterFormatLegalityWidget->addSettingsWidget(formatLegalityWidget); - - // fill groupbox layouts - sortLayout->addWidget(sortByLabel); - sortLayout->addWidget(sortColumnCombo); - sortLayout->addWidget(sortOrderCombo); - - filterLayout->addWidget(filterByLabel); - filterLayout->addWidget(quickFilterNameWidget); - filterLayout->addWidget(quickFilterMainTypeWidget); - filterLayout->addWidget(quickFilterSubTypeWidget); - filterLayout->addWidget(quickFilterSetWidget); - filterLayout->addWidget(quickFilterFormatLegalityWidget); - - // put everything into main layout - filterContainerLayout->addWidget(sortGroupBox); - filterContainerLayout->addWidget(filterGroupBox); - filterContainerLayout->addStretch(); - filterContainerLayout->addWidget(quickFilterSaveLoadWidget); -} - -void VisualDatabaseDisplayFilterToolbarWidget::retranslateUi() -{ - sortByLabel->setToolTip(tr("Sort by")); - filterByLabel->setToolTip(tr("Filter by")); - - quickFilterSaveLoadWidget->setToolTip(tr("Save and load filters")); - quickFilterNameWidget->setToolTip(tr("Filter by exact card name")); - quickFilterMainTypeWidget->setToolTip(tr("Filter by card main-type")); - quickFilterSubTypeWidget->setToolTip(tr("Filter by card sub-type")); - quickFilterSetWidget->setToolTip(tr("Filter by set")); - quickFilterFormatLegalityWidget->setToolTip(tr("Filter by format legality")); - - quickFilterSaveLoadWidget->setButtonText(tr("Save/Load")); - quickFilterNameWidget->setButtonText(tr("Name")); - quickFilterMainTypeWidget->setButtonText(tr("Main Type")); - quickFilterSubTypeWidget->setButtonText(tr("Sub Type")); - quickFilterSetWidget->setButtonText(tr("Sets")); - quickFilterFormatLegalityWidget->setButtonText(tr("Formats")); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.h deleted file mode 100644 index 5cca5187a..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_TOOLBAR_WIDGET_H -#define COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_TOOLBAR_WIDGET_H - -#include "visual_database_display_filter_save_load_widget.h" -#include "visual_database_display_format_legality_filter_widget.h" -#include "visual_database_display_main_type_filter_widget.h" -#include "visual_database_display_name_filter_widget.h" -#include "visual_database_display_set_filter_widget.h" -#include "visual_database_display_sub_type_filter_widget.h" - -class VisualDatabaseDisplayWidget; - -class VisualDatabaseDisplayFilterToolbarWidget : public QWidget -{ - Q_OBJECT - -signals: - void searchModelChanged(); - -public: - explicit VisualDatabaseDisplayFilterToolbarWidget(VisualDatabaseDisplayWidget *parent); - void initialize(); - void retranslateUi(); - -private: - VisualDatabaseDisplayWidget *visualDatabaseDisplay; - - QGroupBox *sortGroupBox; - QLabel *sortByLabel; - QComboBox *sortColumnCombo, *sortOrderCombo; - - QGroupBox *filterGroupBox; - QLabel *filterByLabel; - - QHBoxLayout *filterContainerLayout; - SettingsButtonWidget *quickFilterSaveLoadWidget; - VisualDatabaseDisplayFilterSaveLoadWidget *saveLoadWidget; - SettingsButtonWidget *quickFilterNameWidget; - VisualDatabaseDisplayNameFilterWidget *nameFilterWidget; - SettingsButtonWidget *quickFilterMainTypeWidget; - VisualDatabaseDisplayMainTypeFilterWidget *mainTypeFilterWidget; - SettingsButtonWidget *quickFilterSubTypeWidget; - VisualDatabaseDisplaySubTypeFilterWidget *subTypeFilterWidget; - SettingsButtonWidget *quickFilterSetWidget; - VisualDatabaseDisplaySetFilterWidget *setFilterWidget; - SettingsButtonWidget *quickFilterFormatLegalityWidget; - VisualDatabaseDisplayFormatLegalityFilterWidget *formatLegalityWidget; -}; - -#endif // COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_TOOLBAR_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp deleted file mode 100644 index 633f07af7..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "visual_database_display_format_legality_filter_widget.h" - -#include "../../../filters/filter_tree_model.h" -#include "visual_database_display_filter_button.h" - -#include -#include -#include -#include -#include -#include - -VisualDatabaseDisplayFormatLegalityFilterWidget::VisualDatabaseDisplayFormatLegalityFilterWidget( - QWidget *parent, - FilterTreeModel *_filterModel) - : QWidget(parent), filterModel(_filterModel) -{ - allFormatsWithCount = CardDatabaseManager::query()->getAllFormatsWithCount(); - int maxValue = std::numeric_limits::min(); - for (int value : allFormatsWithCount) { - maxValue = std::max(maxValue, value); - } - setMinimumWidth(300); - setMaximumHeight(300); - - layout = new QVBoxLayout(this); - setLayout(layout); - layout->setContentsMargins(0, 1, 0, 1); - layout->setSpacing(1); - layout->setAlignment(Qt::AlignTop); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - layout->addWidget(flowWidget); - - // Create a container for the threshold control - auto *thresholdLayout = new QHBoxLayout(); - thresholdLayout->setContentsMargins(0, 0, 0, 0); - - thresholdLabel = new QLabel(this); - thresholdLayout->addWidget(thresholdLabel); - - // Create the spinbox - spinBox = new QSpinBox(this); - spinBox->setMinimum(1); - spinBox->setMaximum(maxValue); // Set the max value dynamically - spinBox->setValue(150); - thresholdLayout->addWidget(spinBox); - thresholdLayout->addStretch(); - - layout->addLayout(thresholdLayout); - - connect(spinBox, qOverload(&QSpinBox::valueChanged), this, - &VisualDatabaseDisplayFormatLegalityFilterWidget::updateFormatButtonsVisibility); - - // Create the toggle button for Exact Match/Includes mode - toggleButton = new QPushButton(this); - layout->addWidget(toggleButton); - connect(toggleButton, &QPushButton::clicked, this, - &VisualDatabaseDisplayFormatLegalityFilterWidget::updateFilterMode); - connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() { - QTimer::singleShot(100, this, &VisualDatabaseDisplayFormatLegalityFilterWidget::syncWithFilterModel); - }); - - createFormatButtons(); // Populate buttons initially - updateFilterMode(); // Initialize toggle button text - - retranslateUi(); -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::retranslateUi() -{ - thresholdLabel->setText(tr("Show formats with at least:")); - spinBox->setSuffix(tr(" cards")); - spinBox->setToolTip(tr("Do not display formats with less than this amount of cards in the database")); - toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)")); -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::createFormatButtons() -{ - // Iterate through main types and create buttons - for (auto it = allFormatsWithCount.begin(); it != allFormatsWithCount.end(); ++it) { - auto *button = new QPushButton(it.key(), flowWidget); - button->setCheckable(true); - button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle); - - flowWidget->addWidget(button); - formatButtons[it.key()] = button; - - // Connect toggle signal - connect(button, &QPushButton::toggled, this, - [this, mainType = it.key()](bool checked) { handleFormatToggled(mainType, checked); }); - } - updateFormatButtonsVisibility(); // Ensure visibility is updated initially -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::updateFormatButtonsVisibility() -{ - int threshold = spinBox->value(); // Get the current spinbox value - - // Iterate through buttons and hide/disable those below the threshold - for (auto it = formatButtons.begin(); it != formatButtons.end(); ++it) { - bool visible = allFormatsWithCount[it.key()] >= threshold; - it.value()->setVisible(visible); - it.value()->setEnabled(visible); - } -} - -int VisualDatabaseDisplayFormatLegalityFilterWidget::getMaxMainTypeCount() const -{ - int maxCount = 1; - for (auto it = allFormatsWithCount.begin(); it != allFormatsWithCount.end(); ++it) { - maxCount = qMax(maxCount, it.value()); - } - return maxCount; -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::handleFormatToggled(const QString &format, bool active) -{ - activeFormats[format] = active; - - if (formatButtons.contains(format)) { - formatButtons[format]->setChecked(active); - } - - updateFormatFilter(); -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::updateFormatFilter() -{ - // Clear existing filters related to main type - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - filterModel->clearFiltersOfType(CardFilter::Attr::AttrFormat); - - if (exactMatchMode) { - // Exact Match: Only selected main types are allowed - QSet selectedTypes; - for (const auto &type : activeFormats.keys()) { - if (activeFormats[type]) { - selectedTypes.insert(type); - } - } - - if (!selectedTypes.isEmpty()) { - // Require all selected types (TypeAnd) - for (const auto &type : selectedTypes) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrFormat)); - } - - // Exclude any other types (TypeAndNot) - for (const auto &type : formatButtons.keys()) { - if (!selectedTypes.contains(type)) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrFormat)); - } - } - } - } else { - // Default Includes Mode (TypeOr) - match any selected main types - for (const auto &type : activeFormats.keys()) { - if (activeFormats[type]) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrFormat)); - } - } - } - - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::updateFilterMode() -{ - exactMatchMode = !exactMatchMode; - toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); - updateFormatFilter(); -} - -void VisualDatabaseDisplayFormatLegalityFilterWidget::syncWithFilterModel() -{ - // Temporarily block signals for each button to prevent toggling while updating button states - for (auto it = formatButtons.begin(); it != formatButtons.end(); ++it) { - it.value()->blockSignals(true); - } - - // Uncheck all buttons - for (auto it = formatButtons.begin(); it != formatButtons.end(); ++it) { - it.value()->setChecked(false); - } - - // Get active filters for main types - QSet activeTypes; - for (const auto &filter : filterModel->getFiltersOfType(CardFilter::AttrFormat)) { - if (filter->type() == CardFilter::Type::TypeAnd) { - activeTypes.insert(filter->term()); - } - } - - // Check the buttons for active types - for (const auto &type : activeTypes) { - activeFormats[type] = true; - if (formatButtons.contains(type)) { - formatButtons[type]->setChecked(true); - } - } - - // Re-enable signal emissions for each button - for (auto it = formatButtons.begin(); it != formatButtons.end(); ++it) { - it.value()->blockSignals(false); - } - - // Update the visibility of buttons - updateFormatButtonsVisibility(); -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.h deleted file mode 100644 index 1b1a1382e..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef COCKATRICE_VISUAL_DATABASE_DISPLAY_FORMAT_LEGALITY_FILTER_WIDGET_H -#define COCKATRICE_VISUAL_DATABASE_DISPLAY_FORMAT_LEGALITY_FILTER_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -class VisualDatabaseDisplayFormatLegalityFilterWidget : public QWidget -{ - Q_OBJECT -public: - explicit VisualDatabaseDisplayFormatLegalityFilterWidget(QWidget *parent, FilterTreeModel *filterModel); - void retranslateUi(); - void createFormatButtons(); - void updateFormatButtonsVisibility(); - int getMaxMainTypeCount() const; - - void handleFormatToggled(const QString &format, bool active); - void updateFormatFilter(); - void updateFilterMode(); - void syncWithFilterModel(); - -private: - FilterTreeModel *filterModel; - QMap allFormatsWithCount; - - QVBoxLayout *layout; - FlowWidget *flowWidget; - QLabel *thresholdLabel; - QSpinBox *spinBox; - QPushButton *toggleButton; // Mode switch button - - QMap activeFormats; // Track active filters - QMap formatButtons; // Store toggle buttons - - bool exactMatchMode = true; // Toggle between "Exact Match" and "Includes" -}; - -#endif // COCKATRICE_VISUAL_DATABASE_DISPLAY_FORMAT_LEGALITY_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp deleted file mode 100644 index c44489c1b..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "visual_database_display_main_type_filter_widget.h" - -#include "../../../filters/filter_tree_model.h" -#include "visual_database_display_filter_button.h" - -#include -#include -#include -#include -#include -#include - -VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, - FilterTreeModel *_filterModel) - : QWidget(parent), filterModel(_filterModel) -{ - // Get all main card types with their count - allMainCardTypesWithCount = CardDatabaseManager::query()->getAllMainCardTypesWithCount(); - setMinimumWidth(300); - setMaximumHeight(200); - - layout = new QVBoxLayout(this); - setLayout(layout); - layout->setContentsMargins(0, 1, 0, 1); - layout->setSpacing(1); - layout->setAlignment(Qt::AlignTop); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - layout->addWidget(flowWidget); - - // Create a container for the threshold control - auto *thresholdLayout = new QHBoxLayout(); - thresholdLayout->setContentsMargins(0, 0, 0, 0); - - thresholdLabel = new QLabel(this); - thresholdLayout->addWidget(thresholdLabel); - - // Create the spinbox - spinBox = new QSpinBox(this); - spinBox->setMinimum(1); - spinBox->setMaximum(getMaxMainTypeCount()); - spinBox->setValue(150); - thresholdLayout->addWidget(spinBox); - thresholdLayout->addStretch(); - - layout->addLayout(thresholdLayout); - - connect(spinBox, qOverload(&QSpinBox::valueChanged), this, - &VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeButtonsVisibility); - - // Create the toggle button for Exact Match/Includes mode - toggleButton = new QPushButton(this); - layout->addWidget(toggleButton); - connect(toggleButton, &QPushButton::clicked, this, &VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode); - connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() { - QTimer::singleShot(100, this, &VisualDatabaseDisplayMainTypeFilterWidget::syncWithFilterModel); - }); - - createMainTypeButtons(); // Populate buttons initially - updateFilterMode(); // Initialize toggle button text - - retranslateUi(); -} - -void VisualDatabaseDisplayMainTypeFilterWidget::retranslateUi() -{ - thresholdLabel->setText(tr("Show main types with at least:")); - spinBox->setSuffix(tr(" cards")); - spinBox->setToolTip(tr("Do not display card main-types with less than this amount of cards in the database")); - toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)")); -} - -void VisualDatabaseDisplayMainTypeFilterWidget::createMainTypeButtons() -{ - // Iterate through main types and create buttons - for (auto it = allMainCardTypesWithCount.begin(); it != allMainCardTypesWithCount.end(); ++it) { - auto *button = new QPushButton(it.key(), flowWidget); - button->setCheckable(true); - - button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle); - - flowWidget->addWidget(button); - typeButtons[it.key()] = button; - - // Connect toggle signal - connect(button, &QPushButton::toggled, this, - [this, mainType = it.key()](bool checked) { handleMainTypeToggled(mainType, checked); }); - } - updateMainTypeButtonsVisibility(); // Ensure visibility is updated initially -} - -void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeButtonsVisibility() -{ - int threshold = spinBox->value(); // Get the current spinbox value - - // Iterate through buttons and hide/disable those below the threshold - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - bool visible = allMainCardTypesWithCount[it.key()] >= threshold; - it.value()->setVisible(visible); - it.value()->setEnabled(visible); - } -} - -int VisualDatabaseDisplayMainTypeFilterWidget::getMaxMainTypeCount() const -{ - int maxCount = 1; - for (auto it = allMainCardTypesWithCount.begin(); it != allMainCardTypesWithCount.end(); ++it) { - maxCount = qMax(maxCount, it.value()); - } - return maxCount; -} - -void VisualDatabaseDisplayMainTypeFilterWidget::handleMainTypeToggled(const QString &mainType, bool active) -{ - activeMainTypes[mainType] = active; - - if (typeButtons.contains(mainType)) { - typeButtons[mainType]->setChecked(active); - } - - updateMainTypeFilter(); -} - -void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter() -{ - // Clear existing filters related to main type - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - filterModel->clearFiltersOfType(CardFilter::Attr::AttrMainType); - - if (exactMatchMode) { - // Exact Match: Only selected main types are allowed - QSet selectedTypes; - for (const auto &type : activeMainTypes.keys()) { - if (activeMainTypes[type]) { - selectedTypes.insert(type); - } - } - - if (!selectedTypes.isEmpty()) { - // Require all selected types (TypeAnd) - for (const auto &type : selectedTypes) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrMainType)); - } - - // Exclude any other types (TypeAndNot) - for (const auto &type : typeButtons.keys()) { - if (!selectedTypes.contains(type)) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrMainType)); - } - } - } - } else { - // Default Includes Mode (TypeOr) - match any selected main types - for (const auto &type : activeMainTypes.keys()) { - if (activeMainTypes[type]) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrMainType)); - } - } - } - - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); -} - -void VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode() -{ - exactMatchMode = !exactMatchMode; - toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); - updateMainTypeFilter(); -} - -void VisualDatabaseDisplayMainTypeFilterWidget::syncWithFilterModel() -{ - // Temporarily block signals for each button to prevent toggling while updating button states - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - it.value()->blockSignals(true); - } - - // Uncheck all buttons - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - it.value()->setChecked(false); - } - - // Get active filters for main types - QSet activeTypes; - for (const auto &filter : filterModel->getFiltersOfType(CardFilter::AttrMainType)) { - if (filter->type() == CardFilter::Type::TypeAnd) { - activeTypes.insert(filter->term()); - } - } - - // Check the buttons for active types - for (const auto &type : activeTypes) { - activeMainTypes[type] = true; - if (typeButtons.contains(type)) { - typeButtons[type]->setChecked(true); - } - } - - // Re-enable signal emissions for each button - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - it.value()->blockSignals(false); - } - - // Update the visibility of buttons - updateMainTypeButtonsVisibility(); -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h deleted file mode 100644 index 9145812a7..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file visual_database_display_main_type_filter_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_MAIN_TYPE_FILTER_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_MAIN_TYPE_FILTER_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include -#include -#include - -class VisualDatabaseDisplayMainTypeFilterWidget : public QWidget -{ - Q_OBJECT -public: - explicit VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel); - void retranslateUi(); - void createMainTypeButtons(); - void updateMainTypeButtonsVisibility(); - int getMaxMainTypeCount() const; - - void handleMainTypeToggled(const QString &mainType, bool active); - void updateMainTypeFilter(); - void updateFilterMode(); - void syncWithFilterModel(); - -private: - FilterTreeModel *filterModel; - QMap allMainCardTypesWithCount; - - QVBoxLayout *layout; - FlowWidget *flowWidget; - QLabel *thresholdLabel; - QSpinBox *spinBox; - QPushButton *toggleButton; // Mode switch button - - QMap activeMainTypes; // Track active filters - QMap typeButtons; // Store toggle buttons - - bool exactMatchMode = true; // Toggle between "Exact Match" and "Includes" -}; - -#endif // VISUAL_DATABASE_DISPLAY_MAIN_TYPE_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp deleted file mode 100644 index 2751ee971..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "visual_database_display_name_filter_widget.h" - -#include "../../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h" -#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h" -#include "../deck_editor/deck_state_manager.h" -#include "visual_database_display_filter_button.h" - -#include - -VisualDatabaseDisplayNameFilterWidget::VisualDatabaseDisplayNameFilterWidget(QWidget *parent, - AbstractTabDeckEditor *_deckEditor, - FilterTreeModel *_filterModel) - : QWidget(parent), deckEditor(_deckEditor), filterModel(_filterModel) -{ - setMinimumWidth(300); - setMaximumHeight(300); - - layout = new QVBoxLayout(this); - setLayout(layout); - - searchBox = new QLineEdit(this); - layout->addWidget(searchBox); - - connect(searchBox, &QLineEdit::returnPressed, this, [this]() { - QString text = searchBox->text().trimmed(); - if (!text.isEmpty() && !activeFilters.contains(text)) { - createNameFilter(text); - searchBox->clear(); - updateFilterModel(); - } - }); - - // Create container for active filters - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - layout->addWidget(flowWidget); - - loadFromDeckButton = new QPushButton(this); - layout->addWidget(loadFromDeckButton); - - connect(loadFromDeckButton, &QPushButton::clicked, this, &VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck); - - loadFromClipboardButton = new QPushButton(this); - layout->addWidget(loadFromClipboardButton); - - connect(loadFromClipboardButton, &QPushButton::clicked, this, - &VisualDatabaseDisplayNameFilterWidget::actLoadFromClipboard); - - connect(filterModel, &FilterTreeModel::layoutChanged, this, - [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayNameFilterWidget::syncWithFilterModel); }); - - retranslateUi(); -} - -void VisualDatabaseDisplayNameFilterWidget::retranslateUi() -{ - searchBox->setPlaceholderText(tr("Filter by name... (Exact match)")); - loadFromDeckButton->setText(tr("Load from Deck")); - loadFromDeckButton->setToolTip(tr("Apply all card names in currently loaded deck as exact match name filters")); - loadFromClipboardButton->setText(tr("Load from Clipboard")); - loadFromClipboardButton->setToolTip(tr("Apply all card names in clipboard as exact match name filters")); -} - -void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck() -{ - DeckListModel *deckListModel = deckEditor->deckStateManager->getModel(); - - if (!deckListModel) - return; - - QList cardNames = deckListModel->getCardNames(); - for (auto cardName : cardNames) { - createNameFilter(cardName); - } - - updateFilterModel(); -} - -void VisualDatabaseDisplayNameFilterWidget::actLoadFromClipboard() -{ - DlgLoadDeckFromClipboard dlg(this); - if (!dlg.exec()) - return; - - QStringList cardsInClipboard = dlg.getDeckList().getCardList(); - for (QString cardName : cardsInClipboard) { - createNameFilter(cardName); - } - - updateFilterModel(); -} - -void VisualDatabaseDisplayNameFilterWidget::createNameFilter(const QString &name) -{ - if (activeFilters.contains(name)) - return; - - // Create a button for the filter - auto *button = new QPushButton(name, flowWidget); - - button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle); - - connect(button, &QPushButton::clicked, this, [this, name]() { - removeNameFilter(name); - QTimer::singleShot(0, this, - &VisualDatabaseDisplayNameFilterWidget::updateFilterModel); // Avoid concurrent modification - }); - - flowWidget->addWidget(button); - activeFilters[name] = button; -} - -void VisualDatabaseDisplayNameFilterWidget::removeNameFilter(const QString &name) -{ - if (activeFilters.contains(name)) { - activeFilters[name]->deleteLater(); // Safe deletion - activeFilters.remove(name); - } -} - -void VisualDatabaseDisplayNameFilterWidget::updateFilterModel() -{ - // Clear existing name filters - emit filterModel->layoutAboutToBeChanged(); - filterModel->clearFiltersOfType(CardFilter::Attr::AttrNameExact); - - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - - for (const auto &name : activeFilters.keys()) { - QString nameString = name; - filterModel->addFilter(new CardFilter(nameString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrNameExact)); - } - - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); -} - -void VisualDatabaseDisplayNameFilterWidget::syncWithFilterModel() -{ - QStringList currentFilters; - for (const auto &filter : filterModel->getFiltersOfType(CardFilter::Attr::AttrNameExact)) { - if (filter->type() == CardFilter::Type::TypeOr) { - currentFilters.append(filter->term()); - } - } - - QStringList activeFilterList = activeFilters.keys(); - - // Sort lists for efficient comparison - std::sort(currentFilters.begin(), currentFilters.end()); - std::sort(activeFilterList.begin(), activeFilterList.end()); - - if (currentFilters == activeFilterList) { - return; - } - - // Remove filters that are in the UI but not in the model - for (const auto &name : activeFilterList) { - if (!currentFilters.contains(name)) { - removeNameFilter(name); - } - } - - // Add filters that are in the model but not in the UI - for (const auto &name : currentFilters) { - if (!activeFilters.contains(name)) { - createNameFilter(name); - } - } -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.h deleted file mode 100644 index 76d3ec29e..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file visual_database_display_name_filter_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_NAME_FILTER_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_NAME_FILTER_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include - -class VisualDatabaseDisplayNameFilterWidget : public QWidget -{ - Q_OBJECT -public: - explicit VisualDatabaseDisplayNameFilterWidget(QWidget *parent, - AbstractTabDeckEditor *deckEditor, - FilterTreeModel *filterModel); - - void createNameFilter(const QString &name); - void removeNameFilter(const QString &name); - void updateFilterList(); - void updateFilterModel(); - void syncWithFilterModel(); - -public slots: - void retranslateUi(); - -private: - AbstractTabDeckEditor *deckEditor; - FilterTreeModel *filterModel; - QVBoxLayout *layout; - QLineEdit *searchBox; - FlowWidget *flowWidget; - QPushButton *loadFromDeckButton; - QPushButton *loadFromClipboardButton; - - QMap activeFilters; // Store active name filter buttons - -private slots: - void actLoadFromDeck(); - void actLoadFromClipboard(); -}; - -#endif // VISUAL_DATABASE_DISPLAY_NAME_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp deleted file mode 100644 index b72116461..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include "visual_database_display_set_filter_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../../../filters/filter_tree_model.h" -#include "visual_database_display_filter_button.h" - -#include -#include -#include -#include -#include -#include - -VisualDatabaseDisplayRecentSetFilterSettingsWidget::VisualDatabaseDisplayRecentSetFilterSettingsWidget(QWidget *parent) - : QWidget(parent) -{ - layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - - setLayout(layout); - - filterToMostRecentSetsCheckBox = new QCheckBox(this); - filterToMostRecentSetsCheckBox->setChecked( - SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsEnabled()); - connect(filterToMostRecentSetsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled); - - filterToMostRecentSetsAmount = new QSpinBox(this); - filterToMostRecentSetsAmount->setMinimum(1); - filterToMostRecentSetsAmount->setMaximum(100); - filterToMostRecentSetsAmount->setValue( - SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsAmount()); - connect(filterToMostRecentSetsAmount, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), - &SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount); - - layout->addWidget(filterToMostRecentSetsCheckBox); - layout->addWidget(filterToMostRecentSetsAmount); - - retranslateUi(); -} - -void VisualDatabaseDisplayRecentSetFilterSettingsWidget::retranslateUi() -{ - filterToMostRecentSetsCheckBox->setText(tr("Filter to most recent sets")); -} - -VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidget *parent, - FilterTreeModel *_filterModel) - : QWidget(parent), filterModel(_filterModel) -{ - setMinimumWidth(300); - setMaximumHeight(300); - - layout = new QVBoxLayout(this); - setLayout(layout); - - searchBox = new QLineEdit(this); - searchBox->setPlaceholderText(tr("Search sets...")); - layout->addWidget(searchBox); - connect(searchBox, &QLineEdit::textChanged, this, - &VisualDatabaseDisplaySetFilterWidget::updateSetButtonsVisibility); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - layout->addWidget(flowWidget); - - recentSetsSettingsWidget = new VisualDatabaseDisplayRecentSetFilterSettingsWidget(this); - layout->addWidget(recentSetsSettingsWidget); - - connect(&SettingsCache::instance(), &SettingsCache::visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged, this, - &VisualDatabaseDisplaySetFilterWidget::filterToRecentSets); - connect(&SettingsCache::instance(), &SettingsCache::visualDatabaseDisplayFilterToMostRecentSetsAmountChanged, this, - &VisualDatabaseDisplaySetFilterWidget::filterToRecentSets); - - // Create the toggle button for Exact Match/Includes mode - toggleButton = new QPushButton(this); - layout->addWidget(toggleButton); - connect(toggleButton, &QPushButton::clicked, this, &VisualDatabaseDisplaySetFilterWidget::updateFilterMode); - connect(filterModel, &FilterTreeModel::layoutChanged, this, - [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel); }); - - createSetButtons(); // Populate buttons initially - updateFilterMode(); - retranslateUi(); -} - -void VisualDatabaseDisplaySetFilterWidget::retranslateUi() -{ - toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); -} - -void VisualDatabaseDisplaySetFilterWidget::createSetButtons() -{ - CardSetList allSets = CardDatabaseManager::getInstance()->getSetList(); - - // Sort by release date - std::sort(allSets.begin(), allSets.end(), - [](const auto &a, const auto &b) { return a->getReleaseDate() > b->getReleaseDate(); }); - - for (const auto &set : allSets) { - QString shortName = set->getShortName(); - QString longName = set->getLongName(); - - auto *button = new QPushButton(longName + " (" + shortName + ")", flowWidget); - button->setCheckable(true); - - button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle); - - flowWidget->addWidget(button); - setButtons[shortName] = button; - - // Connect toggle signal - connect(button, &QPushButton::toggled, this, - [this, shortName](bool checked) { handleSetToggled(shortName, checked); }); - } - - filterToRecentSets(); -} - -void VisualDatabaseDisplaySetFilterWidget::filterToRecentSets() -{ - if (SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsEnabled()) { - for (auto set : activeSets.keys()) { - activeSets[set] = false; - } - - CardSetList allSets = CardDatabaseManager::getInstance()->getSetList(); - - // Sort by release date - std::sort(allSets.begin(), allSets.end(), - [](const auto &a, const auto &b) { return a->getReleaseDate() > b->getReleaseDate(); }); - - int setsToPreactivate = SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsAmount(); - int setsActivated = 0; - - for (const auto &set : allSets) { - QString shortName = set->getShortName(); - QString longName = set->getLongName(); - - auto button = setButtons[shortName]; - - if (setsActivated < setsToPreactivate) { - setsActivated++; - activeSets[shortName] = true; - button->blockSignals(true); - button->setChecked(true); - button->blockSignals(false); - } else { - break; - } - } - - updateSetFilter(); - updateSetButtonsVisibility(); - } -} - -void VisualDatabaseDisplaySetFilterWidget::updateSetButtonsVisibility() -{ - QString filterText = searchBox->text().trimmed().toLower(); - - for (const QString &setName : setButtons.keys()) { - QPushButton *buttonForSet = setButtons[setName]; - QString shortName = setName.toLower(); - QString longName = buttonForSet->text().toLower(); - bool alwaysVisible = activeSets.contains(setName) && activeSets[setName]; - bool visible = - alwaysVisible || filterText.isEmpty() || shortName.contains(filterText) || longName.contains(filterText); - buttonForSet->setVisible(visible); - } -} - -void VisualDatabaseDisplaySetFilterWidget::handleSetToggled(const QString &setShortName, bool active) -{ - activeSets[setShortName] = active; - - if (setButtons.contains(setShortName)) { - setButtons[setShortName]->setChecked(active); - } - - updateSetFilter(); -} - -void VisualDatabaseDisplaySetFilterWidget::updateSetFilter() -{ - // Clear existing filters related to sets - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - filterModel->clearFiltersOfType(CardFilter::Attr::AttrSet); - - if (exactMatchMode) { - // Exact Match: Only selected sets are allowed - QSet selectedSets; - for (const auto &set : activeSets.keys()) { - if (activeSets[set]) { - selectedSets.insert(set); - } - } - - if (!selectedSets.isEmpty()) { - // Require all selected sets (TypeAnd) - for (const auto &set : selectedSets) { - QString setString = set; - filterModel->addFilter(new CardFilter(setString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrSet)); - } - - // Exclude any other sets (TypeAndNot) - for (const auto &set : setButtons.keys()) { - if (!selectedSets.contains(set)) { - QString setString = set; - filterModel->addFilter( - new CardFilter(setString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrSet)); - } - } - } - } else { - // Default Includes Mode (TypeOr) - match any selected sets - for (const auto &set : activeSets.keys()) { - if (activeSets[set]) { - QString setString = set; - filterModel->addFilter(new CardFilter(setString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrSet)); - } - } - } - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); -} - -void VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel() -{ - // Clear activeSets - activeSets.clear(); - - // Read the current filters in filterModel - auto currentFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrSet); - - // Determine if we're in Exact Match mode or Includes mode - QSet selectedSets; - QSet excludedSets; - for (const auto &filter : currentFilters) { - if (filter->type() == CardFilter::Type::TypeAnd) { - selectedSets.insert(filter->term()); - } else if (filter->type() == CardFilter::Type::TypeAndNot) { - excludedSets.insert(filter->term()); - } else if (filter->type() == CardFilter::Type::TypeOr) { - selectedSets.insert(filter->term()); - } - } - - // Determine exact match mode based on filter structure - bool newExactMatchMode = !excludedSets.isEmpty(); - - if (newExactMatchMode != exactMatchMode) { - exactMatchMode = newExactMatchMode; - toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); - } - - // Sync button states with selected sets - for (const auto &key : setButtons.keys()) { - bool active = selectedSets.contains(key); - activeSets[key] = active; - setButtons[key]->blockSignals(true); - setButtons[key]->setChecked(active); - setButtons[key]->blockSignals(false); - } -} - -void VisualDatabaseDisplaySetFilterWidget::updateFilterMode() -{ - // Disconnect the layoutChanged -> sync lambda temporarily - disconnect(filterModel, &FilterTreeModel::layoutChanged, this, nullptr); - - exactMatchMode = !exactMatchMode; - updateSetFilter(); - retranslateUi(); - - // Reconnect the layoutChanged -> sync lambda - connect(filterModel, &FilterTreeModel::layoutChanged, this, - [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel); }); -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.h deleted file mode 100644 index dc7fd0e92..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_set_filter_widget.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file visual_database_display_set_filter_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_SET_FILTER_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_SET_FILTER_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -class VisualDatabaseDisplayRecentSetFilterSettingsWidget : public QWidget -{ - Q_OBJECT -public: - VisualDatabaseDisplayRecentSetFilterSettingsWidget(QWidget *parent); - void retranslateUi(); - -private: - QHBoxLayout *layout; - QCheckBox *filterToMostRecentSetsCheckBox; - QSpinBox *filterToMostRecentSetsAmount; -}; - -class VisualDatabaseDisplaySetFilterWidget : public QWidget -{ - Q_OBJECT -public: - explicit VisualDatabaseDisplaySetFilterWidget(QWidget *parent, FilterTreeModel *filterModel); - void retranslateUi(); - void createSetButtons(); - void filterToRecentSets(); - void updateSetButtonsVisibility(); - void handleSetToggled(const QString &setShortName, bool active); - - void updateSetFilter(); - void syncWithFilterModel(); - void updateFilterMode(); - -private: - FilterTreeModel *filterModel; - QMap allMainCardTypesWithCount; - QVBoxLayout *layout; - VisualDatabaseDisplayRecentSetFilterSettingsWidget *recentSetsSettingsWidget; - QLineEdit *searchBox; - FlowWidget *flowWidget; - QPushButton *toggleButton; // Mode switch button - - QMap activeMainTypes; // Track active filters - QMap typeButtons; // Store toggle buttons - QMap setButtons; // Store set filter buttons - QMap activeSets; // Track active set filters - - bool exactMatchMode = true; // Toggle between "Exact Match" and "Includes" -}; - -#endif // VISUAL_DATABASE_DISPLAY_SET_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp deleted file mode 100644 index 6d4bcb58e..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "visual_database_display_sub_type_filter_widget.h" - -#include "../../../filters/filter_tree_model.h" -#include "visual_database_display_filter_button.h" - -#include -#include -#include -#include -#include -#include -#include - -VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, - FilterTreeModel *_filterModel) - : QWidget(parent), filterModel(_filterModel) -{ - allSubCardTypesWithCount = CardDatabaseManager::query()->getAllSubCardTypesWithCount(); - - setMinimumWidth(300); - - layout = new QVBoxLayout(this); - setLayout(layout); - - // Create search box - searchBox = new QLineEdit(this); - searchBox->setPlaceholderText(tr("Search subtypes...")); - layout->addWidget(searchBox); - connect(searchBox, &QLineEdit::textChanged, this, - &VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - flowWidget->setMaximumHeight(300); - layout->addWidget(flowWidget); - - // Create a container for the threshold control - auto *thresholdLayout = new QHBoxLayout(); - thresholdLayout->setContentsMargins(0, 0, 0, 0); - - thresholdLabel = new QLabel(this); - thresholdLayout->addWidget(thresholdLabel); - - // Create the spinbox - spinBox = new QSpinBox(this); - spinBox->setMinimum(1); - spinBox->setMaximum(getMaxSubTypeCount()); - spinBox->setValue(150); - thresholdLayout->addWidget(spinBox); - thresholdLayout->addStretch(); - - layout->addLayout(thresholdLayout); - - connect(spinBox, qOverload(&QSpinBox::valueChanged), this, - &VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility); - - // Toggle button setup (Exact Match / Includes mode) - toggleButton = new QPushButton(this); - layout->addWidget(toggleButton); - connect(toggleButton, &QPushButton::clicked, this, &VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode); - connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() { - QTimer::singleShot(100, this, &VisualDatabaseDisplaySubTypeFilterWidget::syncWithFilterModel); - }); - - createSubTypeButtons(); // Populate buttons initially - updateFilterMode(); // Initialize the toggle button text - - retranslateUi(); -} - -void VisualDatabaseDisplaySubTypeFilterWidget::retranslateUi() -{ - thresholdLabel->setText(tr("Show sub types with at least:")); - spinBox->setSuffix(tr(" cards")); - spinBox->setToolTip(tr("Do not display card sub-types with less than this amount of cards in the database")); - toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)")); -} - -void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons() -{ - // Iterate through sub types and create buttons - for (auto it = allSubCardTypesWithCount.begin(); it != allSubCardTypesWithCount.end(); ++it) { - auto *button = new QPushButton(it.key(), flowWidget); - button->setCheckable(true); - - button->setStyleSheet(visualDatabaseDisplayFilterButtonStyle); - - flowWidget->addWidget(button); - typeButtons[it.key()] = button; - - // Connect toggle signal for each button - connect(button, &QPushButton::toggled, this, - [this, subType = it.key()](bool checked) { handleSubTypeToggled(subType, checked); }); - } - updateSubTypeButtonsVisibility(); // Ensure visibility is updated initially -} - -void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility() -{ - int threshold = spinBox->value(); - QString filterText = searchBox->text().trimmed().toLower(); - - // Iterate through buttons and hide/disable those below the threshold - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - QString subType = it.key().toLower(); - bool isActive = activeSubTypes.value(it.key(), false); - bool visible = isActive || (allSubCardTypesWithCount[it.key()] >= threshold && - (filterText.isEmpty() || subType.contains(filterText))); - - it.value()->setVisible(visible); - it.value()->setEnabled(visible); - } -} - -int VisualDatabaseDisplaySubTypeFilterWidget::getMaxSubTypeCount() const -{ - int maxCount = 1; - for (auto it = allSubCardTypesWithCount.begin(); it != allSubCardTypesWithCount.end(); ++it) { - maxCount = qMax(maxCount, it.value()); - } - return maxCount; -} - -void VisualDatabaseDisplaySubTypeFilterWidget::handleSubTypeToggled(const QString &subType, bool active) -{ - activeSubTypes[subType] = active; - - if (typeButtons.contains(subType)) { - typeButtons[subType]->setChecked(active); - } - - updateSubTypeFilter(); -} - -void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter() -{ - filterModel->blockSignals(true); - // Clear existing filters related to sub types - filterModel->clearFiltersOfType(CardFilter::Attr::AttrSubType); - - if (exactMatchMode) { - // Exact Match: Only selected sub types are allowed - QSet selectedTypes; - for (const auto &type : activeSubTypes.keys()) { - if (activeSubTypes[type]) { - selectedTypes.insert(type); - } - } - - if (!selectedTypes.isEmpty()) { - // Require all selected subtypes (TypeAnd) - for (const auto &type : selectedTypes) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrSubType)); - } - - // Exclude any other types (TypeAndNot) - for (const auto &type : typeButtons.keys()) { - if (!selectedTypes.contains(type)) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrSubType)); - } - } - } - } else { - // Default Includes Mode (TypeOr) - match any selected subtypes - for (const auto &type : activeSubTypes.keys()) { - if (activeSubTypes[type]) { - QString typeString = type; - filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrSubType)); - } - } - } - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); -} - -void VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode() -{ - exactMatchMode = !exactMatchMode; - toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); - updateSubTypeFilter(); -} - -void VisualDatabaseDisplaySubTypeFilterWidget::syncWithFilterModel() -{ - // Temporarily block signals for each button to prevent toggling while updating button states - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - it.value()->blockSignals(true); - } - - // Uncheck all buttons - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - it.value()->setChecked(false); - } - - // Get active filters for sub types - QSet activeTypes; - for (const auto &filter : filterModel->getFiltersOfType(CardFilter::AttrSubType)) { - if (filter->type() == CardFilter::Type::TypeAnd || filter->type() == CardFilter::Type::TypeOr) { - activeTypes.insert(filter->term()); - } - } - - // Check the buttons for active types - for (const auto &type : activeTypes) { - activeSubTypes[type] = true; - if (typeButtons.contains(type)) { - typeButtons[type]->setChecked(true); - } - } - - // Re-enable signal emissions for each button - for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { - it.value()->blockSignals(false); - } - - // Update the visibility of buttons - updateSubTypeButtonsVisibility(); -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h deleted file mode 100644 index ce5546fc8..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @file visual_database_display_sub_type_filter_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_SUB_TYPE_FILTER_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_SUB_TYPE_FILTER_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include -#include - -class VisualDatabaseDisplaySubTypeFilterWidget : public QWidget -{ - Q_OBJECT -public: - explicit VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel); - void retranslateUi(); - void createSubTypeButtons(); - void updateSubTypeButtonsVisibility(); - [[nodiscard]] int getMaxSubTypeCount() const; - - void handleSubTypeToggled(const QString &mainType, bool active); - void updateSubTypeFilter(); - void updateFilterMode(); - void syncWithFilterModel(); - -private: - FilterTreeModel *filterModel; - QMap allSubCardTypesWithCount; - - QVBoxLayout *layout; - QLineEdit *searchBox; - FlowWidget *flowWidget; - QLabel *thresholdLabel; - QSpinBox *spinBox; - QPushButton *toggleButton; // Mode switch button - - QMap activeSubTypes; // Track active filters - QMap typeButtons; // Store toggle buttons - - bool exactMatchMode = true; // Toggle between "Exact Match" and "Includes" -}; - -#endif // VISUAL_DATABASE_DISPLAY_SUB_TYPE_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp deleted file mode 100644 index 9c4432042..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.cpp +++ /dev/null @@ -1,377 +0,0 @@ -#include "visual_database_display_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../../../filters/filter_tree_model.h" -#include "../../../filters/syntax_help.h" -#include "../../pixel_map_generator.h" -#include "../cards/card_info_picture_with_text_overlay_widget.h" -#include "../quick_settings/settings_button_widget.h" -#include "../utility/custom_line_edit.h" -#include "visual_database_display_color_filter_widget.h" -#include "visual_database_display_filter_save_load_widget.h" -#include "visual_database_display_main_type_filter_widget.h" -#include "visual_database_display_name_filter_widget.h" -#include "visual_database_display_set_filter_widget.h" -#include "visual_database_display_sub_type_filter_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent, - AbstractTabDeckEditor *_deckEditor, - CardDatabaseModel *database_model, - CardDatabaseDisplayModel *database_display_model) - : QWidget(parent), deckEditor(_deckEditor), databaseModel(database_model), - databaseDisplayModel(database_display_model) -{ - debounceTimer = new QTimer(this); - debounceTimer->setSingleShot(true); // Ensure it only fires once after the timeout - - connect(debounceTimer, &QTimer::timeout, this, &VisualDatabaseDisplayWidget::onSearchModelChanged); - - cards = new QList; - connect(databaseDisplayModel, &CardDatabaseDisplayModel::modelDirty, this, - &VisualDatabaseDisplayWidget::modelDirty); - - // Set up main layout and widgets - setMinimumSize(0, 0); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mainLayout = new QVBoxLayout(this); - setLayout(mainLayout); - mainLayout->setSpacing(1); - mainLayout->setContentsMargins(0, 0, 0, 0); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarPolicy::ScrollBarAsNeeded); - cardSizeWidget = new CardSizeWidget(this, flowWidget, SettingsCache::instance().getVisualDatabaseDisplayCardSize()); - connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(), - &SettingsCache::setVisualDatabaseDisplayCardSize); - - searchContainer = new QWidget(this); - searchLayout = new QHBoxLayout(searchContainer); - searchContainer->setLayout(searchLayout); - - searchEdit = new SearchLineEdit(); - searchEdit->setObjectName("searchEdit"); - searchEdit->setPlaceholderText(tr("Search by card name (or search expressions)")); - searchEdit->setClearButtonEnabled(true); - searchEdit->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition); - auto help = searchEdit->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition); - connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(searchEdit); }); - searchEdit->installEventFilter(&searchKeySignals); - - setFocusProxy(searchEdit); - setFocusPolicy(Qt::ClickFocus); - - displayModeButton = new QPushButton(tr("Visual"), this); - displayModeButton->setCheckable(true); // Toggle button - - connect(displayModeButton, &QPushButton::toggled, this, &VisualDatabaseDisplayWidget::onDisplayModeChanged); - - displayModeButton->setChecked(false); // Start in Visual mode - - filterModel = new FilterTreeModel(); - filterModel->setObjectName("filterModel"); - - searchKeySignals.setObjectName("searchKeySignals"); - connect(searchEdit, &SearchLineEdit::textChanged, this, &VisualDatabaseDisplayWidget::updateSearch); - - DeckEditorDatabaseDisplayWidget *databaseDisplayWidget = deckEditor->cardDatabaseDockWidget->databaseDisplayWidget; - connect(&searchKeySignals, &KeySignals::onEnter, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck); - connect(&searchKeySignals, &KeySignals::onCtrlAltEqual, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck); - connect(&searchKeySignals, &KeySignals::onCtrlAltRBracket, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard); - connect(&searchKeySignals, &KeySignals::onCtrlAltMinus, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actDecrementCardFromMainDeck); - connect(&searchKeySignals, &KeySignals::onCtrlAltLBracket, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actDecrementCardFromSideboard); - connect(&searchKeySignals, &KeySignals::onCtrlAltEnter, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard); - connect(&searchKeySignals, &KeySignals::onCtrlEnter, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard); - connect(&searchKeySignals, &KeySignals::onCtrlC, databaseDisplayWidget, - &DeckEditorDatabaseDisplayWidget::copyDatabaseCellContents); - connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(searchEdit); }); - - connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::addCardToMainDeck, this, - &VisualDatabaseDisplayWidget::highlightAllSearchEdit); - connect(databaseDisplayWidget, &DeckEditorDatabaseDisplayWidget::addCardToSideboard, this, - &VisualDatabaseDisplayWidget::highlightAllSearchEdit); - - databaseView = databaseDisplayWidget->getDatabaseView(); - databaseView->setFocusProxy(searchEdit); - databaseView->setItemDelegate(nullptr); - databaseView->setVisible(false); - - searchEdit->setTreeView(databaseView); - - colorFilterWidget = new VisualDatabaseDisplayColorFilterWidget(this, filterModel); - - filterContainer = new VisualDatabaseDisplayFilterToolbarWidget(this); - - clearFilterWidget = new QToolButton(); - clearFilterWidget->setFixedSize(32, 32); - clearFilterWidget->setIcon(QPixmap("theme:icons/delete")); - connect(clearFilterWidget, &QToolButton::clicked, this, [this] { - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - filterModel->clear(); - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); - }); - - databaseLoadIndicator = new QLabel(this); - databaseLoadIndicator->setAlignment(Qt::AlignCenter); - - mainLayout->addWidget(databaseLoadIndicator); - - if (CardDatabaseManager::getInstance()->getLoadStatus() != LoadStatus::Ok) { - connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this, - &VisualDatabaseDisplayWidget::initialize); - filterContainer->setVisible(false); - } else { - initialize(); - databaseLoadIndicator->setVisible(false); - } - - retranslateUi(); -} - -void VisualDatabaseDisplayWidget::initialize() -{ - databaseLoadIndicator->setVisible(false); - - filterContainer->initialize(); - filterContainer->setVisible(true); - - searchLayout->addWidget(colorFilterWidget); - searchLayout->addWidget(clearFilterWidget); - searchLayout->addWidget(searchEdit); - searchLayout->addWidget(displayModeButton); - - mainLayout->addWidget(searchContainer); - - mainLayout->addWidget(filterContainer); - - mainLayout->addWidget(databaseView); - - mainLayout->addWidget(flowWidget); - - mainLayout->addWidget(cardSizeWidget); - - databaseDisplayModel->setFilterTree(filterModel->filterTree()); - - connect(filterModel, &FilterTreeModel::layoutChanged, this, &VisualDatabaseDisplayWidget::onSearchModelChanged); - - loadCardsTimer = new QTimer(this); - loadCardsTimer->setSingleShot(true); // Ensure it only fires once after the timeout - - connect(loadCardsTimer, &QTimer::timeout, this, [this]() { loadCurrentPage(); }); - loadCardsTimer->start(5000); - - retranslateUi(); -} - -void VisualDatabaseDisplayWidget::retranslateUi() -{ - databaseLoadIndicator->setText(tr("Loading database ...")); - clearFilterWidget->setToolTip(tr("Clear all filters")); -} - -void VisualDatabaseDisplayWidget::highlightAllSearchEdit() -{ - searchEdit->setSelection(0, searchEdit->text().length()); -} - -void VisualDatabaseDisplayWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - loadCurrentPage(); -} - -void VisualDatabaseDisplayWidget::onDisplayModeChanged(bool checked) -{ - if (checked) { - // Table mode - displayModeButton->setText(tr("Table")); - flowWidget->setVisible(false); - cardSizeWidget->setVisible(false); - databaseView->setItemDelegate(new QStyledItemDelegate(databaseView)); - databaseView->setVisible(true); - } else { - // Visual mode - displayModeButton->setText(tr("Visual")); - flowWidget->setVisible(true); - cardSizeWidget->setVisible(true); - databaseView->setVisible(false); - populateCards(); - } -} - -void VisualDatabaseDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance) -{ - emit cardClickedDatabaseDisplay(event, instance); -} - -void VisualDatabaseDisplayWidget::onHover(const ExactCard &hoveredCard) -{ - emit cardHoveredDatabaseDisplay(hoveredCard); -} - -void VisualDatabaseDisplayWidget::addCard(const ExactCard &cardToAdd) -{ - cards->append(cardToAdd); - auto *display = new CardInfoPictureWithTextOverlayWidget(flowWidget, false); - display->setScaleFactor(cardSizeWidget->getSlider()->value()); - display->setCard(cardToAdd); - flowWidget->addWidget(display); - connect(display, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &VisualDatabaseDisplayWidget::onClick); - connect(display, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &VisualDatabaseDisplayWidget::onHover); - connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, display, &CardInfoPictureWidget::setScaleFactor); -} - -void VisualDatabaseDisplayWidget::updateSearch(const QString &search) const -{ - databaseDisplayModel->setStringFilter(search); - QModelIndexList sel = databaseView->selectionModel()->selectedRows(); - if (sel.isEmpty() && databaseDisplayModel->rowCount()) - databaseView->selectionModel()->setCurrentIndex(databaseDisplayModel->index(0, 0), - QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); -} - -bool VisualDatabaseDisplayWidget::isVisualDisplayMode() const -{ - return !displayModeButton->isChecked(); -} - -void VisualDatabaseDisplayWidget::onSearchModelChanged() -{ - if (flowWidget->isVisible()) { - // Clear the current page and prepare for new data - flowWidget->clearLayout(); // Clear existing cards - cards->clear(); // Clear the card list - // Reset scrollbar position to the top after loading new cards - if (QScrollBar *scrollBar = flowWidget->scrollArea->verticalScrollBar()) { - scrollBar->setValue(0); // Reset scrollbar to top - } - - currentPage = 0; - loadCurrentPage(); - qCDebug(VisualDatabaseDisplayLog) << "Search model changed"; - } -} - -void VisualDatabaseDisplayWidget::loadCurrentPage() -{ - // Ensure only the initial page is loaded - if (currentPage == 0) { - // Only load the first page initially - qCDebug(VisualDatabaseDisplayLog) << "Loading the first page"; - populateCards(); - } else { - // If not the first page, just load the next page and append to the flow widget - loadNextPage(); - } -} - -void VisualDatabaseDisplayWidget::populateCards() -{ - cards->clear(); - loadNextPage(); -} - -void VisualDatabaseDisplayWidget::loadNextPage() -{ - // Calculate the start and end indices for the next page - int rowCount = databaseDisplayModel->rowCount(); - int start = currentPage * cardsPerPage; - int end = qMin(start + cardsPerPage, rowCount); - - // Load more cards if we are at the end of the current list and can fetch more - if (end >= rowCount && databaseDisplayModel->canFetchMore(QModelIndex())) { - databaseDisplayModel->fetchMore(QModelIndex()); - } - - // Load the next page of cards and add them to the flow widget - flowWidget->setUpdatesEnabled(false); - loadPage(start, end); - flowWidget->setUpdatesEnabled(true); -} - -void VisualDatabaseDisplayWidget::loadPage(int start, int end) -{ - QList setFilters = filterModel->getFiltersOfType(CardFilter::AttrSet); - for (int row = start; row < end; ++row) { - qCDebug(VisualDatabaseDisplayLog) << "Adding " << row; - QModelIndex index = databaseDisplayModel->index(row, CardDatabaseModel::NameColumn); - QVariant name = databaseDisplayModel->data(index, Qt::DisplayRole); - qCDebug(VisualDatabaseDisplayLog) << name.toString(); - - if (CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(name.toString())) { - if (!setFilters.empty()) { - SetToPrintingsMap setMap = info->getSets(); - for (const CardFilter *setFilter : setFilters) { - if (setMap.contains(setFilter->term())) { - for (PrintingInfo printing : setMap[setFilter->term()]) { - addCard(ExactCard(info, printing)); - } - } - } - } else { - addCard(CardDatabaseManager::query()->getPreferredCard(info)); - } - } else { - qCDebug(VisualDatabaseDisplayLog) << "Card not found in database!"; - } - } - currentPage++; -} - -void VisualDatabaseDisplayWidget::modelDirty() const -{ - debounceTimer->start(debounceTime); -} - -void VisualDatabaseDisplayWidget::sortCardList(const QStringList &properties, - Qt::SortOrder order = Qt::AscendingOrder) const -{ - CardInfoComparator comparator(properties, order); - std::sort(cards->begin(), cards->end(), [comparator](const ExactCard &a, const ExactCard &b) { - return comparator(a.getCardPtr(), b.getCardPtr()); - }); -} - -void VisualDatabaseDisplayWidget::databaseDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) -{ - (void)topLeft; - (void)bottomRight; - qCDebug(VisualDatabaseDisplayLog) << "Database Data changed"; -} - -void VisualDatabaseDisplayWidget::wheelEvent(QWheelEvent *event) -{ - int totalCards = databaseDisplayModel->rowCount(); // Total number of cards - int loadedCards = currentPage * cardsPerPage; - - // Handle scrolling down - if (event->angleDelta().y() < 0) { - // Check if the next page has any cards to load - if (loadedCards < totalCards) { - loadCurrentPage(); // Load the next page - event->accept(); // Accept the event as valid - return; - } - qCDebug(VisualDatabaseDisplayLog) << loadedCards << ":" << totalCards; - } - - // Prevent overscrolling when there's no more data to load - event->ignore(); -} diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h deleted file mode 100644 index 190ea1f6d..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_widget.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file visual_database_display_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_DISPLAY_WIDGET_H -#define VISUAL_DATABASE_DISPLAY_WIDGET_H - -#include "../../../filters/filter_tree_model.h" -#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h" -#include "../../key_signals.h" -#include "../cards/card_info_picture_with_text_overlay_widget.h" -#include "../cards/card_size_widget.h" -#include "../general/layout_containers/flow_widget.h" -#include "../general/layout_containers/overlap_control_widget.h" -#include "../utility/custom_line_edit.h" -#include "visual_database_display_color_filter_widget.h" -#include "visual_database_display_filter_toolbar_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -inline Q_LOGGING_CATEGORY(VisualDatabaseDisplayLog, "visual_database_display"); - -class VisualDatabaseDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDatabaseDisplayWidget(QWidget *parent, - AbstractTabDeckEditor *deckEditor, - CardDatabaseModel *database_model, - CardDatabaseDisplayModel *database_display_model); - void retranslateUi(); - - void adjustCardsPerPage(); - void populateCards(); - void loadPage(int start, int end); - void loadNextPage(); - void loadCurrentPage(); - void sortCardList(const QStringList &properties, Qt::SortOrder order) const; - void setDeckList(const DeckList &new_deck_list_model); - - AbstractTabDeckEditor *getDeckEditor() - { - return deckEditor; - } - - CardDatabaseDisplayModel *getDatabaseDisplayModel() - { - return databaseDisplayModel; - } - - QTreeView *getDatabaseView() - { - return databaseView; - } - - FilterTreeModel *getFilterModel() - { - return filterModel; - } - - /** - * @return False if the widget is in database display mode and true if it's in visual display mode - */ - bool isVisualDisplayMode() const; - -public slots: - void onSearchModelChanged(); - -signals: - void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance); - void cardHoveredDatabaseDisplay(const ExactCard &hoveredCard); - -protected slots: - void initialize(); - void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance); - void onHover(const ExactCard &hoveredCard); - void addCard(const ExactCard &cardToAdd); - void databaseDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); - void wheelEvent(QWheelEvent *event) override; - void modelDirty() const; - void updateSearch(const QString &search) const; - void onDisplayModeChanged(bool checked); - -private: - QWidget *searchContainer; - QHBoxLayout *searchLayout; - SearchLineEdit *searchEdit; - QPushButton *displayModeButton; - FilterTreeModel *filterModel; - VisualDatabaseDisplayColorFilterWidget *colorFilterWidget; - - QLabel *databaseLoadIndicator; - - QToolButton *clearFilterWidget; - VisualDatabaseDisplayFilterToolbarWidget *filterContainer; - KeySignals searchKeySignals; - AbstractTabDeckEditor *deckEditor; - CardDatabaseModel *databaseModel; - CardDatabaseDisplayModel *databaseDisplayModel; - QTreeView *databaseView; - QList *cards; - QVBoxLayout *mainLayout; - QScrollArea *scrollArea; - FlowWidget *flowWidget; - QWidget *overlapCategories; - QVBoxLayout *overlapCategoriesLayout; - OverlapControlWidget *overlapControlWidget; - CardSizeWidget *cardSizeWidget; - QTimer *debounceTimer; - QTimer *loadCardsTimer; - - int debounceTime = 300; // in Ms - int currentPage = 0; // Current page index - int cardsPerPage = 100; // Number of cards per page - - void highlightAllSearchEdit(); - -protected: - void resizeEvent(QResizeEvent *event) override; -}; - -#endif // VISUAL_DATABASE_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp deleted file mode 100644 index 5364fa813..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "visual_database_filter_display_widget.h" - -#include "../../../client/settings/cache_settings.h" - -#include -#include -#include -#include -#include -#include - -FilterDisplayWidget::FilterDisplayWidget(QWidget *parent, const QString &filename, FilterTreeModel *_filterModel) - : QWidget(parent), filterFilename(filename), filterModel(_filterModel) -{ - setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - // Create layout - auto *layout = new QHBoxLayout(this); - layout->setContentsMargins(5, 5, 5, 5); - layout->setSpacing(5); - - // Filter button (displays filename) - filterButton = new QPushButton(filterFilename, this); - layout->addWidget(filterButton); - - // Create close button (inside the filter button) - closeButton = new QPushButton("x", this); - closeButton->setFixedSize(20, 20); // Small square close button - closeButton->setFocusPolicy(Qt::NoFocus); - layout->addWidget(closeButton); - - // Connect the filter button for loading the filter - connect(filterButton, &QPushButton::clicked, this, &FilterDisplayWidget::loadFilter); - - // Connect the close button for deleting the filter - connect(closeButton, &QPushButton::clicked, this, &FilterDisplayWidget::deleteFilter); -} - -QSize FilterDisplayWidget::sizeHint() const -{ - // Calculate the size based on the filter name and the close button - QFontMetrics fm(font()); - int textWidth = fm.horizontalAdvance(filterFilename); - int width = textWidth + 30 + 16; // Space for the filename and close button - int height = fm.height() + 10; // Height based on font size + padding - - return QSize(width, height); -} - -void FilterDisplayWidget::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - emit filterClicked(); - } - QWidget::mousePressEvent(event); -} - -void FilterDisplayWidget::loadFilter() -{ - // Trigger the loading of the filter - emit filterLoadRequested(filterFilename); -} - -void FilterDisplayWidget::deleteFilter() -{ - // Show confirmation dialog before deleting the filter - QMessageBox::StandardButton reply = QMessageBox::question( - this, tr("Confirm Delete"), tr("Are you sure you want to delete the filter '%1'?").arg(filterFilename), - QMessageBox::Yes | QMessageBox::No); - if (reply == QMessageBox::Yes) { - // If confirmed, delete the filter - QString filePath = SettingsCache::instance().getFiltersPath() + QDir::separator() + filterFilename; - QFile file(filePath); - if (file.remove()) { - emit filterDeleted(filterFilename); // Emit signal for deletion - delete this; // Delete this widget - } else { - QMessageBox::warning(this, tr("Delete Failed"), tr("Failed to delete filter '%1'.").arg(filterFilename)); - } - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.h deleted file mode 100644 index 05bf43118..000000000 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_filter_display_widget.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @file visual_database_filter_display_widget.h - * @ingroup VisualCardDatabaseWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DATABASE_FILTER_DISPLAY_WIDGET_H -#define VISUAL_DATABASE_FILTER_DISPLAY_WIDGET_H - -#include -#include -#include -#include - -class FilterTreeModel; - -class FilterDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - explicit FilterDisplayWidget(QWidget *parent, const QString &filename, FilterTreeModel *_filterModel); - ~FilterDisplayWidget() = default; - - QSize sizeHint() const override; - -protected: - void mousePressEvent(QMouseEvent *event) override; - -private slots: - void loadFilter(); - void deleteFilter(); - -signals: - void filterClicked(); - void filterLoadRequested(const QString &filename); - void filterDeleted(const QString &filename); - -private: - QString filterFilename; - FilterTreeModel *filterModel; - QPushButton *filterButton; // Button for the filter text - QPushButton *closeButton; // Close button to delete the filter -}; - -#endif // VISUAL_DATABASE_FILTER_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp deleted file mode 100644 index 79a98fda6..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "visual_deck_display_options_widget.h" - -#include "../tabs/visual_deck_editor/tab_deck_editor_visual.h" - -#include - -VisualDeckDisplayOptionsWidget::VisualDeckDisplayOptionsWidget(QWidget *parent) : QWidget(parent) -{ - groupAndSortLayout = new QHBoxLayout(this); - groupAndSortLayout->setContentsMargins(0, 0, 0, 0); - groupAndSortLayout->setSpacing(3); - groupAndSortLayout->setAlignment(Qt::AlignLeft); - this->setLayout(groupAndSortLayout); - - groupByLabel = new QLabel(this); - - groupByComboBox = new QComboBox(this); - - if (auto tab = QtUtils::findParentOfType(this)) { - auto originalBox = tab->getDeckDockWidget()->getGroupByComboBox(); - groupByComboBox->setModel(originalBox->model()); - groupByComboBox->setModelColumn(originalBox->modelColumn()); - - // Original -> clone - connect(originalBox, QOverload::of(&QComboBox::currentIndexChanged), - [this](int index) { groupByComboBox->setCurrentIndex(index); }); - - // Clone -> original - connect(groupByComboBox, QOverload::of(&QComboBox::currentIndexChanged), - [originalBox](int index) { originalBox->setCurrentIndex(index); }); - } else { - groupByComboBox->addItem( - tr(qPrintable(DeckListModelGroupCriteria::toString(DeckListModelGroupCriteria::MAIN_TYPE))), - DeckListModelGroupCriteria::MAIN_TYPE); - groupByComboBox->addItem( - tr(qPrintable(DeckListModelGroupCriteria::toString(DeckListModelGroupCriteria::MANA_COST))), - DeckListModelGroupCriteria::MANA_COST); - groupByComboBox->addItem( - tr(qPrintable(DeckListModelGroupCriteria::toString(DeckListModelGroupCriteria::COLOR))), - DeckListModelGroupCriteria::COLOR); - groupByComboBox->setMinimumWidth(300); - connect(groupByComboBox, QOverload::of(&QComboBox::currentTextChanged), this, - &VisualDeckDisplayOptionsWidget::groupCriteriaChanged); - emit groupCriteriaChanged(groupByComboBox->currentText()); - } - - sortByLabel = new QLabel(this); - - sortCriteriaButton = new SettingsButtonWidget(this); - sortCriteriaButton->setButtonIcon(QPixmap("theme:icons/sort_arrow_down")); - - sortLabel = new QLabel(sortCriteriaButton); - sortLabel->setWordWrap(true); - - QStringList sortProperties = {"colors", "cmc", "name", "maintype"}; - sortByListWidget = new QListWidget(); - sortByListWidget->setSelectionMode(QAbstractItemView::SingleSelection); - sortByListWidget->setDragDropMode(QAbstractItemView::InternalMove); - sortByListWidget->setDefaultDropAction(Qt::MoveAction); - - for (const QString &property : sortProperties) { - QListWidgetItem *item = new QListWidgetItem(property, sortByListWidget); - item->setFlags(item->flags() | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled); - } - - connect(sortByListWidget->model(), &QAbstractItemModel::rowsMoved, this, - &VisualDeckDisplayOptionsWidget::onSortCriteriaChange); - onSortCriteriaChange(); - - sortByListWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - - sortCriteriaButton->addSettingsWidget(sortLabel); - sortCriteriaButton->addSettingsWidget(sortByListWidget); - - displayTypeButton = new QPushButton(this); - connect(displayTypeButton, &QPushButton::clicked, this, &VisualDeckDisplayOptionsWidget::updateDisplayType); - - groupAndSortLayout->addWidget(groupByLabel); - groupAndSortLayout->addWidget(groupByComboBox); - groupAndSortLayout->addWidget(sortByLabel); - groupAndSortLayout->addWidget(sortCriteriaButton); - groupAndSortLayout->addWidget(displayTypeButton); - - retranslateUi(); -} - -void VisualDeckDisplayOptionsWidget::retranslateUi() -{ - groupByLabel->setText(tr("Group by:")); - groupByComboBox->setToolTip(tr("Change how cards are divided into categories/groups.")); - sortByLabel->setText(tr("Sort by:")); - sortLabel->setText(tr("Click and drag to change the sort order within the groups")); - sortCriteriaButton->setToolTip(tr("Configure how cards are sorted within their groups")); - displayTypeButton->setText(tr("Toggle Layout: Overlap")); - displayTypeButton->setToolTip( - tr("Change how cards are displayed within zones (i.e. overlapped or fully visible.)")); -} - -void VisualDeckDisplayOptionsWidget::onSortCriteriaChange() -{ - QStringList selectedCriteria; - for (int i = 0; i < sortByListWidget->count(); ++i) { - QListWidgetItem *item = sortByListWidget->item(i); - selectedCriteria.append(item->text()); // Collect user-defined sort order - } - - emit sortCriteriaChanged(selectedCriteria); -} - -void VisualDeckDisplayOptionsWidget::updateDisplayType() -{ - // Toggle the display type - currentDisplayType = (currentDisplayType == DisplayType::Overlap) ? DisplayType::Flat : DisplayType::Overlap; - - // Update UI and emit signal - switch (currentDisplayType) { - case DisplayType::Flat: - displayTypeButton->setText(tr("Toggle Layout: Flat")); - break; - case DisplayType::Overlap: - displayTypeButton->setText(tr("Toggle Layout: Overlap")); - break; - } - emit displayTypeChanged(currentDisplayType); -} diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.h b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.h deleted file mode 100644 index 7a447753f..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H -#define COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H - -#include "visual_deck_editor_widget.h" - -#include -#include -#include -#include -#include -#include - -/** - * @class VisualDeckDisplayOptionsWidget - * @brief A widget that controls how deck cards are displayed in the visual deck editor. - * - * This widget provides: - * - A **group-by** selector (QComboBox) - * - A **sort-by** multi-criteria, draggable list (QListWidget within a SettingsButtonWidget) - * - A **display-type toggler** (flat vs. overlap layout) - * - * Depending on whether the parent is a VisualDeckEditorWidget, this widget can mirror the - * original group by checkbox from the main deck editor UI to maintain synchronization. - * - * It emits signals whenever the grouping criterion, sorting criteria, or display mode changes. - */ -class VisualDeckDisplayOptionsWidget : public QWidget -{ - Q_OBJECT -signals: - /** - * @brief Emitted when the display type (flat or overlapping layout) changes. - * @param displayType The newly selected display layout. - */ - void displayTypeChanged(const DisplayType &displayType); - - /** - * @brief Emitted when a new grouping criterion is selected. - * @param activeGroupCriteria Name of the selected group-by criterion. - */ - void groupCriteriaChanged(const QString &activeGroupCriteria); - - /** - * @brief Emitted when the order of sort criteria changes. - * @param activeSortCriteria Ordered list of sorting keys. - */ - void sortCriteriaChanged(const QStringList &activeSortCriteria); - -public slots: - /** - * @brief Updates all UI text for retranslation/localization. - * - * Called when the application language changes. - */ - void retranslateUi(); - -public: - /** - * @brief Constructs a new VisualDeckDisplayOptionsWidget. - * @param parent The parent QWidget—may trigger cloning of models if the parent is a visual deck editor. - */ - explicit VisualDeckDisplayOptionsWidget(QWidget *parent); - - /** - * @brief Gets the current display type (Overlap or Flat). - */ - DisplayType getDisplayType() const - { - return currentDisplayType; - } - - /** - * @brief Gets the currently active group-by criterion. - */ - QString getActiveGroupCriteria() const - { - return activeGroupCriteria; - } - - /** - * @brief Gets the currently active ordered sort criteria. - */ - QStringList getActiveSortCriteria() const - { - return activeSortCriteria; - } - -private slots: - /** - * @brief Slot triggered whenever the sort list is reordered. - * - * Reads the QListWidget’s order and emits `sortCriteriaChanged()`. - */ - void onSortCriteriaChange(); - - /** - * @brief Toggles the display layout between flat and overlapping modes. - * - * Emits `displayTypeChanged()`. - */ - void updateDisplayType(); - -private: - /// Layout for grouping and sorting UI elements. - QHBoxLayout *groupAndSortLayout; - - /// Current deck display type. - DisplayType currentDisplayType = DisplayType::Overlap; - - /// Button used to toggle the display layout. - QPushButton *displayTypeButton; - - /// Label for the group-by selector. - QLabel *groupByLabel; - - /// Combo box listing group-by criteria. - QComboBox *groupByComboBox; - - /// Currently active group-by criterion. - QString activeGroupCriteria = "maintype"; - - /// Encapsulates the sort settings widgets (label + list). - SettingsButtonWidget *sortCriteriaButton; - - /// Label for “Sort by”. - QLabel *sortByLabel; - - /// Descriptive label inside the sort criteria button. - QLabel *sortLabel; - - /// Draggable list of sort criteria. - QListWidget *sortByListWidget; - - /// Ordered list of current sort criteria. - QStringList activeSortCriteria = {"name", "cmc", "colors", "maintype"}; -}; - -#endif // COCKATRICE_VISUAL_DECK_DISPLAY_OPTIONS_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp deleted file mode 100644 index da4fe09e5..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "visual_deck_editor_placeholder_widget.h" - -VisualDeckEditorPlaceholderWidget::VisualDeckEditorPlaceholderWidget(QWidget *parent) : QWidget(parent) -{ - mainLayout = new QVBoxLayout(this); - mainLayout->setAlignment(Qt::AlignCenter); - setLayout(mainLayout); - - // Image label with the background image - imageLabel = new QLabel(this); - imageLabel->setAlignment(Qt::AlignCenter); - imageLabel->setStyleSheet(R"( - QLabel { - background-image: url(theme:backgrounds/card_triplet.svg); - background-repeat: no-repeat; - background-position: center; - } - )"); - imageLabel->setFixedSize(300, 300); - - textLabel = new QLabel(this); - textLabel->setAlignment(Qt::AlignCenter); - textLabel->setWordWrap(true); - textLabel->setStyleSheet(R"( - QLabel { - color: palette(mid); - font-size: 14px; - padding: 10px; - } - )"); - - mainLayout->addWidget(imageLabel); - mainLayout->addWidget(textLabel); - - retranslateUi(); -} - -void VisualDeckEditorPlaceholderWidget::retranslateUi() -{ - textLabel->setText(tr("Add cards using the search bar or database tab to have them appear here")); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.h b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.h deleted file mode 100644 index de2362a81..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef COCKATRICE_VISUAL_DECK_EDITOR_PLACEHOLDER_WIDGET_H -#define COCKATRICE_VISUAL_DECK_EDITOR_PLACEHOLDER_WIDGET_H - -#include -#include -#include - -class VisualDeckEditorPlaceholderWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDeckEditorPlaceholderWidget(QWidget *parent = nullptr); - void retranslateUi(); - -private: - QVBoxLayout *mainLayout; - QLabel *imageLabel; - QLabel *textLabel; -}; - -#endif // COCKATRICE_VISUAL_DECK_EDITOR_PLACEHOLDER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp deleted file mode 100644 index cc35372b0..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "visual_deck_editor_sample_hand_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../../deck_loader/deck_loader.h" -#include "../cards/card_info_picture_widget.h" -#include "../deck_analytics/analyzer_modules/draw_probability/draw_probability_widget.h" -#include "../deck_analytics/deck_list_statistics_analyzer.h" - -#include -#include -#include - -VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *parent, - DeckListModel *_deckListModel, - DeckListStatisticsAnalyzer *_statsAnalyzer) - : QWidget(parent), deckListModel(_deckListModel), statsAnalyzer(_statsAnalyzer) -{ - layout = new QVBoxLayout(this); - layout->setSpacing(0); - setLayout(layout); - - auto upperLayout = new QVBoxLayout(); - upperLayout->setContentsMargins(0, 0, 0, 0); - upperLayout->setSpacing(0); - - resetAndHandSizeContainerWidget = new QWidget(this); - resetAndHandSizeLayout = new QHBoxLayout(resetAndHandSizeContainerWidget); - resetAndHandSizeLayout->setContentsMargins(11, 0, 11, 0); - resetAndHandSizeContainerWidget->setLayout(resetAndHandSizeLayout); - - resetButton = new QPushButton(this); - connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay())); - resetAndHandSizeLayout->addWidget(resetButton); - - handSizeSpinBox = new QSpinBox(this); - handSizeSpinBox->setValue(SettingsCache::instance().getVisualDeckEditorSampleHandSize()); - handSizeSpinBox->setMinimum(1); - connect(handSizeSpinBox, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), - &SettingsCache::setVisualDeckEditorSampleHandSize); - connect(handSizeSpinBox, qOverload(&QSpinBox::valueChanged), this, - &VisualDeckEditorSampleHandWidget::updateDisplay); - resetAndHandSizeLayout->addWidget(handSizeSpinBox); - - upperLayout->addWidget(resetAndHandSizeContainerWidget); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - upperLayout->addWidget(flowWidget); - - cardSizeWidget = new CardSizeWidget(this, flowWidget); - upperLayout->addWidget(cardSizeWidget); - - auto upperLayoutWidget = new QWidget(this); - upperLayoutWidget->setLayout(upperLayout); - - drawProbabilityWidget = new DrawProbabilityWidget(this, statsAnalyzer); - - auto *splitter = new QSplitter(this); - splitter->setObjectName("splitter"); - splitter->setOrientation(Qt::Vertical); - - splitter->addWidget(upperLayoutWidget); - splitter->addWidget(drawProbabilityWidget); - - layout->addWidget(splitter); - - retranslateUi(); -} - -void VisualDeckEditorSampleHandWidget::retranslateUi() -{ - resetButton->setText(tr("Draw a new sample hand")); - handSizeSpinBox->setToolTip(tr("Sample hand size")); -} - -void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel) -{ - deckListModel = deckModel; - // connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorSampleHandWidget::updateDisplay); - updateDisplay(); -} - -void VisualDeckEditorSampleHandWidget::updateDisplay() -{ - flowWidget->clearLayout(); - for (const ExactCard &card : getRandomCards(handSizeSpinBox->value())) { - auto displayWidget = new CardInfoPictureWidget(this); - displayWidget->setCard(card); - displayWidget->setScaleFactor(cardSizeWidget->getSlider()->value()); - connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, displayWidget, - &CardInfoPictureWidget::setScaleFactor); - flowWidget->addWidget(displayWidget); - } -} - -static QList cardNodesToExactCards(QList nodes) -{ - QList cards; - for (auto node : nodes) { - ExactCard card = CardDatabaseManager::query()->getCard(node->toCardRef()); - if (card) { - for (int k = 0; k < node->getNumber(); ++k) { - cards.append(card); - } - } else { - qDebug() << "Card not found in database!"; - } - } - - return cards; -} - -QList VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGet) -{ - QList randomCards; - if (!deckListModel) - return randomCards; - - QList mainDeckCards = cardNodesToExactCards(deckListModel->getCardNodesForZone(DECK_ZONE_MAIN)); - - if (mainDeckCards.isEmpty()) - return randomCards; - - // Shuffle the deck - std::random_device rd; - std::mt19937 rng(rd()); - std::shuffle(mainDeckCards.begin(), mainDeckCards.end(), rng); - - // Select amountToGet cards - - for (int i = 0; i < qMin(amountToGet, mainDeckCards.size()); ++i) { - randomCards.append(mainDeckCards.at(i)); - } - - std::sort(randomCards.begin(), randomCards.end(), - [](const ExactCard &a, const ExactCard &b) { return a.getInfo().getCmc() < b.getInfo().getCmc(); }); - - return randomCards; -} diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h deleted file mode 100644 index c63c74a4d..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file visual_deck_editor_sample_hand_widget.h - * @ingroup DeckEditorAnalyticsWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H -#define VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H - -#include "../cards/card_size_widget.h" -#include "../deck_analytics/deck_list_statistics_analyzer.h" -#include "../general/layout_containers/flow_widget.h" - -#include -#include -#include -#include - -class DrawProbabilityWidget; -class VisualDeckEditorSampleHandWidget : public QWidget -{ - Q_OBJECT -public: - VisualDeckEditorSampleHandWidget(QWidget *parent, - DeckListModel *deckListModel, - DeckListStatisticsAnalyzer *statsAnalyzer); - QList getRandomCards(int amountToGet); - -public slots: - void updateDisplay(); - void setDeckModel(DeckListModel *deckModel); - void retranslateUi(); - -private: - DeckListModel *deckListModel; - DeckListStatisticsAnalyzer *statsAnalyzer; - QVBoxLayout *layout; - QWidget *resetAndHandSizeContainerWidget; - QHBoxLayout *resetAndHandSizeLayout; - QPushButton *resetButton; - QSpinBox *handSizeSpinBox; - FlowWidget *flowWidget; - DrawProbabilityWidget *drawProbabilityWidget; - CardSizeWidget *cardSizeWidget; -}; - -#endif // VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp deleted file mode 100644 index e957eb304..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp +++ /dev/null @@ -1,417 +0,0 @@ -#include "visual_deck_editor_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../../../main.h" -#include "../../deck_loader/deck_loader.h" -#include "../../layouts/overlap_layout.h" -#include "../cards/card_info_picture_with_text_overlay_widget.h" -#include "../cards/deck_card_zone_display_widget.h" -#include "../general/layout_containers/flow_widget.h" -#include "../tabs/visual_deck_editor/tab_deck_editor_visual.h" -#include "../tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h" -#include "visual_deck_display_options_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, - DeckListModel *_deckListModel, - QItemSelectionModel *_selectionModel) - : QWidget(parent), deckListModel(_deckListModel), selectionModel(_selectionModel) -{ - // The Main Widget and Main Layout, which contain a single Widget: The Scroll Area - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - mainLayout = new QVBoxLayout(this); - setLayout(mainLayout); - mainLayout->setContentsMargins(9, 0, 9, 5); - mainLayout->setSpacing(0); - - initializeDisplayOptionsAndSearchWidget(); - - initializeScrollAreaAndZoneContainer(); - - cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckEditorCardSize()); - connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(), - &SettingsCache::setVisualDeckEditorCardSize); - - mainLayout->addWidget(displayOptionsAndSearch); - mainLayout->addWidget(scrollArea); - mainLayout->addWidget(cardSizeWidget); - - connectDeckListModel(); - - constructZoneWidgetsFromDeckListModel(); - - if (selectionModel) { - connect(selectionModel, &QItemSelectionModel::selectionChanged, this, - &VisualDeckEditorWidget::onSelectionChanged); - } - - updatePlaceholderVisibility(); - retranslateUi(); -} - -// ===================================================================================================================== -// Constructor helpers -// ===================================================================================================================== - -void VisualDeckEditorWidget::initializeSearchBarAndCompleter() -{ - searchBar = new QLineEdit(this); - connect(searchBar, &QLineEdit::returnPressed, this, [=, this]() { - if (!searchBar->hasFocus()) - return; - - ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()}); - if (card) { - emit cardAdditionRequested(card); - } - }); - - setFocusProxy(searchBar); - setFocusPolicy(Qt::ClickFocus); - - cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this); - cardDatabaseDisplayModel = new CardDatabaseDisplayModel(this); - cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel); - CardSearchModel *searchModel = new CardSearchModel(cardDatabaseDisplayModel, this); - - proxyModel = new CardCompleterProxyModel(this); - proxyModel->setSourceModel(searchModel); - proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - proxyModel->setFilterRole(Qt::DisplayRole); - - completer = new QCompleter(proxyModel, this); - completer->setCompletionRole(Qt::DisplayRole); - completer->setCompletionMode(QCompleter::PopupCompletion); - completer->setCaseSensitivity(Qt::CaseInsensitive); - completer->setFilterMode(Qt::MatchContains); - completer->setMaxVisibleItems(15); - searchBar->setCompleter(completer); - - // Update suggestions dynamically - connect(searchBar, &QLineEdit::textEdited, searchModel, &CardSearchModel::updateSearchResults); - connect(searchBar, &QLineEdit::textEdited, this, [=, this](const QString &text) { - // Ensure substring matching - QString pattern = ".*" + QRegularExpression::escape(text) + ".*"; - proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); - - if (!text.isEmpty()) { - completer->complete(); // Force the dropdown to appear - } - }); - - connect(completer, static_cast(&QCompleter::activated), this, - [=, this](const QString &completion) { - // Prevent the text from changing automatically when navigating with arrow keys - if (searchBar->text() != completion) { - searchBar->setText(completion); // Set the completion explicitly - searchBar->setCursorPosition(searchBar->text().length()); // Move cursor to the end - } - }); - - // Ensure that the text stays consistent during selection - connect(searchBar, &QLineEdit::textEdited, this, [=, this](const QString &text) { - if (searchBar->hasFocus() && !searchBar->completer()->popup()->isVisible()) { - // Allow text to change when typing, but not when navigating the completer - QString pattern = ".*" + QRegularExpression::escape(text) + ".*"; - proxyModel->setFilterRegularExpression( - QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption)); - } - }); - - // Search button functionality - searchPushButton = new QPushButton(this); - connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { - ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()}); - if (card) { - emit cardAdditionRequested(card); - } - }); -} - -void VisualDeckEditorWidget::initializeDisplayOptionsWidget() -{ - displayOptionsWidget = new VisualDeckDisplayOptionsWidget(this); - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::displayTypeChanged, this, - &VisualDeckEditorWidget::displayTypeChanged); - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::groupCriteriaChanged, this, - &VisualDeckEditorWidget::activeGroupCriteriaChanged); - connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::sortCriteriaChanged, this, - &VisualDeckEditorWidget::activeSortCriteriaChanged); -} - -void VisualDeckEditorWidget::initializeDisplayOptionsAndSearchWidget() -{ - initializeSearchBarAndCompleter(); - - initializeDisplayOptionsWidget(); - - displayOptionsAndSearch = new QWidget(this); - displayOptionsAndSearchLayout = new QHBoxLayout(displayOptionsAndSearch); - displayOptionsAndSearchLayout->setContentsMargins(0, 0, 0, 0); - displayOptionsAndSearchLayout->setAlignment(Qt::AlignLeft); - displayOptionsAndSearch->setLayout(displayOptionsAndSearchLayout); - - displayOptionsAndSearchLayout->addWidget(displayOptionsWidget); - displayOptionsAndSearchLayout->addWidget(searchBar); - displayOptionsAndSearchLayout->addWidget(searchPushButton); -} - -void VisualDeckEditorWidget::initializeScrollAreaAndZoneContainer() -{ - scrollArea = new QScrollArea(this); - scrollArea->setWidgetResizable(true); - scrollArea->setMinimumSize(0, 0); - - // Set scrollbar policies - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - - zoneContainer = new QWidget(scrollArea); - zoneContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - zoneContainer->setObjectName("zoneContainer"); - zoneContainerLayout = new QVBoxLayout(zoneContainer); - zoneContainer->setLayout(zoneContainerLayout); - - // Create placeholder widget - placeholderWidget = new VisualDeckEditorPlaceholderWidget(zoneContainer); - zoneContainerLayout->addWidget(placeholderWidget); - - scrollArea->addScrollBarWidget(zoneContainer, Qt::AlignHCenter); - scrollArea->setWidget(zoneContainer); -} - -void VisualDeckEditorWidget::connectDeckListModel() -{ - connect(deckListModel, &DeckListModel::modelReset, this, &VisualDeckEditorWidget::decklistModelReset); - connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorWidget::decklistDataChanged); - connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &VisualDeckEditorWidget::onCardAddition); - connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &VisualDeckEditorWidget::onCardRemoval); -} - -void VisualDeckEditorWidget::retranslateUi() -{ - searchBar->setPlaceholderText(tr("Type a card name here for suggestions from the database...")); - searchPushButton->setText(tr("Quick search and add card")); - searchPushButton->setToolTip(tr("Search for closest match in the database (with auto-suggestions) and add " - "preferred printing to the deck on pressing enter")); - - if (placeholderWidget) { - placeholderWidget->retranslateUi(); - } -} - -void VisualDeckEditorWidget::updatePlaceholderVisibility() -{ - if (placeholderWidget) { - placeholderWidget->setVisible(indexToWidgetMap.isEmpty()); - } -} - -// ===================================================================================================================== -// Display Widget Management -// ===================================================================================================================== - -void VisualDeckEditorWidget::constructZoneWidgetForIndex(QPersistentModelIndex persistent) -{ - QString zoneName = - persistent.sibling(persistent.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString(); - DeckCardZoneDisplayWidget *zoneDisplayWidget = new DeckCardZoneDisplayWidget( - zoneContainer, deckListModel, selectionModel, persistent, zoneName, - displayOptionsWidget->getActiveGroupCriteria(), displayOptionsWidget->getActiveSortCriteria(), - displayOptionsWidget->getDisplayType(), 20, 10, cardSizeWidget); - connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardHovered, this, &VisualDeckEditorWidget::onHover); - connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::cardClicked, this, &VisualDeckEditorWidget::onCardClick); - connect(zoneDisplayWidget, &DeckCardZoneDisplayWidget::requestCleanup, this, - &VisualDeckEditorWidget::cleanupInvalidZones); - connect(this, &VisualDeckEditorWidget::activeSortCriteriaChanged, zoneDisplayWidget, - &DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged); - connect(this, &VisualDeckEditorWidget::activeGroupCriteriaChanged, zoneDisplayWidget, - &DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged); - connect(this, &VisualDeckEditorWidget::displayTypeChanged, zoneDisplayWidget, - &DeckCardZoneDisplayWidget::refreshDisplayType); - zoneDisplayWidget->refreshDisplayType(displayOptionsWidget->getDisplayType()); - zoneContainerLayout->addWidget(zoneDisplayWidget); - - indexToWidgetMap.insert(persistent, zoneDisplayWidget); -} - -void VisualDeckEditorWidget::constructZoneWidgetsFromDeckListModel() -{ - QSortFilterProxyModel proxy; - proxy.setSourceModel(deckListModel); - proxy.setSortRole(Qt::EditRole); - proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder); - - for (int i = 0; i < proxy.rowCount(); ++i) { - QModelIndex proxyIndex = proxy.index(i, 0); - QModelIndex sourceIndex = proxy.mapToSource(proxyIndex); - - // Make a persistent index from the *source* model - QPersistentModelIndex persistent(sourceIndex); - - if (indexToWidgetMap.contains(persistent)) { - continue; - } - - constructZoneWidgetForIndex(persistent); - } - updatePlaceholderVisibility(); -} - -void VisualDeckEditorWidget::updateZoneWidgets() -{ -} - -void VisualDeckEditorWidget::clearAllDisplayWidgets() -{ - for (auto idx : indexToWidgetMap.keys()) { - auto displayWidget = indexToWidgetMap.value(idx); - zoneContainerLayout->removeWidget(displayWidget); - indexToWidgetMap.remove(idx); - delete displayWidget; - } - updatePlaceholderVisibility(); -} - -void VisualDeckEditorWidget::cleanupInvalidZones(DeckCardZoneDisplayWidget *displayWidget) -{ - zoneContainerLayout->removeWidget(displayWidget); - for (auto idx : indexToWidgetMap.keys()) { - if (!idx.isValid()) { - indexToWidgetMap.remove(idx); - } - } - delete displayWidget; - updatePlaceholderVisibility(); -} - -// ===================================================================================================================== -// DeckModel Signals Management -// ===================================================================================================================== - -void VisualDeckEditorWidget::onCardAddition(const QModelIndex &parent, int first, int last) -{ - if (parent == deckListModel->getRoot()) { - for (int i = first; i <= last; i++) { - QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(i, 0, deckListModel->getRoot())); - - if (indexToWidgetMap.contains(index)) { - continue; - } - - constructZoneWidgetForIndex(index); - } - } - updatePlaceholderVisibility(); -} - -void VisualDeckEditorWidget::onCardRemoval(const QModelIndex &parent, int first, int last) -{ - Q_UNUSED(parent); - Q_UNUSED(first); - Q_UNUSED(last); - for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) { - if (!idx.isValid()) { - zoneContainerLayout->removeWidget(indexToWidgetMap.value(idx)); - indexToWidgetMap.value(idx)->deleteLater(); - indexToWidgetMap.remove(idx); - } - } - updatePlaceholderVisibility(); -} - -void VisualDeckEditorWidget::decklistModelReset() -{ - clearAllDisplayWidgets(); - constructZoneWidgetsFromDeckListModel(); -} - -void VisualDeckEditorWidget::decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight) -{ - // Might use these at some point. - Q_UNUSED(topLeft); - Q_UNUSED(bottomRight); - // Necessary to delay this in this manner else the updateDisplay will nuke widgets while their onClick event - // hasn't returned yet. Interval of 0 means QT will schedule this after the current event loop has finished. - updateZoneWidgets(); -} - -// ===================================================================================================================== -// User Interaction -// ===================================================================================================================== - -void VisualDeckEditorWidget::onCardClick(QMouseEvent *event, - CardInfoPictureWithTextOverlayWidget *instance, - QString zoneName) -{ - emit cardClicked(event, instance, zoneName); -} - -void VisualDeckEditorWidget::onHover(const ExactCard &hoveredCard) -{ - // If user has any card selected, ignore hover - if (selectionModel->hasSelection()) { - return; - } - - // If nothing is selected -> this is our "active/preview" card - emit activeCardChanged(hoveredCard); - - // TODO: highlight hovered card visually: - // highlightHoveredCard(hoveredCard); -} - -void VisualDeckEditorWidget::setSelectionModel(QItemSelectionModel *model) -{ - if (selectionModel == model) { - return; - } - - if (selectionModel) { - // TODO: Possibly disconnect old ones? - } - - selectionModel = model; - - if (selectionModel) { - connect(selectionModel, &QItemSelectionModel::selectionChanged, this, - &VisualDeckEditorWidget::onSelectionChanged); - } -} - -void VisualDeckEditorWidget::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) -{ - for (auto &range : selected) { - for (int row = range.top(); row <= range.bottom(); ++row) { - QModelIndex idx = range.model()->index(row, 0, range.parent()); - auto it = indexToWidgetMap.find(QPersistentModelIndex(idx)); - if (it != indexToWidgetMap.end()) { - // it.value()->setHighlighted(true); - } - } - } - - for (auto &range : deselected) { - for (int row = range.top(); row <= range.bottom(); ++row) { - QModelIndex idx = range.model()->index(row, 0, range.parent()); - auto it = indexToWidgetMap.find(QPersistentModelIndex(idx)); - if (it != indexToWidgetMap.end()) { - // it.value()->setHighlighted(false); - } - } - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.h b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.h deleted file mode 100644 index 13065d623..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file visual_deck_editor_widget.h - * @ingroup DeckEditors - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_EDITOR_H -#define VISUAL_DECK_EDITOR_H - -#include "../cards/card_info_picture_with_text_overlay_widget.h" -#include "../cards/card_size_widget.h" -#include "../general/layout_containers/overlap_control_widget.h" -#include "../quick_settings/settings_button_widget.h" -#include "visual_deck_editor_placeholder_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class VisualDeckDisplayOptionsWidget; -class DeckCardZoneDisplayWidget; -enum class DisplayType -{ - Flat, - Overlap -}; - -class VisualDeckEditorWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDeckEditorWidget(QWidget *parent, DeckListModel *deckListModel, QItemSelectionModel *selectionModel); - void retranslateUi(); - void clearAllDisplayWidgets(); - - void setDeckList(const DeckList &_deckListModel); - - void setSelectionModel(QItemSelectionModel *model); - void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); - void updatePlaceholderVisibility(); - QItemSelectionModel *getSelectionModel() const - { - return selectionModel; - } - - QLineEdit *searchBar; - CardSizeWidget *cardSizeWidget; - -public slots: - void decklistDataChanged(QModelIndex topLeft, QModelIndex bottomRight); - void updateZoneWidgets(); - void cleanupInvalidZones(DeckCardZoneDisplayWidget *displayWidget); - void onCardAddition(const QModelIndex &parent, int first, int last); - void onCardRemoval(const QModelIndex &parent, int first, int last); - void constructZoneWidgetForIndex(QPersistentModelIndex persistent); - void constructZoneWidgetsFromDeckListModel(); - -signals: - void activeCardChanged(const ExactCard &activeCard); - void activeGroupCriteriaChanged(QString activeGroupCriteria); - void activeSortCriteriaChanged(QStringList activeSortCriteria); - void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName); - void cardAdditionRequested(const ExactCard &card); - void displayTypeChanged(DisplayType displayType); - -protected: - void initializeSearchBarAndCompleter(); - void initializeDisplayOptionsWidget(); - void initializeDisplayOptionsAndSearchWidget(); - void initializeScrollAreaAndZoneContainer(); - void connectDeckListModel(); - -protected slots: - void onHover(const ExactCard &hoveredCard); - void onCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName); - void decklistModelReset(); - -private: - DeckListModel *deckListModel; - QItemSelectionModel *selectionModel; - QVBoxLayout *mainLayout; - CardDatabaseModel *cardDatabaseModel; - CardDatabaseDisplayModel *cardDatabaseDisplayModel; - CardCompleterProxyModel *proxyModel; - QCompleter *completer; - QWidget *displayOptionsAndSearch; - QHBoxLayout *displayOptionsAndSearchLayout; - VisualDeckDisplayOptionsWidget *displayOptionsWidget; - QPushButton *searchPushButton; - QScrollArea *scrollArea; - QWidget *zoneContainer; - QVBoxLayout *zoneContainerLayout; - VisualDeckEditorPlaceholderWidget *placeholderWidget; - // OverlapControlWidget *overlapControlWidget; - QHash indexToWidgetMap; -}; - -#endif // VISUAL_DECK_EDITOR_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp deleted file mode 100644 index 575632724..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "deck_preview_color_identity_filter_widget.h" - -#include "../../cards/additional_info/mana_symbol_widget.h" -#include "deck_preview_widget.h" - -#include - -DeckPreviewColorIdentityFilterWidget::DeckPreviewColorIdentityFilterWidget(VisualDeckStorageWidget *parent) - : QWidget(parent), layout(new QHBoxLayout(this)) -{ - setLayout(layout); - layout->setSpacing(5); - layout->setContentsMargins(0, 0, 0, 0); - - QString fullColorIdentity = "WUBRG"; - for (const QChar &color : fullColorIdentity) { - auto *manaSymbol = new ManaSymbolWidget(this, color, false, true); - manaSymbol->setFixedWidth(25); - - layout->addWidget(manaSymbol); - - // Initialize the activeColors map - activeColors[color] = false; - - // Connect the color toggled signal - connect(manaSymbol, &ManaSymbolWidget::colorToggled, this, - &DeckPreviewColorIdentityFilterWidget::handleColorToggled); - } - - toggleButton = new QPushButton(this); - toggleButton->setCheckable(true); - layout->addWidget(toggleButton); - - // Connect the button's toggled signal - connect(toggleButton, &QPushButton::toggled, this, &DeckPreviewColorIdentityFilterWidget::updateFilterMode); - connect(this, &DeckPreviewColorIdentityFilterWidget::activeColorsChanged, parent, - &VisualDeckStorageWidget::updateColorFilter); - connect(this, &DeckPreviewColorIdentityFilterWidget::filterModeChanged, parent, - &VisualDeckStorageWidget::updateColorFilter); - - // Call retranslateUi to set the initial text - retranslateUi(); -} - -void DeckPreviewColorIdentityFilterWidget::retranslateUi() -{ - // Set the toggle button text based on the current mode - toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); - toggleButton->setToolTip(tr("Color identity filter mode (AND/OR/NOT conjunctions of filters)")); -} - -void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar color, bool active) -{ - activeColors[color] = active; - emit activeColorsChanged(); -} - -void DeckPreviewColorIdentityFilterWidget::updateFilterMode(bool checked) -{ - exactMatchMode = checked; // Toggle between modes - retranslateUi(); // Update the button text - emit filterModeChanged(exactMatchMode); -} - -void DeckPreviewColorIdentityFilterWidget::filterWidgets(QList widgets) -{ - // Check if no colors are active - bool noColorsActive = true; - for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) { - if (it.value()) { - noColorsActive = false; - break; - } - } - - // If no colors are active, return the unfiltered list of widgets - if (noColorsActive) { - for (DeckPreviewWidget *previewWidget : widgets) { - previewWidget->filteredByColor = false; - } - } - - for (const auto &widget : widgets) { - QString colorIdentity = widget->getColorIdentity(); - - bool matchesFilter = true; - if (exactMatchMode) { - // Exact match mode: active colors must exactly match colorIdentity - - // Create a set of active colors - QSet activeColorSet; - for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) { - if (it.value()) { - activeColorSet.insert(it.key().toUpper()); // Use uppercase for uniformity - } - } - - // Create a set of colors from the color identity string - QSet colorIdentitySet; - for (const QChar &color : colorIdentity) { - colorIdentitySet.insert(color.toUpper()); // Ensure case uniformity - } - - // Compare the sets: the sets must match exactly - if (activeColorSet != colorIdentitySet) { - matchesFilter = false; - } - } else { - // Includes mode: colorIdentity must contain all active colors - for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) { - if (it.value() && !colorIdentity.contains(it.key())) { - matchesFilter = false; - break; - } - } - } - - widget->filteredByColor = !matchesFilter; - } -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.h deleted file mode 100644 index 551dbb35c..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file deck_preview_color_identity_filter_widget.h - * @ingroup VisualDeckPreviewWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_COLOR_IDENTITY_FILTER_WIDGET_H -#define DECK_PREVIEW_COLOR_IDENTITY_FILTER_WIDGET_H - -#include "../visual_deck_storage_widget.h" - -#include -#include -#include - -class DeckPreviewWidget; -class VisualDeckStorageWidget; - -class DeckPreviewColorIdentityFilterWidget : public QWidget -{ - Q_OBJECT - -public: - explicit DeckPreviewColorIdentityFilterWidget(VisualDeckStorageWidget *parent); - void retranslateUi(); - void filterWidgets(QList widgets); - -signals: - void filterModeChanged(bool exactMatchMode); - void activeColorsChanged(); - -private slots: - void handleColorToggled(QChar color, bool active); - void updateFilterMode(bool checked); - -private: - QHBoxLayout *layout; - QPushButton *toggleButton; - QMap activeColors; - bool exactMatchMode = false; // Default to "includes" mode -}; - -#endif // DECK_PREVIEW_COLOR_IDENTITY_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp deleted file mode 100644 index 8cd1004de..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "deck_preview_deck_tags_display_widget.h" - -#include "../../../../client/settings/cache_settings.h" -#include "../../../../interface/widgets/dialogs/dlg_convert_deck_to_cod_format.h" -#include "../../../../interface/widgets/tabs/tab_deck_editor.h" -#include "../../general/layout_containers/flow_widget.h" -#include "deck_preview_tag_addition_widget.h" -#include "deck_preview_tag_dialog.h" -#include "deck_preview_tag_display_widget.h" -#include "deck_preview_widget.h" - -#include -#include -#include - -DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, const QStringList &_tags) - : QWidget(_parent), currentTags(_tags) -{ - - setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - - // Create layout - auto *layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - - setFixedHeight(100); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - - layout->addWidget(flowWidget); - - refreshTags(); -} - -void DeckPreviewDeckTagsDisplayWidget::setTags(const QStringList &_tags) -{ - currentTags = _tags; - refreshTags(); -} - -void DeckPreviewDeckTagsDisplayWidget::refreshTags() -{ - flowWidget->clearLayout(); - - for (const QString &tag : currentTags) { - flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag)); - } - - auto tagAdditionWidget = new DeckPreviewTagAdditionWidget(this, tr("Edit tags ...")); - connect(tagAdditionWidget, &DeckPreviewTagAdditionWidget::tagClicked, this, - &DeckPreviewDeckTagsDisplayWidget::openTagEditDlg); - flowWidget->addWidget(tagAdditionWidget); -} - -/** - * Gets the filepath of all files (no directories) in target directory and all subdirectories - */ -static QStringList getAllFiles(const QString &filePath) -{ - QStringList allFiles; - - // QDirIterator with QDir::Files ensures only files are listed (no directories) - QDirIterator it(filePath, QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); - - while (it.hasNext()) { - allFiles << it.next(); // Add each file path to the list - } - - return allFiles; -} - -/** - * Gets all tags that appear in the deck folder - */ -static QStringList findAllKnownTags() -{ - QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath()); - - QStringList knownTags; - for (const QString &file : allFiles) { - std::optional deckOpt = - DeckLoader::loadFromFile(file, DeckFileFormat::getFormatFromName(file), false); - QStringList tags = deckOpt.has_value() ? deckOpt->deckList.getTags() : QStringList(); - knownTags.append(tags); - knownTags.removeDuplicates(); - } - - return knownTags; -} - -void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg() -{ - if (qobject_cast(parentWidget())) { - // If we're the child of a DeckPreviewWidget, then we need to handle conversion - auto *deckPreviewWidget = qobject_cast(parentWidget()); - - bool canAddTags = promptFileConversionIfRequired(deckPreviewWidget); - - if (canAddTags) { - QStringList knownTags = deckPreviewWidget->visualDeckStorageWidget->tagFilterWidget->getAllKnownTags(); - execTagDialog(knownTags); - } - } else { - // If we're the child of an AbstractTabDeckEditor, then we don't bother with conversion - QStringList knownTags = findAllKnownTags(); - execTagDialog(knownTags); - } -} - -static bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath) -{ - QFileInfo fileInfo(filePath); - QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod"); - - if (QFile::exists(newFileName)) { - QMessageBox::StandardButton reply = - QMessageBox::question(parent, QObject::tr("Overwrite Existing File?"), - QObject::tr("A .cod version of this deck already exists. Overwrite it?"), - QMessageBox::Yes | QMessageBox::No); - return reply == QMessageBox::Yes; - } - return true; // Safe to proceed -} - -static void convertFileToCockatriceFormat(DeckPreviewWidget *deckPreviewWidget) -{ - DeckLoader::convertToCockatriceFormat(deckPreviewWidget->deckLoader->getDeck()); - deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getDeck().lastLoadInfo.fileName; - deckPreviewWidget->refreshBannerCardText(); -} - -/** - * Checks if the deck's file format supports tags. - * If not, then prompt the user for file conversion. - * @return whether the resulting file can support adding tags - */ -bool DeckPreviewDeckTagsDisplayWidget::promptFileConversionIfRequired(DeckPreviewWidget *deckPreviewWidget) -{ - if (DeckFileFormat::getFormatFromName(deckPreviewWidget->filePath) == DeckFileFormat::Cockatrice) { - return true; - } - - // Retrieve saved preference if the prompt is disabled - if (!SettingsCache::instance().getVisualDeckStoragePromptForConversion()) { - if (!SettingsCache::instance().getVisualDeckStorageAlwaysConvert()) { - return false; - } - - if (!confirmOverwriteIfExists(this, deckPreviewWidget->filePath)) { - return false; - } - - convertFileToCockatriceFormat(deckPreviewWidget); - return true; - } - - // Show the dialog to the user - DialogConvertDeckToCodFormat conversionDialog(parentWidget()); - if (conversionDialog.exec() != QDialog::Accepted) { - SettingsCache::instance().setVisualDeckStoragePromptForConversion(!conversionDialog.dontAskAgain()); - SettingsCache::instance().setVisualDeckStorageAlwaysConvert(false); - - return false; - } - - // Try to convert file - if (!confirmOverwriteIfExists(this, deckPreviewWidget->filePath)) { - return false; - } - - convertFileToCockatriceFormat(deckPreviewWidget); - - if (conversionDialog.dontAskAgain()) { - SettingsCache::instance().setVisualDeckStoragePromptForConversion(false); - SettingsCache::instance().setVisualDeckStorageAlwaysConvert(true); - } - - return true; -} - -void DeckPreviewDeckTagsDisplayWidget::execTagDialog(const QStringList &knownTags) -{ - DeckPreviewTagDialog dialog(knownTags, currentTags); - if (dialog.exec() == QDialog::Accepted) { - QStringList updatedTags = dialog.getActiveTags(); - if (updatedTags != currentTags) { - setTags(updatedTags); - emit tagsChanged(updatedTags); - } - } -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h deleted file mode 100644 index bfd0a170d..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file deck_preview_deck_tags_display_widget.h - * @ingroup VisualDeckPreviewWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H -#define DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H - -#include "../../../deck_loader/deck_loader.h" -#include "deck_preview_widget.h" - -#include - -class DeckPreviewWidget; -class DeckPreviewDeckTagsDisplayWidget : public QWidget -{ - Q_OBJECT - - QStringList currentTags; - FlowWidget *flowWidget; - -public: - explicit DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, const QStringList &_tags = {}); - void setTags(const QStringList &_tags); - void refreshTags(); - -public slots: - void openTagEditDlg(); - -private: - bool promptFileConversionIfRequired(DeckPreviewWidget *deckPreviewWidget); - void execTagDialog(const QStringList &knownTags); - -signals: - /** - * Emitted when the tags have changed due to user interaction. - * @param tags The new list of tags. - */ - void tagsChanged(const QStringList &tags); -}; -#endif // DECK_PREVIEW_DECK_TAGS_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp deleted file mode 100644 index fdf4b2a28..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "deck_preview_tag_addition_widget.h" - -#include "../../../../client/settings/cache_settings.h" -#include "../../../../interface/widgets/tabs/abstract_tab_deck_editor.h" - -#include -#include -#include -#include -#include - -DeckPreviewTagAdditionWidget::DeckPreviewTagAdditionWidget(QWidget *_parent, QString _tagName) - : QWidget(_parent), tagName_(std::move(_tagName)) -{ - // Create layout - auto *layout = new QHBoxLayout(this); - layout->setContentsMargins(5, 5, 5, 5); - layout->setSpacing(5); - - // Adjust widget size - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); -} - -QSize DeckPreviewTagAdditionWidget::sizeHint() const -{ - // Calculate the size based on the tag name - QFontMetrics fm(font()); - int textWidth = fm.horizontalAdvance(tagName_); - int width = textWidth + 50; // Add extra padding - int height = fm.height() + 10; // Height based on font size + padding - - return {width, height}; -} - -void DeckPreviewTagAdditionWidget::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - emit tagClicked(); - } - QWidget::mousePressEvent(event); -} - -void DeckPreviewTagAdditionWidget::paintEvent(QPaintEvent *event) -{ - QPainter painter(this); - - // Set background color - QColor backgroundColor = Qt::lightGray; - painter.setBrush(backgroundColor); - painter.setPen(Qt::NoPen); - - // Draw background - painter.drawRect(rect()); - - // Draw border - QColor borderColor = Qt::gray; - QPen borderPen(borderColor, 1); - painter.setPen(borderPen); - painter.drawRect(rect().adjusted(0, 0, -1, -1)); // Adjust for pen width - - // Calculate font size based on widget height - QFont font = painter.font(); - int fontSize = std::max(10, height() / 2); // Ensure a minimum font size of 10 - font.setPointSize(fontSize); - painter.setFont(font); - - // Calculate text rect with margin - int margin = 10; // Left and right margins - QRect textRect(margin, 0, width() - margin * 2, height()); - - // Draw the text with a black border for better legibility - painter.setPen(Qt::black); - - // Draw text border by offsetting - for (int dx = -1; dx <= 1; ++dx) { - for (int dy = -1; dy <= 1; ++dy) { - if (dx != 0 || dy != 0) { - painter.drawText(textRect.translated(dx, dy), Qt::AlignLeft | Qt::AlignVCenter, tagName_); - } - } - } - - // Draw the actual text - painter.setPen(Qt::white); - painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, tagName_); - - QWidget::paintEvent(event); -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.h deleted file mode 100644 index c0fa86d19..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file deck_preview_tag_addition_widget.h - * @ingroup VisualDeckPreviewWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_TAG_ADDITION_WIDGET_H -#define DECK_PREVIEW_TAG_ADDITION_WIDGET_H - -#include "deck_preview_deck_tags_display_widget.h" - -class DeckPreviewTagAdditionWidget : public QWidget -{ - Q_OBJECT - -public: - explicit DeckPreviewTagAdditionWidget(QWidget *_parent, QString _tagName); - [[nodiscard]] QSize sizeHint() const override; - -signals: - void tagClicked(); // Emitted when the tag is clicked - void tagClosed(); // Emitted when the close button is clicked - -protected: - void mousePressEvent(QMouseEvent *event) override; - void paintEvent(QPaintEvent *event) override; - -private: - QString tagName_; -}; - -#endif // DECK_PREVIEW_TAG_ADDITION_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp deleted file mode 100644 index e8a399fe5..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "deck_preview_tag_dialog.h" - -#include "../../../../client/settings/cache_settings.h" -#include "../../../../interface/widgets/dialogs/dlg_default_tags_editor.h" -#include "deck_preview_tag_item_widget.h" - -#include -#include -#include -#include -#include -#include -#include - -DeckPreviewTagDialog::DeckPreviewTagDialog(const QStringList &knownTags, - const QStringList &_activeTags, - QWidget *parent) - : QDialog(parent), activeTags(_activeTags), knownTags_(knownTags) -{ - resize(400, 500); - - QStringList defaultTags = SettingsCache::instance().getVisualDeckStorageDefaultTagsList(); - - // Merge knownTags with defaultTags, ensuring no duplicates - QStringList combinedTags = defaultTags + knownTags + activeTags; - combinedTags.removeDuplicates(); - - // Main layout - mainLayout = new QVBoxLayout(this); - - // Filter bar - filterInput = new QLineEdit(this); - mainLayout->addWidget(filterInput); - - connect(filterInput, &QLineEdit::textChanged, this, &DeckPreviewTagDialog::filterTags); - - // Instruction label - instructionLabel = new QLabel(this); - instructionLabel->setWordWrap(true); - mainLayout->addWidget(instructionLabel); - - // Tag list view - tagListView = new QListWidget(this); - mainLayout->addWidget(tagListView); - - // Populate combined tags - for (const auto &tag : combinedTags) { - auto *item = new QListWidgetItem(tagListView); - auto *tagWidget = new DeckPreviewTagItemWidget(tag, activeTags.contains(tag), this); - tagListView->addItem(item); - tagListView->setItemWidget(item, tagWidget); - - connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged); - } - - // Add tag input layout - auto *addTagLayout = new QHBoxLayout(); - newTagInput = new QLineEdit(this); - addTagButton = new QPushButton(this); - editButton = new QPushButton(this); - connect(editButton, &QPushButton::clicked, this, [this]() { - auto *editor = new DlgDefaultTagsEditor(this); - editor->setAttribute(Qt::WA_DeleteOnClose); - editor->setModal(true); - editor->show(); - QTimer::singleShot(0, editor, [editor]() { - editor->raise(); - editor->activateWindow(); - }); - }); - addTagLayout->addWidget(newTagInput); - addTagLayout->addWidget(addTagButton); - addTagLayout->addWidget(editButton); - mainLayout->addLayout(addTagLayout); - - connect(addTagButton, &QPushButton::clicked, this, &DeckPreviewTagDialog::addTag); - connect(newTagInput, &QLineEdit::textChanged, this, - [this](const QString &text) { addTagButton->setEnabled(!text.trimmed().isEmpty()); }); - - // OK and Cancel buttons - buttonLayout = new QHBoxLayout(this); - okButton = new QPushButton(this); - cancelButton = new QPushButton(this); - - buttonLayout->addStretch(); - buttonLayout->addWidget(okButton); - buttonLayout->addWidget(cancelButton); - mainLayout->addLayout(buttonLayout); - - connect(okButton, &QPushButton::clicked, this, &DeckPreviewTagDialog::accept); - connect(cancelButton, &QPushButton::clicked, this, &DeckPreviewTagDialog::reject); - - connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDefaultTagsListChanged, this, - &DeckPreviewTagDialog::refreshTagList); - - retranslateUi(); -} - -void DeckPreviewTagDialog::retranslateUi() -{ - setWindowTitle(tr("Deck Tags Manager")); - instructionLabel->setText(tr("Manage your deck tags. Check or uncheck tags as needed, or add new ones:")); - newTagInput->setPlaceholderText(tr("Add a new tag (e.g., Aggro️)")); - addTagButton->setText(tr("Add Tag")); - filterInput->setPlaceholderText(tr("Filter tags...")); - okButton->setText(tr("OK")); - editButton->setText(tr("Edit default tags")); - cancelButton->setText(tr("Cancel")); -} - -void DeckPreviewTagDialog::refreshTagList() -{ - // First, clear the current tags in the list view - tagListView->clear(); - - // Get the updated list of tags from SettingsCache - QStringList defaultTags = SettingsCache::instance().getVisualDeckStorageDefaultTagsList(); - QStringList combinedTags = defaultTags + knownTags_ + activeTags; - combinedTags.removeDuplicates(); - - // Re-populate the tag list view - for (const auto &tag : combinedTags) { - auto *item = new QListWidgetItem(tagListView); - auto *tagWidget = new DeckPreviewTagItemWidget(tag, activeTags.contains(tag), this); - tagListView->addItem(item); - tagListView->setItemWidget(item, tagWidget); - - connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged); - } -} - -QStringList DeckPreviewTagDialog::getActiveTags() const -{ - return activeTags; -} - -void DeckPreviewTagDialog::addTag() -{ - QString newTag = newTagInput->text().trimmed(); - if (newTag.isEmpty()) { - QMessageBox::warning(this, tr("Invalid Input"), tr("Tag name cannot be empty!")); - return; - } - - // Prevent duplicate tags - for (int i = 0; i < tagListView->count(); ++i) { - auto *item = tagListView->item(i); - auto *tagWidget = qobject_cast(tagListView->itemWidget(item)); - if (tagWidget && tagWidget->checkBox()->text() == newTag) { - QMessageBox::warning(this, tr("Duplicate Tag"), tr("This tag already exists.")); - return; - } - } - - // Add the new tag - auto *item = new QListWidgetItem(tagListView); - auto *tagWidget = new DeckPreviewTagItemWidget(newTag, true, this); - tagListView->addItem(item); - tagListView->setItemWidget(item, tagWidget); - activeTags.append(newTag); - - connect(tagWidget->checkBox(), &QCheckBox::toggled, this, &DeckPreviewTagDialog::onCheckboxStateChanged); - - // Clear the input field - newTagInput->clear(); -} - -void DeckPreviewTagDialog::filterTags(const QString &text) -{ - for (int i = 0; i < tagListView->count(); ++i) { - auto *item = tagListView->item(i); - auto *tagWidget = qobject_cast(tagListView->itemWidget(item)); - if (tagWidget) { - bool matches = tagWidget->checkBox()->text().contains(text, Qt::CaseInsensitive); - item->setHidden(!matches); - } - } -} - -void DeckPreviewTagDialog::onCheckboxStateChanged() -{ - activeTags.clear(); - for (int i = 0; i < tagListView->count(); ++i) { - auto *item = tagListView->item(i); - auto *tagWidget = qobject_cast(tagListView->itemWidget(item)); - if (tagWidget && tagWidget->checkBox()->isChecked()) { - activeTags.append(tagWidget->checkBox()->text()); - } - } -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h deleted file mode 100644 index 59b330a65..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file deck_preview_tag_dialog.h - * @ingroup VisualDeckPreviewWidgets - * @ingroup Dialogs - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_TAG_DIALOG_H -#define DECK_PREVIEW_TAG_DIALOG_H - -#include -#include -#include -#include -#include - -class DeckPreviewTagDialog : public QDialog -{ - Q_OBJECT - -public: - explicit DeckPreviewTagDialog(const QStringList &knownTags, - const QStringList &activeTags, - QWidget *parent = nullptr); - [[nodiscard]] QStringList getActiveTags() const; - void filterTags(const QString &text); - -private slots: - void addTag(); - void onCheckboxStateChanged(); - void retranslateUi(); - void refreshTagList(); - -private: - QVBoxLayout *mainLayout; - QLabel *instructionLabel; - QListWidget *tagListView; - QLineEdit *filterInput; - QHBoxLayout *addTagLayout; - QLineEdit *newTagInput; - QPushButton *addTagButton; - QHBoxLayout *buttonLayout; - QPushButton *okButton; - QPushButton *editButton; - QPushButton *cancelButton; - QStringList activeTags; - QStringList knownTags_; -}; - -#endif // DECK_PREVIEW_TAG_DIALOG_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp deleted file mode 100644 index db466b77a..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "deck_preview_tag_display_widget.h" - -#include -#include -#include -#include - -DeckPreviewTagDisplayWidget::DeckPreviewTagDisplayWidget(QWidget *parent, const QString &_tagName) - : QWidget(parent), tagName(_tagName), state(TagState::NotSelected) -{ - // Create layout - auto *layout = new QHBoxLayout(this); - layout->setContentsMargins(5, 5, 5, 5); - layout->setSpacing(5); - - // Add a stretch spacer for text and close button separation - // layout->addStretch(); // Ensures the close button stays at the far-right side - - // Create close button - // closeButton = new QPushButton("x", this); - // closeButton->setFixedSize(16, 16); // Small square button - // closeButton->setFocusPolicy(Qt::NoFocus); - - // Set font for close button to ensure the "x" appears correctly - // QFont closeButtonFont = closeButton->font(); - // closeButtonFont.setPointSize(10); // Adjust the size to make the "x" clear - // closeButton->setFont(closeButtonFont); - - // layout->addWidget(closeButton); - - // Adjust widget size - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - - // Connect close button to the remove signal - // connect(closeButton, &QPushButton::clicked, this, &DeckPreviewTagDisplayWidget::tagClosed); -} - -QSize DeckPreviewTagDisplayWidget::sizeHint() const -{ - // Calculate the size based on the tag name and close button - QFontMetrics fm(font()); - int textWidth = fm.horizontalAdvance(tagName); - int width = textWidth + 50; // Add extra padding - int height = fm.height() + 10; // Height based on font size + padding - - return QSize(width, height); -} - -void DeckPreviewTagDisplayWidget::mousePressEvent(QMouseEvent *event) -{ - switch (event->button()) { - case Qt::LeftButton: - setState(state != TagState::Selected ? TagState::Selected : TagState::NotSelected); - break; - case Qt::RightButton: - setState(state != TagState::Excluded ? TagState::Excluded : TagState::NotSelected); - break; - case Qt::MiddleButton: - setState(TagState::NotSelected); - break; - default: - break; - } - - emit tagClicked(); - QWidget::mousePressEvent(event); -} - -void DeckPreviewTagDisplayWidget::paintEvent(QPaintEvent *event) -{ - QPainter painter(this); - - QColor backgroundColor; - QColor borderColor; - int borderWidth; - - switch (state) { - case TagState::Selected: - backgroundColor = QColor(173, 216, 230); // Light blue - borderColor = Qt::blue; - borderWidth = 2; - break; - case TagState::Excluded: - backgroundColor = QColor(255, 182, 193); // Light red/pink - borderColor = Qt::red; - borderWidth = 2; - break; - case TagState::NotSelected: - default: - backgroundColor = Qt::white; - borderColor = Qt::gray; - borderWidth = 1; - break; - } - - painter.setBrush(backgroundColor); - painter.setPen(Qt::NoPen); - painter.drawRect(rect()); - - QPen borderPen(borderColor, borderWidth); - painter.setPen(borderPen); - painter.drawRect(rect().adjusted(0, 0, -1, -1)); - - // Calculate font size based on widget height - QFont font = painter.font(); - int fontSize = std::max(10, height() / 2); // Ensure a minimum font size of 10 - font.setPointSize(fontSize); - painter.setFont(font); - - // Calculate text rect to avoid overlap with the close button - // int closeButtonWidth = closeButton->width(); - int margin = 10; // Left and right margins - QRect textRect(margin, 0, width() - margin * 2, height()); - - // Draw the text with a black border for better legibility - painter.setPen(Qt::black); - - // Draw text border by offsetting - for (int dx = -1; dx <= 1; ++dx) { - for (int dy = -1; dy <= 1; ++dy) { - if (dx != 0 || dy != 0) { - painter.drawText(textRect.translated(dx, dy), Qt::AlignLeft | Qt::AlignVCenter, tagName); - } - } - } - - // Draw the actual text - painter.setPen(Qt::white); - painter.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, tagName); - - QWidget::paintEvent(event); -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h deleted file mode 100644 index a868aa4f1..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_display_widget.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file deck_preview_tag_display_widget.h - * @ingroup VisualDeckPreviewWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_TAG_DISPLAY_WIDGET_H -#define DECK_PREVIEW_TAG_DISPLAY_WIDGET_H - -#include -#include -#include -#include - -enum class TagState -{ - NotSelected, - Selected, - Excluded -}; - -class DeckPreviewTagDisplayWidget : public QWidget -{ - Q_OBJECT - -public: - /** - * @brief Constructor for DeckPreviewTagDisplayWidget. - * @param parent The parent widget. - * @param tagName The name of the tag to display. - */ - explicit DeckPreviewTagDisplayWidget(QWidget *parent = nullptr, const QString &tagName = ""); - [[nodiscard]] QSize sizeHint() const override; - [[nodiscard]] QString getTagName() const - { - return tagName; - } - [[nodiscard]] TagState getState() const - { - return state; - } - - void setState(const TagState newState) - { - state = newState; - update(); - } - -signals: - /** - * @brief Emitted when the tag is clicked. - */ - void tagClicked(); - - /** - * @brief Emitted when the close button is clicked. - */ - void tagClosed(); - -protected: - /** - * @brief Custom paint event for drawing the widget. - * @param event The paint event. - */ - void paintEvent(QPaintEvent *event) override; - - /** - * @brief Custom mouse press event handler. - * @param event The mouse event. - */ - void mousePressEvent(QMouseEvent *event) override; - -private: - QLabel *tagLabel; ///< Label for displaying the tag name. - QPushButton *closeButton; ///< Button to close/remove the tag. - QString tagName; ///< The name of the tag. - TagState state; ///< Indicates whether the tag is unselected, selected, or excluded. -}; - -#endif // DECK_PREVIEW_TAG_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp deleted file mode 100644 index d9ea9fc30..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "deck_preview_tag_item_widget.h" - -DeckPreviewTagItemWidget::DeckPreviewTagItemWidget(const QString &tagName, bool isChecked, QWidget *parent) - : QWidget(parent), checkBox_(new QCheckBox(this)) -{ - auto *layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(5); - - checkBox_->setText(tagName); // Set the tag name as the checkbox label - checkBox_->setChecked(isChecked); // Set the initial state of the checkbox - - layout->addWidget(checkBox_); // Add the checkbox to the layout - setLayout(layout); // Set the layout of this widget -} - -QCheckBox *DeckPreviewTagItemWidget::checkBox() const -{ - return checkBox_; // Return the checkbox widget -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h deleted file mode 100644 index 5caae90a1..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file deck_preview_tag_item_widget.h - * @ingroup VisualDeckPreviewWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_TAG_ITEM_WIDGET_H -#define DECK_PREVIEW_TAG_ITEM_WIDGET_H - -#include -#include -#include - -class DeckPreviewTagItemWidget : public QWidget -{ - Q_OBJECT -public: - // Constructor: Initializes the tag item widget with a tag name and initial checkbox state - DeckPreviewTagItemWidget(const QString &tagName, bool isChecked, QWidget *parent = nullptr); - - // Accessor for the checkbox widget - [[nodiscard]] QCheckBox *checkBox() const; - -private: - QCheckBox *checkBox_; // Checkbox to represent the tag's state -}; - -#endif // DECK_PREVIEW_TAG_ITEM_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp deleted file mode 100644 index 77ea8f865..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp +++ /dev/null @@ -1,517 +0,0 @@ -#include "deck_preview_widget.h" - -#include "../../../../client/settings/cache_settings.h" -#include "../../cards/additional_info/color_identity_widget.h" -#include "../../cards/deck_preview_card_picture_widget.h" -#include "deck_preview_deck_tags_display_widget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DeckPreviewWidget::DeckPreviewWidget(QWidget *_parent, - VisualDeckStorageWidget *_visualDeckStorageWidget, - const QString &_filePath) - : QWidget(_parent), visualDeckStorageWidget(_visualDeckStorageWidget), filePath(_filePath), - colorIdentityWidget(nullptr), deckTagsDisplayWidget(nullptr) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - deckLoader = new DeckLoader(this); - connect(deckLoader, &DeckLoader::loadFinished, this, &DeckPreviewWidget::initializeUi); - /* TODO: We shouldn't update the tags on *every* deck load, since it's kinda expensive. We should instead count how - many deck loads have finished already and if we've loaded all decks and THEN load all the tags at once. */ - connect(deckLoader, &DeckLoader::loadFinished, visualDeckStorageWidget->tagFilterWidget, - &VisualDeckStorageTagFilterWidget::refreshTags); - deckLoader->loadFromFileAsync(filePath, DeckFileFormat::getFormatFromName(filePath), false); - - bannerCardDisplayWidget = - new DeckPreviewCardPictureWidget(this, false, visualDeckStorageWidget->deckPreviewSelectionAnimationEnabled); - - connect(bannerCardDisplayWidget, &DeckPreviewCardPictureWidget::imageClicked, this, - &DeckPreviewWidget::imageClickedEvent); - connect(bannerCardDisplayWidget, &DeckPreviewCardPictureWidget::imageDoubleClicked, this, - &DeckPreviewWidget::imageDoubleClickedEvent); - - connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageShowColorIdentityChanged, this, - &DeckPreviewWidget::updateColorIdentityVisibility); - connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageShowTagsOnDeckPreviewsChanged, this, - &DeckPreviewWidget::updateTagsVisibility); - connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageShowBannerCardComboBoxChanged, this, - &DeckPreviewWidget::updateBannerCardComboBoxVisibility); - connect(visualDeckStorageWidget->settings(), &VisualDeckStorageQuickSettingsWidget::deckPreviewTooltipChanged, this, - &DeckPreviewWidget::refreshBannerCardToolTip); - - layout->addWidget(bannerCardDisplayWidget); -} - -void DeckPreviewWidget::retranslateUi() -{ - bannerCardLabel->setText(tr("Banner Card")); -} - -void DeckPreviewWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - if (bannerCardDisplayWidget == nullptr) { - return; - } - QList widgets = findChildren(); - for (QWidget *widget : widgets) { - widget->setMaximumWidth(bannerCardDisplayWidget->width()); - } -} - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -void DeckPreviewWidget::enterEvent(QEnterEvent *event) -#else -void DeckPreviewWidget::enterEvent(QEvent *event) -#endif -{ - QWidget::enterEvent(event); - - // don't do reloads until widgets have been created - if (bannerCardComboBox != nullptr) { - reloadIfModified(); - } -} - -/** - * @brief Sets the lastModifiedTime to the value given by the file. - */ -void DeckPreviewWidget::updateLastModifiedTime() -{ - QFileInfo fileInfo(filePath); - lastModifiedTime = fileInfo.lastModified(); -} - -/** - * @brief Writes the current contents of the deck to file. Updates the lastModifiedTime afterward. - */ -void DeckPreviewWidget::writeDeckToFile() -{ - DeckLoader::saveToFile(deckLoader->getDeck()); - updateLastModifiedTime(); -} - -void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess) -{ - if (!deckLoadSuccess) { - return; - } - - QFileInfo fileInfo(filePath); - lastModifiedTime = fileInfo.lastModified(); - - bannerCardDisplayWidget->setFontSize(24); - setFilePath(deckLoader->getDeck().lastLoadInfo.fileName); - - colorIdentityWidget = new ColorIdentityWidget(this); - deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this); - connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, this, &DeckPreviewWidget::setTags); - - bannerCardLabel = new QLabel(this); - bannerCardLabel->setObjectName("bannerCardLabel"); - bannerCardComboBox = new QComboBox(this); - bannerCardComboBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - bannerCardComboBox->setObjectName("bannerCardComboBox"); - bannerCardComboBox->installEventFilter(new NoScrollFilter(bannerCardComboBox)); - connect(bannerCardComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, - &DeckPreviewWidget::setBannerCard); - - updateColorIdentityVisibility(SettingsCache::instance().getVisualDeckStorageShowColorIdentity()); - updateBannerCardComboBoxVisibility(SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox()); - updateTagsVisibility(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews()); - - layout->addWidget(colorIdentityWidget); - layout->addWidget(deckTagsDisplayWidget); - layout->addWidget(bannerCardLabel); - layout->addWidget(bannerCardComboBox); - - retranslateUi(); - resyncWidgets(); -} - -/** - * @brief Syncs the contents of the child widgets with the current deck. - */ -void DeckPreviewWidget::resyncWidgets() -{ - auto bannerCardRef = deckLoader->getDeck().deckList.getBannerCard(); - auto bannerCard = bannerCardRef.name.isEmpty() ? ExactCard() : CardDatabaseManager::query()->getCard(bannerCardRef); - - bannerCardDisplayWidget->setCard(bannerCard); - refreshBannerCardText(); - updateBannerCardComboBox(bannerCardRef.name); - colorIdentityWidget->setColorIdentity(getColorIdentity()); - deckTagsDisplayWidget->setTags(deckLoader->getDeck().deckList.getTags()); -} - -/** - * @brief Reloads the deck if the file's last modified time has increased since we last checked. - */ -void DeckPreviewWidget::reloadIfModified() -{ - QFileInfo fileInfo(filePath); - QDateTime newLastModifiedTime = fileInfo.lastModified(); - - if (!newLastModifiedTime.isValid() || newLastModifiedTime <= lastModifiedTime) { - return; - } - - bool success = deckLoader->reload(); - - if (success) { - fileInfo.refresh(); - lastModifiedTime = fileInfo.lastModified(); - resyncWidgets(); - } -} - -void DeckPreviewWidget::updateVisibility() -{ - setHidden(!checkVisibility()); -} - -bool DeckPreviewWidget::checkVisibility() const -{ - if (filteredBySearch || filteredByColor || filteredByTags) { - return false; - } - return true; -} - -void DeckPreviewWidget::updateColorIdentityVisibility(bool visible) -{ - if (colorIdentityWidget == nullptr) { - return; - } - - colorIdentityWidget->setVisible(visible); -} - -void DeckPreviewWidget::updateBannerCardComboBoxVisibility(bool visible) -{ - if (bannerCardComboBox == nullptr) { - return; - } - - if (visible) { - bannerCardComboBox->setVisible(true); - bannerCardLabel->setVisible(true); - } else { - bannerCardComboBox->setHidden(true); - bannerCardLabel->setHidden(true); - } -} - -void DeckPreviewWidget::updateTagsVisibility(bool visible) -{ - if (deckTagsDisplayWidget == nullptr) { - return; - } - - if (visible) { - deckTagsDisplayWidget->setVisible(true); - } else { - deckTagsDisplayWidget->setHidden(true); - } -} - -QString DeckPreviewWidget::getColorIdentity() -{ - QStringList cardList = deckLoader->getDeck().deckList.getCardList({DECK_ZONE_MAIN, DECK_ZONE_SIDE}); - if (cardList.isEmpty()) { - return {}; - } - - QSet colorSet; // A set to collect unique color symbols (e.g., W, U, B, R, G) - - for (const QString &cardName : cardList) { - CardInfoPtr currentCard = CardDatabaseManager::query()->getCardInfo(cardName); - if (currentCard) { - QString colors = currentCard->getColors(); // Assuming this returns something like "WUB" - for (const QChar &color : colors) { - colorSet.insert(color); - } - } - } - - // Ensure the color identity is in WUBRG order - QString colorIdentity; - const QString wubrgOrder = "WUBRG"; - for (const QChar &color : wubrgOrder) { - if (colorSet.contains(color)) { - colorIdentity.append(color); - } - } - - return colorIdentity; -} - -/** - * The display name is given by the deck name, or the filename if the deck name is not set. - */ -QString DeckPreviewWidget::getDisplayName() const -{ - QString deckName = deckLoader->getDeck().deckList.getName(); - return !deckName.isEmpty() ? deckName : QFileInfo(deckLoader->getDeck().lastLoadInfo.fileName).fileName(); -} - -void DeckPreviewWidget::setFilePath(const QString &_filePath) -{ - filePath = _filePath; -} - -/** - * Refreshes the banner card text. - * This also calls `refreshBannerCardToolTip`, since those two often need to be updated together. - */ -void DeckPreviewWidget::refreshBannerCardText() -{ - bannerCardDisplayWidget->setOverlayText(getDisplayName()); - - refreshBannerCardToolTip(); -} - -void DeckPreviewWidget::refreshBannerCardToolTip() -{ - auto type = visualDeckStorageWidget->settings()->getDeckPreviewTooltip(); - switch (type) { - case VisualDeckStorageQuickSettingsWidget::TooltipType::None: - bannerCardDisplayWidget->setToolTip(""); - break; - case VisualDeckStorageQuickSettingsWidget::TooltipType::Filepath: - bannerCardDisplayWidget->setToolTip(filePath); - break; - } -} - -void DeckPreviewWidget::updateBannerCardComboBox(const QString ¤tText) -{ - // Block signals temporarily - bool wasBlocked = bannerCardComboBox->blockSignals(true); - bannerCardComboBox->setUpdatesEnabled(false); - - // Clear the existing items in the combo box - bannerCardComboBox->clear(); - - // Prepare the new items with deduplication - QSet> bannerCardSet; - - QList cardsInDeck = deckLoader->getDeck().deckList.getCardNodes(); - - for (auto currentCard : cardsInDeck) { - for (int k = 0; k < currentCard->getNumber(); ++k) { - bannerCardSet.insert(QPair(currentCard->getName(), currentCard->getCardProviderId())); - } - } - - QList> pairList = bannerCardSet.values(); - - // Sort QList by the first() element of the QPair - std::sort(pairList.begin(), pairList.end(), [](const QPair &a, const QPair &b) { - return a.first.toLower() < b.first.toLower(); - }); - - // This is *slightly* more performant than using addItem in a loop. - - QStandardItemModel *model = new QStandardItemModel(pairList.size(), 1, bannerCardComboBox); - - int row = 0; - for (const auto &pair : pairList) { - QStandardItem *item = new QStandardItem(pair.first); - item->setData(QVariant::fromValue(pair), Qt::UserRole); - model->setItem(row++, 0, item); - } - - bannerCardComboBox->setModel(model); - - // Try to restore the previous selection by finding the currentText - int restoredIndex = bannerCardComboBox->findText(currentText); - if (restoredIndex != -1) { - bannerCardComboBox->setCurrentIndex(restoredIndex); - } else { - // Add a placeholder "-" and set it as the current selection - int bannerIndex = bannerCardComboBox->findText(deckLoader->getDeck().deckList.getBannerCard().name); - if (bannerIndex != -1) { - bannerCardComboBox->setCurrentIndex(bannerIndex); - } else { - bannerCardComboBox->insertItem(0, "-"); - bannerCardComboBox->setCurrentIndex(0); - } - } - - // Restore the previous signal blocking state - bannerCardComboBox->blockSignals(wasBlocked); - bannerCardComboBox->setUpdatesEnabled(true); -} - -void DeckPreviewWidget::setBannerCard(int /* changedIndex */) -{ - auto [name, id] = bannerCardComboBox->currentData().value>(); - CardRef cardRef = {name, id}; - deckLoader->getDeck().deckList.setBannerCard(cardRef); - writeDeckToFile(); - bannerCardDisplayWidget->setCard(CardDatabaseManager::query()->getCard(cardRef)); -} - -void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance) -{ - Q_UNUSED(instance); - - if (event && event->button() == Qt::RightButton) { - createRightClickMenu()->popup(QCursor::pos()); - } -} - -void DeckPreviewWidget::imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance) -{ - Q_UNUSED(event); - Q_UNUSED(instance); - emit deckLoadRequested(filePath); -} - -void DeckPreviewWidget::setTags(const QStringList &tags) -{ - deckLoader->getDeck().deckList.setTags(tags); - writeDeckToFile(); -} - -QMenu *DeckPreviewWidget::createRightClickMenu() -{ - auto *menu = new QMenu(this); - menu->setAttribute(Qt::WA_DeleteOnClose); - - connect(menu->addAction(tr("Open in deck editor")), &QAction::triggered, this, - [this] { emit openDeckEditor(deckLoader->getDeck()); }); - - connect(menu->addAction(tr("Edit Tags")), &QAction::triggered, deckTagsDisplayWidget, - &DeckPreviewDeckTagsDisplayWidget::openTagEditDlg); - - addSetBannerCardMenu(menu); - - menu->addSeparator(); - - connect(menu->addAction(tr("Rename Deck")), &QAction::triggered, this, &DeckPreviewWidget::actRenameDeck); - - auto saveToClipboardMenu = menu->addMenu(tr("Save Deck to Clipboard")); - - connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this, - [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, true, true); }); - connect(saveToClipboardMenu->addAction(tr("Annotated (No set info)")), &QAction::triggered, this, - [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, true, false); }); - connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this, - [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, false, true); }); - connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set info)")), &QAction::triggered, this, - [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, false, false); }); - - menu->addSeparator(); - - connect(menu->addAction(tr("Rename File")), &QAction::triggered, this, &DeckPreviewWidget::actRenameFile); - - connect(menu->addAction(tr("Delete File")), &QAction::triggered, this, &DeckPreviewWidget::actDeleteFile); - - return menu; -} - -/** - * Adds the "Set Banner Card" submenu to the given menu. Does nothing if bannerCardComboBox is null. - * @param menu The menu to add the submenu to - */ -void DeckPreviewWidget::addSetBannerCardMenu(QMenu *menu) -{ - if (!bannerCardComboBox) { - return; - } - - auto bannerCardMenu = menu->addMenu(tr("Set Banner Card")); - - for (int i = 0; i < bannerCardComboBox->count(); ++i) { - auto action = bannerCardMenu->addAction(bannerCardComboBox->itemText(i)); - connect(action, &QAction::triggered, this, [this, i] { bannerCardComboBox->setCurrentIndex(i); }); - - // the checkability is purely for visuals - action->setCheckable(true); - action->setChecked(bannerCardComboBox->currentIndex() == i); - } -} - -void DeckPreviewWidget::actRenameDeck() -{ - // read input - const QString oldName = deckLoader->getDeck().deckList.getName(); - - bool ok; - QString newName = QInputDialog::getText(this, "Rename deck", tr("New name:"), QLineEdit::Normal, oldName, &ok); - if (!ok || oldName == newName) { - return; - } - - // write change - deckLoader->getDeck().deckList.setName(newName); - writeDeckToFile(); - - // update VDS - refreshBannerCardText(); -} - -void DeckPreviewWidget::actRenameFile() -{ - // read input - const auto info = QFileInfo(filePath); - const QString oldName = info.baseName(); - - bool ok; - QString newName = QInputDialog::getText(this, "Rename file", tr("New name:"), QLineEdit::Normal, oldName, &ok); - if (!ok || newName.isEmpty() || oldName == newName) { - return; - } - - QString newFileName = newName; - if (!info.suffix().isEmpty()) { - newFileName += "." + info.suffix(); - } - - // write change - const QString newFilePath = QFileInfo(info.dir(), newFileName).filePath(); - if (!QFile::rename(info.filePath(), newFilePath)) { - QMessageBox::critical(this, tr("Error"), tr("Rename failed")); - return; - } - - deckLoader->getDeck().lastLoadInfo.fileName = newFilePath; - setFilePath(newFilePath); - - // update VDS - updateLastModifiedTime(); - refreshBannerCardText(); -} - -void DeckPreviewWidget::actDeleteFile() -{ - // read input - auto res = QMessageBox::warning(this, tr("Delete file"), tr("Are you sure you want to delete the selected file?"), - QMessageBox::Yes | QMessageBox::No); - if (res != QMessageBox::Yes) { - return; - } - - // write change - if (!QFile::remove(QFileInfo(filePath).filePath())) { - QMessageBox::critical(this, tr("Error"), tr("Delete failed")); - return; - } - - // update VDS - this->deleteLater(); -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h deleted file mode 100644 index 98116cabe..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * @file deck_preview_widget.h - * @ingroup VisualDeckPreviewWidgets - * @brief TODO: Document this. - */ - -#ifndef DECK_PREVIEW_WIDGET_H -#define DECK_PREVIEW_WIDGET_H - -#include "../../../deck_loader/deck_loader.h" -#include "../../cards/additional_info/color_identity_widget.h" -#include "../../cards/deck_preview_card_picture_widget.h" -#include "../visual_deck_storage_widget.h" -#include "deck_preview_deck_tags_display_widget.h" - -#include -#include -#include -#include -#include -#include - -class QMenu; -class VisualDeckStorageWidget; -class DeckPreviewDeckTagsDisplayWidget; - -class DeckPreviewWidget final : public QWidget -{ - Q_OBJECT -public: - explicit DeckPreviewWidget(QWidget *_parent, - VisualDeckStorageWidget *_visualDeckStorageWidget, - const QString &_filePath); - void retranslateUi(); - QString getColorIdentity(); - [[nodiscard]] QString getDisplayName() const; - - VisualDeckStorageWidget *visualDeckStorageWidget; - QVBoxLayout *layout; - QString filePath; - QDateTime lastModifiedTime; - DeckLoader *deckLoader; - DeckPreviewCardPictureWidget *bannerCardDisplayWidget = nullptr; - ColorIdentityWidget *colorIdentityWidget = nullptr; - DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget = nullptr; - QLabel *bannerCardLabel = nullptr; - QComboBox *bannerCardComboBox = nullptr; - bool filteredBySearch = false; - bool filteredByColor = false; - bool filteredByTags = false; - [[nodiscard]] bool checkVisibility() const; - -signals: - void deckLoadRequested(const QString &filePath); - void openDeckEditor(const LoadedDeck &deck); - -public slots: - void setFilePath(const QString &filePath); - void refreshBannerCardText(); - void refreshBannerCardToolTip(); - void updateBannerCardComboBox(const QString ¤tText); - void setBannerCard(int); - void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance); - void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance); - void initializeUi(bool deckLoadSuccess); - void resyncWidgets(); - void reloadIfModified(); - void updateVisibility(); - void updateColorIdentityVisibility(bool visible); - void updateBannerCardComboBoxVisibility(bool visible); - void updateTagsVisibility(bool visible); - void resizeEvent(QResizeEvent *event) override; - -protected: -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - void enterEvent(QEnterEvent *event) override; // Qt6 signature -#else - void enterEvent(QEvent *event) override; // Qt5 signature -#endif - -private: - void updateLastModifiedTime(); - void writeDeckToFile(); - QMenu *createRightClickMenu(); - void addSetBannerCardMenu(QMenu *menu); - -private slots: - void setTags(const QStringList &tags); - - void actRenameDeck(); - void actRenameFile(); - void actDeleteFile(); -}; - -class NoScrollFilter : public QObject -{ - Q_OBJECT -public: - explicit NoScrollFilter(QObject *parent = nullptr) : QObject(parent) - { - } - -protected: - bool eventFilter(QObject *obj, QEvent *event) override - { - if (event->type() == QEvent::Wheel) { - if (auto *combo = qobject_cast(obj)) { - // If popup is not open, forward event to parent scroll area - if (!combo->view()->isVisible()) { - // Try to find a scrollable parent and manually send the event - QWidget *parent = combo->parentWidget(); - while (parent) { - if (auto *scroll = qobject_cast(parent)) { - QApplication::sendEvent(scroll->viewport(), event); - return true; // Mark event as handled - } - parent = parent->parentWidget(); - } - // If no scrollable parent found, just block - return true; - } - } - } - return QObject::eventFilter(obj, event); - } -}; - -#endif // DECK_PREVIEW_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp deleted file mode 100644 index fdb44dff4..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "visual_deck_storage_folder_display_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "deck_preview/deck_preview_widget.h" -#include "visual_deck_storage_widget.h" - -#include -#include - -VisualDeckStorageFolderDisplayWidget::VisualDeckStorageFolderDisplayWidget( - QWidget *parent, - VisualDeckStorageWidget *_visualDeckStorageWidget, - QString _filePath, - bool canBeHidden, - bool _showFolders) - : QWidget(parent), showFolders(_showFolders), visualDeckStorageWidget(_visualDeckStorageWidget), filePath(_filePath) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - header = new BannerWidget(this, ""); - header->setClickable(canBeHidden); - header->setHidden(!showFolders); - layout->addWidget(header); - - container = new QWidget(this); - containerLayout = new QVBoxLayout(container); - container->setLayout(containerLayout); - - header->setBuddy(container); - - layout->addWidget(container); - - flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff); - containerLayout->addWidget(flowWidget); - - createWidgetsForFiles(); - createWidgetsForFolders(); - - refreshUi(); -} - -void VisualDeckStorageFolderDisplayWidget::refreshUi() -{ - QString bannerText = tr("Deck Storage"); - QString deckPath = SettingsCache::instance().getDeckPath(); - if (filePath != deckPath) { - QString relativePath = filePath; - - if (filePath.startsWith(deckPath)) { - relativePath = filePath.mid(deckPath.length()); // Remove the deckPath prefix - if (relativePath.startsWith('/')) { - relativePath.remove(0, 1); // Remove leading '/' if it exists - } - } - - bannerText = relativePath; - } - header->setText(bannerText); -} - -/** - * Gets all files in the directory that have an accepted decklist file extension - * - * @param filePath The directory to search through - * @param recursive Whether to search through subdirectories - */ -static QStringList getAllFiles(const QString &filePath, bool recursive) -{ - QStringList allFiles; - - // QDirIterator with QDir::Files ensures only files are listed (no directories) - auto flags = - recursive ? QDirIterator::Subdirectories | QDirIterator::FollowSymlinks : QDirIterator::NoIteratorFlags; - QDirIterator it(filePath, DeckLoader::ACCEPTED_FILE_EXTENSIONS, QDir::Files, flags); - - while (it.hasNext()) { - allFiles << it.next(); // Add each file path to the list - } - - return allFiles; -} - -void VisualDeckStorageFolderDisplayWidget::createWidgetsForFiles() -{ - QList allDecks; - for (const QString &file : getAllFiles(filePath, !showFolders)) { - auto *display = new DeckPreviewWidget(flowWidget, visualDeckStorageWidget, file); - - connect(display, &DeckPreviewWidget::deckLoadRequested, visualDeckStorageWidget, - &VisualDeckStorageWidget::deckLoadRequested); - connect(display, &DeckPreviewWidget::openDeckEditor, visualDeckStorageWidget, - &VisualDeckStorageWidget::openDeckEditor); - connect(visualDeckStorageWidget->settings(), &VisualDeckStorageQuickSettingsWidget::cardSizeChanged, - display->bannerCardDisplayWidget, &CardInfoPictureWidget::setScaleFactor); - display->bannerCardDisplayWidget->setScaleFactor(visualDeckStorageWidget->settings()->getCardSize()); - allDecks.append(display); - } - - flowWidget->clearLayout(); // Clear existing widgets in the flow layout - - for (DeckPreviewWidget *deck : allDecks) { - flowWidget->addWidget(deck); - } -} - -/** - * Updates the visibility of this folder and all its DeckPreviewWidgets - * - * @param recursive Also update the visibility of all subfolders and their DeckPreviewWidgets. - */ -void VisualDeckStorageFolderDisplayWidget::updateVisibility(bool recursive) -{ - bool atLeastOneWidgetVisible = checkVisibility(); - if (atLeastOneWidgetVisible) { - setVisible(true); - for (DeckPreviewWidget *display : flowWidget->findChildren()) { - display->updateVisibility(); - } - if (recursive) { - for (auto *subFolder : findChildren()) { - subFolder->updateVisibility(false); - } - } - } else { - setVisible(false); - } -} - -bool VisualDeckStorageFolderDisplayWidget::checkVisibility() -{ - bool atLeastOneWidgetVisible = false; - if (flowWidget) { - // Iterate through all DeckPreviewWidgets - for (DeckPreviewWidget *display : flowWidget->findChildren()) { - if (display->checkVisibility()) { - atLeastOneWidgetVisible = true; - } - } - } - for (VisualDeckStorageFolderDisplayWidget *subFolder : findChildren()) { - if (subFolder->checkVisibility()) { - atLeastOneWidgetVisible = true; - } - } - return atLeastOneWidgetVisible; -} - -static QStringList getAllSubFolders(const QString &filePath) -{ - QStringList allFolders; - - // QDirIterator with QDir::Files ensures only files are listed (no directories) - QDirIterator it(filePath, QDir::Dirs | QDir::NoDotAndDotDot); - - while (it.hasNext()) { - allFolders << it.next(); // Add each file path to the list - } - - return allFolders; -} - -void VisualDeckStorageFolderDisplayWidget::createWidgetsForFolders() -{ - if (!showFolders) { - return; - } - - for (const QString &dir : getAllSubFolders(filePath)) { - auto *display = new VisualDeckStorageFolderDisplayWidget(this, visualDeckStorageWidget, dir, true, showFolders); - containerLayout->addWidget(display); - } -} - -void VisualDeckStorageFolderDisplayWidget::updateShowFolders(bool enabled) -{ - showFolders = enabled; - - if (!showFolders) { - flattenFolderStructure(); - } else { - // if setting was switched from disabled to enabled, we assume that there aren't any existing subfolders - createWidgetsForFiles(); - createWidgetsForFolders(); - } - - header->setHidden(!showFolders); -} - -/** - * Steals all DeckPreviewWidgets from this widget's nested subfolders, and deletes those subfolders - */ -void VisualDeckStorageFolderDisplayWidget::flattenFolderStructure() -{ - for (auto *subFolder : findChildren()) { - // steal all DeckPreviewWidgets from the subfolder - for (auto *deck : subFolder->getFlowWidget()->findChildren()) { - flowWidget->addWidget(deck); - } - - // delete the subfolder - subFolder->deleteLater(); - } -} - -QStringList VisualDeckStorageFolderDisplayWidget::gatherAllTagsFromFlowWidget() const -{ - QStringList allTags; - - if (flowWidget) { - // Iterate through all DeckPreviewWidgets - for (DeckPreviewWidget *display : flowWidget->findChildren()) { - // Get tags from each DeckPreviewWidget - QStringList tags = display->deckLoader->getDeck().deckList.getTags(); - - // Add tags to the list while avoiding duplicates - allTags.append(tags); - } - } - - // Remove duplicates by calling 'removeDuplicates' - allTags.removeDuplicates(); - - return allTags; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h deleted file mode 100644 index d76fb0497..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file visual_deck_storage_folder_display_widget.h - * @ingroup VisualDeckStorageWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_STORAGE_FOLDER_DISPLAY_WIDGET_H -#define VISUAL_DECK_STORAGE_FOLDER_DISPLAY_WIDGET_H - -#include "../general/display/banner_widget.h" -#include "../general/layout_containers/flow_widget.h" - -class VisualDeckStorageWidget; -class VisualDeckStorageFolderDisplayWidget : public QWidget -{ - Q_OBJECT -public: - VisualDeckStorageFolderDisplayWidget(QWidget *parent, - VisualDeckStorageWidget *_visualDeckStorageWidget, - QString _filePath, - bool canBeHidden, - bool _showFolders); - void refreshUi(); - void createWidgetsForFiles(); - void createWidgetsForFolders(); - void flattenFolderStructure(); - [[nodiscard]] QStringList gatherAllTagsFromFlowWidget() const; - [[nodiscard]] FlowWidget *getFlowWidget() const - { - return flowWidget; - } - -public slots: - void updateVisibility(bool recursive = true); - bool checkVisibility(); - void updateShowFolders(bool enabled); - -private: - bool showFolders; - QVBoxLayout *layout; - VisualDeckStorageWidget *visualDeckStorageWidget; - QString filePath; - BannerWidget *header; - QWidget *container; - QVBoxLayout *containerLayout; - FlowWidget *flowWidget; -}; - -#endif // VISUAL_DECK_STORAGE_FOLDER_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp deleted file mode 100644 index a0e8512ac..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#include "visual_deck_storage_quick_settings_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "visual_deck_storage_widget.h" - -#include -#include -#include - -VisualDeckStorageQuickSettingsWidget::VisualDeckStorageQuickSettingsWidget(QWidget *parent) - : SettingsButtonWidget(parent) -{ - // show folders checkbox - showFoldersCheckBox = new QCheckBox(this); - showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders()); - connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &VisualDeckStorageQuickSettingsWidget::showFoldersChanged); - connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageShowFolders); - - // show tag filter widget checkbox - showTagFilterCheckBox = new QCheckBox(this); - showTagFilterCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagFilter()); - connect(showTagFilterCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged); - connect(showTagFilterCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageShowTagFilter); - - // show color identity on DeckPreviewWidget checkbox - showColorIdentityCheckBox = new QCheckBox(this); - showColorIdentityCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowColorIdentity()); - connect(showColorIdentityCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &VisualDeckStorageQuickSettingsWidget::showColorIdentityChanged); - connect(showColorIdentityCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageShowColorIdentity); - - // show tags on DeckPreviewWidget checkbox - showTagsOnDeckPreviewsCheckBox = new QCheckBox(this); - showTagsOnDeckPreviewsCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews()); - connect(showTagsOnDeckPreviewsCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &VisualDeckStorageQuickSettingsWidget::showTagsOnDeckPreviewsChanged); - connect(showTagsOnDeckPreviewsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageShowTagsOnDeckPreviews); - - // show banner card selector checkbox - showBannerCardComboBoxCheckBox = new QCheckBox(this); - showBannerCardComboBoxCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox()); - connect(showBannerCardComboBoxCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &VisualDeckStorageQuickSettingsWidget::showBannerCardComboBoxChanged); - connect(showBannerCardComboBoxCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageShowBannerCardComboBox); - - // draw unused color identities checkbox - drawUnusedColorIdentitiesCheckBox = new QCheckBox(this); - drawUnusedColorIdentitiesCheckBox->setChecked( - SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()); - connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &VisualDeckStorageQuickSettingsWidget::drawUnusedColorIdentitiesChanged); - connect(drawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities); - - // color identity opacity selector - auto unusedColorIdentityOpacityWidget = new QWidget(this); - - unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget); - unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget); - - unusedColorIdentitiesOpacitySpinBox->setMinimum(0); - unusedColorIdentitiesOpacitySpinBox->setMaximum(100); - unusedColorIdentitiesOpacitySpinBox->setValue( - SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity()); - connect(unusedColorIdentitiesOpacitySpinBox, qOverload(&QSpinBox::valueChanged), this, - &VisualDeckStorageQuickSettingsWidget::unusedColorIdentitiesOpacityChanged); - connect(unusedColorIdentitiesOpacitySpinBox, qOverload(&QSpinBox::valueChanged), &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity); - - unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox); - - auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget); - unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0); - unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel); - unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox); - - // tooltip selector - auto deckPreviewTooltipWidget = new QWidget(this); - - deckPreviewTooltipLabel = new QLabel(deckPreviewTooltipWidget); - deckPreviewTooltipComboBox = new QComboBox(deckPreviewTooltipWidget); - deckPreviewTooltipComboBox->setFocusPolicy(Qt::StrongFocus); - deckPreviewTooltipComboBox->addItem("", TooltipType::None); - deckPreviewTooltipComboBox->addItem("", TooltipType::Filepath); - - deckPreviewTooltipComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageTooltipType()); - connect(deckPreviewTooltipComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, - [this] { emit deckPreviewTooltipChanged(getDeckPreviewTooltip()); }); - connect(deckPreviewTooltipComboBox, QOverload::of(&QComboBox::currentIndexChanged), &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageTooltipType); - - auto deckPreviewTooltipLayout = new QHBoxLayout(deckPreviewTooltipWidget); - deckPreviewTooltipLayout->setContentsMargins(11, 0, 11, 0); - deckPreviewTooltipLayout->addWidget(deckPreviewTooltipLabel); - deckPreviewTooltipLayout->addWidget(deckPreviewTooltipComboBox); - - // card size slider - cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize()); - connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this, - &VisualDeckStorageQuickSettingsWidget::cardSizeChanged); - connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(), - &SettingsCache::setVisualDeckStorageCardSize); - - // putting everything together - this->addSettingsWidget(showFoldersCheckBox); - this->addSettingsWidget(showTagFilterCheckBox); - this->addSettingsWidget(showColorIdentityCheckBox); - this->addSettingsWidget(showTagsOnDeckPreviewsCheckBox); - this->addSettingsWidget(showBannerCardComboBoxCheckBox); - this->addSettingsWidget(drawUnusedColorIdentitiesCheckBox); - this->addSettingsWidget(unusedColorIdentityOpacityWidget); - this->addSettingsWidget(deckPreviewTooltipWidget); - this->addSettingsWidget(cardSizeWidget); - - connect(&SettingsCache::instance(), &SettingsCache::langChanged, this, - &VisualDeckStorageQuickSettingsWidget::retranslateUi); - retranslateUi(); -} - -void VisualDeckStorageQuickSettingsWidget::retranslateUi() -{ - showFoldersCheckBox->setText(tr("Show Folders")); - showTagFilterCheckBox->setText(tr("Show Tag Filter")); - showColorIdentityCheckBox->setText(tr("Show Color Identity")); - showTagsOnDeckPreviewsCheckBox->setText(tr("Show Tags On Deck Previews")); - showBannerCardComboBoxCheckBox->setText(tr("Show Banner Card Selection Option")); - drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities")); - unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity")); - unusedColorIdentitiesOpacitySpinBox->setSuffix("%"); - - deckPreviewTooltipLabel->setText(tr("Deck tooltip:")); - deckPreviewTooltipComboBox->setItemText(0, tr("None")); - deckPreviewTooltipComboBox->setItemText(1, tr("Filepath")); -} - -bool VisualDeckStorageQuickSettingsWidget::getShowFolders() const -{ - return showFoldersCheckBox->isChecked(); -} - -bool VisualDeckStorageQuickSettingsWidget::getDrawUnusedColorIdentities() const -{ - return drawUnusedColorIdentitiesCheckBox->isChecked(); -} - -bool VisualDeckStorageQuickSettingsWidget::getShowColorIdentity() const -{ - return showColorIdentityCheckBox->isChecked(); -} - -bool VisualDeckStorageQuickSettingsWidget::getShowBannerCardComboBox() const -{ - return showBannerCardComboBoxCheckBox->isChecked(); -} - -bool VisualDeckStorageQuickSettingsWidget::getShowTagFilter() const -{ - return showTagFilterCheckBox->isChecked(); -} - -bool VisualDeckStorageQuickSettingsWidget::getShowTagsOnDeckPreviews() const -{ - return showTagsOnDeckPreviewsCheckBox->isChecked(); -} - -int VisualDeckStorageQuickSettingsWidget::getUnusedColorIdentitiesOpacity() const -{ - return unusedColorIdentitiesOpacitySpinBox->value(); -} - -VisualDeckStorageQuickSettingsWidget::TooltipType VisualDeckStorageQuickSettingsWidget::getDeckPreviewTooltip() const -{ - return deckPreviewTooltipComboBox->currentData().value(); -} - -int VisualDeckStorageQuickSettingsWidget::getCardSize() const -{ - return cardSizeWidget->getSlider()->value(); -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h deleted file mode 100644 index ea4330a15..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file visual_deck_storage_quick_settings_widget.h - * @ingroup VisualDeckStorageWidgets - * @brief The VDS's quick settings menu. - * Manages the widgets in the quick settings menu dropdown, as well as syncing their values with SettingsCache. - * The current values of the settings are exposed through getters and signals. - */ - -#ifndef VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H -#define VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H - -#include "../quick_settings/settings_button_widget.h" - -class CardSizeWidget; -class QLabel; -class QSpinBox; -class QCheckBox; -class QComboBox; - -class VisualDeckStorageQuickSettingsWidget : public SettingsButtonWidget -{ - Q_OBJECT - - QCheckBox *showFoldersCheckBox; - QCheckBox *showColorIdentityCheckBox; - QCheckBox *drawUnusedColorIdentitiesCheckBox; - QCheckBox *showBannerCardComboBoxCheckBox; - QCheckBox *showTagFilterCheckBox; - QCheckBox *showTagsOnDeckPreviewsCheckBox; - QLabel *unusedColorIdentitiesOpacityLabel; - QSpinBox *unusedColorIdentitiesOpacitySpinBox; - QLabel *deckPreviewTooltipLabel; - QComboBox *deckPreviewTooltipComboBox; - CardSizeWidget *cardSizeWidget; - -public: - /** - * The info to display in the deck preview's banner card tooltip. - */ - enum TooltipType - { - None, - Filepath - }; - Q_ENUM(TooltipType) - - explicit VisualDeckStorageQuickSettingsWidget(QWidget *parent = nullptr); - - void retranslateUi(); - - [[nodiscard]] bool getShowFolders() const; - [[nodiscard]] bool getDrawUnusedColorIdentities() const; - [[nodiscard]] bool getShowColorIdentity() const; - [[nodiscard]] bool getShowBannerCardComboBox() const; - [[nodiscard]] bool getShowTagFilter() const; - [[nodiscard]] bool getShowTagsOnDeckPreviews() const; - [[nodiscard]] int getUnusedColorIdentitiesOpacity() const; - [[nodiscard]] TooltipType getDeckPreviewTooltip() const; - [[nodiscard]] int getCardSize() const; - -signals: - void showFoldersChanged(bool enabled); - void drawUnusedColorIdentitiesChanged(bool enabled); - void showColorIdentityChanged(bool enabled); - void showBannerCardComboBoxChanged(bool enabled); - void showTagFilterChanged(bool enabled); - void showTagsOnDeckPreviewsChanged(bool enabled); - void unusedColorIdentitiesOpacityChanged(int opacity); - void deckPreviewTooltipChanged(TooltipType tooltip); - void cardSizeChanged(int scale); -}; - -#endif // VISUAL_DECK_STORAGE_QUICK_SETTINGS_WIDGET_H \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp deleted file mode 100644 index 70b438232..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "visual_deck_storage_search_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../../../filters/deck_filter_string.h" -#include "../../../filters/syntax_help.h" -#include "../../pixel_map_generator.h" - -#include -#include - -/** - * @brief Constructs a PrintingSelectorCardSearchWidget for searching cards by set name or set code. - * - * This widget provides a search bar that allows users to search for cards by either their set name - * or set code. It uses a debounced timer to trigger the search action after the user stops typing. - * - * @param parent The parent PrintingSelector widget that will handle the search results. - */ -VisualDeckStorageSearchWidget::VisualDeckStorageSearchWidget(VisualDeckStorageWidget *parent) : parent(parent) -{ - layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - setLayout(layout); - - searchBar = new QLineEdit(this); - searchBar->setPlaceholderText(tr("Search by filename (or search expression)")); - searchBar->setClearButtonEnabled(true); - searchBar->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition); - - auto help = searchBar->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition); - connect(help, &QAction::triggered, this, [this] { createDeckSearchSyntaxHelpWindow(searchBar); }); - - layout->addWidget(searchBar); - - // Add a debounce timer for the search bar to limit frequent updates - searchDebounceTimer = new QTimer(this); - searchDebounceTimer->setSingleShot(true); - connect(searchBar, &QLineEdit::textChanged, this, [this]() { - searchDebounceTimer->start(300); // 300ms debounce - }); - - connect(searchDebounceTimer, &QTimer::timeout, parent, &VisualDeckStorageWidget::updateSearchFilter); -} - -/** - * @brief Retrieves the current text in the search bar. - * - * @return The text entered by the user in the search bar. - */ -QString VisualDeckStorageSearchWidget::getSearchText() -{ - return searchBar->text(); -} - -/** - * Converts the filepath into a relative filepath starting from the deck folder. - * If the file isn't in the deck folder, then this will just return the filename. - * - * @param filePath The filepath to convert into a relative filepath - */ -static QString toRelativeFilepath(const QString &filePath) -{ - QString deckPath = SettingsCache::instance().getDeckPath(); - if (filePath.startsWith(deckPath)) { - return filePath.mid(deckPath.length()); - } - - QFileInfo fileInfo(filePath); - QString fileName = fileInfo.fileName(); - return fileName; -} - -void VisualDeckStorageSearchWidget::filterWidgets(QList widgets, const QString &searchText) -{ - auto filterString = DeckFilterString(searchText); - - for (auto widget : widgets) { - QString relativeFilePath = toRelativeFilepath(widget->filePath); - widget->filteredBySearch = !filterString.check(widget, {relativeFilePath}); - } -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.h deleted file mode 100644 index 67d260b21..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_search_widget.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file visual_deck_storage_search_widget.h - * @ingroup VisualDeckStorageWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_STORAGE_SEARCH_WIDGET_H -#define VISUAL_DECK_STORAGE_SEARCH_WIDGET_H - -#include "deck_preview/deck_preview_widget.h" - -#include -#include -#include - -class VisualDeckStorageWidget; -class VisualDeckStorageSearchWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDeckStorageSearchWidget(VisualDeckStorageWidget *parent); - QString getSearchText(); - void filterWidgets(QList widgets, const QString &searchText); - -private: - QHBoxLayout *layout; - VisualDeckStorageWidget *parent; - QLineEdit *searchBar; - QTimer *searchDebounceTimer; -}; - -#endif // VISUAL_DECK_STORAGE_SEARCH_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp deleted file mode 100644 index 0eb45cdcc..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "visual_deck_storage_sort_widget.h" - -#include "../../../client/settings/cache_settings.h" - -#include - -/** - * @brief Constructs a PrintingSelectorCardSortWidget for searching cards by set name or set code. - * - * This widget provides a search bar that allows users to search for cards by either their set name - * or set code. It uses a debounced timer to trigger the search action after the user stops typing. - * - * @param parent The parent PrintingSelector widget that will handle the search results. - */ -VisualDeckStorageSortWidget::VisualDeckStorageSortWidget(VisualDeckStorageWidget *parent) - : parent(parent), sortOrder(Alphabetical) -{ - layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - setLayout(layout); - - // Initialize the ComboBox - sortComboBox = new QComboBox(this); - layout->addWidget(sortComboBox); - - // Need to retranslateUi first so that the sortComboBox actually has entries and doesn't get its currentIndex - // immediately capped to 0 when we try to set it - retranslateUi(); - - // Set the current sort order - sortComboBox->setCurrentIndex(SettingsCache::instance().getVisualDeckStorageSortingOrder()); - sortOrder = static_cast(sortComboBox->currentIndex()); - - // Connect sorting change signal to refresh the file list - connect(sortComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, - &VisualDeckStorageSortWidget::updateSortOrder); - connect(this, &VisualDeckStorageSortWidget::sortOrderChanged, parent, &VisualDeckStorageWidget::updateSortOrder); -} - -void VisualDeckStorageSortWidget::retranslateUi() -{ - // Block signals to avoid triggering unnecessary updates while changing text - sortComboBox->blockSignals(true); - - int oldIndex = sortComboBox->currentIndex(); - - // Clear and repopulate the ComboBox with translated items - sortComboBox->clear(); - sortComboBox->addItem(tr("Sort Alphabetically (Deck Name)"), ByName); - sortComboBox->addItem(tr("Sort Alphabetically (Filename)"), Alphabetical); - sortComboBox->addItem(tr("Sort by Last Modified"), ByLastModified); - sortComboBox->addItem(tr("Sort by Last Loaded"), ByLastLoaded); - - // Restore the current index - sortComboBox->setCurrentIndex(oldIndex); - - // Re-enable signals - sortComboBox->blockSignals(false); -} - -void VisualDeckStorageSortWidget::updateSortOrder() -{ - sortOrder = static_cast(sortComboBox->currentIndex()); - SettingsCache::instance().setVisualDeckStorageSortingOrder(sortComboBox->currentIndex()); - emit sortOrderChanged(); -} - -void VisualDeckStorageSortWidget::sortFolder(VisualDeckStorageFolderDisplayWidget *folderWidget) -{ - auto children = - folderWidget->getFlowWidget()->findChildren(QString(), Qt::FindChildOption::FindDirectChildrenOnly); - for (auto widget : children) { - auto deckPreviewWidgets = - widget->findChildren(QString(), Qt::FindChildOption::FindDirectChildrenOnly); - auto newOrder = filterFiles(deckPreviewWidgets); - for (DeckPreviewWidget *previewWidget : newOrder) { - folderWidget->getFlowWidget()->removeWidget(previewWidget); - } - for (DeckPreviewWidget *previewWidget : newOrder) { - folderWidget->getFlowWidget()->addWidget(previewWidget); - } - } -} - -QList VisualDeckStorageSortWidget::filterFiles(QList widgets) -{ - // Sort the widgets list based on the current sort order - std::sort(widgets.begin(), widgets.end(), [this](DeckPreviewWidget *widget1, DeckPreviewWidget *widget2) { - if (!widget1 || !widget2) { - return false; // Handle null pointers gracefully - } - - QFileInfo info1(widget1->filePath); - QFileInfo info2(widget2->filePath); - - switch (sortOrder) { - case ByName: - return widget1->deckLoader->getDeck().deckList.getName() < - widget2->deckLoader->getDeck().deckList.getName(); - case Alphabetical: - return QString::localeAwareCompare(info1.fileName(), info2.fileName()) <= 0; - case ByLastModified: - return info1.lastModified() > info2.lastModified(); - case ByLastLoaded: { - QDateTime time1 = - QDateTime::fromString(widget1->deckLoader->getDeck().deckList.getLastLoadedTimestamp()); - QDateTime time2 = - QDateTime::fromString(widget2->deckLoader->getDeck().deckList.getLastLoadedTimestamp()); - return time1 > time2; - } - } - - return false; // Default case, no sorting applied - }); - - return widgets; -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.h deleted file mode 100644 index 1ea06aba4..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_sort_widget.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file visual_deck_storage_sort_widget.h - * @ingroup VisualDeckStorageWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_STORAGE_SORT_WIDGET_H -#define VISUAL_DECK_STORAGE_SORT_WIDGET_H - -#include "visual_deck_storage_widget.h" - -#include -#include -#include - -class VisualDeckStorageWidget; -class VisualDeckStorageFolderDisplayWidget; -class VisualDeckStorageSortWidget : public QWidget -{ - Q_OBJECT - -public: - explicit VisualDeckStorageSortWidget(VisualDeckStorageWidget *parent); - void retranslateUi(); - void updateSortOrder(); - void sortFolder(VisualDeckStorageFolderDisplayWidget *folderWidget); - QString getSearchText(); - QList filterFiles(QList widgets); - -signals: - void sortOrderChanged(); - -private: - enum SortOrder - { - ByName, - Alphabetical, - ByLastModified, - ByLastLoaded, - }; - QHBoxLayout *layout; - VisualDeckStorageWidget *parent; - SortOrder sortOrder; // Current sorting option - QComboBox *sortComboBox; -}; - -#endif // VISUAL_DECK_STORAGE_SORT_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp deleted file mode 100644 index 28fd7a5ca..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "visual_deck_storage_tag_filter_widget.h" - -#include "../general/layout_containers/flow_widget.h" -#include "deck_preview/deck_preview_tag_display_widget.h" -#include "visual_deck_storage_widget.h" - -#include - -VisualDeckStorageTagFilterWidget::VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent) - : QWidget(_parent), parent(_parent) -{ - - setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - - // Create layout - auto *layout = new QHBoxLayout(this); - layout->setContentsMargins(5, 0, 5, 0); - - setFixedHeight(100); - - auto *flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); - - layout->addWidget(flowWidget); -} - -void VisualDeckStorageTagFilterWidget::showEvent(QShowEvent *event) -{ - QWidget::showEvent(event); - refreshTags(); -} - -void VisualDeckStorageTagFilterWidget::filterDecksBySelectedTags(const QList &deckPreviews) const -{ - QStringList selectedTags; - QStringList excludedTags; - - // Collect selected and excluded tags - for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) { - switch (tagWidget->getState()) { - case TagState::Selected: - selectedTags.append(tagWidget->getTagName()); - break; - case TagState::Excluded: - excludedTags.append(tagWidget->getTagName()); - break; - default: - break; - } - } - - // If no tags are selected or excluded, show all - if (selectedTags.isEmpty() && excludedTags.isEmpty()) { - for (DeckPreviewWidget *deckPreview : deckPreviews) { - deckPreview->filteredByTags = false; - } - return; - } - - for (DeckPreviewWidget *deckPreview : deckPreviews) { - QStringList deckTags = deckPreview->deckLoader->getDeck().deckList.getTags(); - - bool hasAllSelected = std::all_of(selectedTags.begin(), selectedTags.end(), - [&deckTags](const QString &tag) { return deckTags.contains(tag); }); - - bool hasAnyExcluded = std::any_of(excludedTags.begin(), excludedTags.end(), - [&deckTags](const QString &tag) { return deckTags.contains(tag); }); - - // Filter out if any excluded tag is present or if any selected tag is missing - deckPreview->filteredByTags = !(hasAllSelected && !hasAnyExcluded); - } -} - -void VisualDeckStorageTagFilterWidget::refreshTags() -{ - QSet allTags = gatherAllTags(); - removeTagsNotInList(allTags); - addTagsIfNotPresent(allTags); - sortTags(); -} - -void VisualDeckStorageTagFilterWidget::removeTagsNotInList(const QSet &tags) -{ - auto *flowWidget = findChild(); - - for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) { - const QString &tagName = tagWidget->getTagName(); - - // Keep the tag widget if it is either selected or excluded - if (!tags.contains(tagName) && tagWidget->getState() == TagState::NotSelected) { - flowWidget->removeWidget(tagWidget); - tagWidget->deleteLater(); - } - } -} - -void VisualDeckStorageTagFilterWidget::addTagsIfNotPresent(const QSet &tags) -{ - for (const QString &tag : tags) { - addTagIfNotPresent(tag); - } -} - -void VisualDeckStorageTagFilterWidget::addTagIfNotPresent(const QString &tag) -{ - // Check if the tag already exists in the flow widget - bool tagExists = false; - for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) { - if (tagWidget->getTagName() == tag) { - tagExists = true; - break; - } - } - - // If the tag doesn't exist, add a new DeckPreviewTagDisplayWidget - if (!tagExists) { - auto *newTagWidget = new DeckPreviewTagDisplayWidget(this, tag); - connect(newTagWidget, &DeckPreviewTagDisplayWidget::tagClicked, parent, - &VisualDeckStorageWidget::updateTagFilter); - connect(newTagWidget, &DeckPreviewTagDisplayWidget::tagClicked, this, - &VisualDeckStorageTagFilterWidget::refreshTags); - auto *flowWidget = findChild(); - flowWidget->addWidget(newTagWidget); - } -} - -void VisualDeckStorageTagFilterWidget::sortTags() -{ - auto *flowWidget = findChild(); - if (!flowWidget) - return; - - // Get all tag widgets - QList tagWidgets = findChildren(); - - // Sort widgets by tag name - std::sort(tagWidgets.begin(), tagWidgets.end(), [](DeckPreviewTagDisplayWidget *a, DeckPreviewTagDisplayWidget *b) { - return a->getTagName().toLower() < b->getTagName().toLower(); - }); - - // Clear and re-add widgets in sorted order - for (DeckPreviewTagDisplayWidget *tagWidget : tagWidgets) { - flowWidget->removeWidget(tagWidget); - } - for (DeckPreviewTagDisplayWidget *tagWidget : tagWidgets) { - flowWidget->addWidget(tagWidget); - } -} - -QSet VisualDeckStorageTagFilterWidget::gatherAllTags() const -{ - QSet allTags; - QList deckWidgets = parent->findChildren(); - - for (DeckPreviewWidget *widget : deckWidgets) { - if (widget->checkVisibility()) { - for (const QString &tag : widget->deckLoader->getDeck().deckList.getTags()) { - allTags.insert(tag); - } - } - } - return allTags; -} - -QStringList VisualDeckStorageTagFilterWidget::getAllKnownTags() const -{ - QStringList allTags; - - for (DeckPreviewTagDisplayWidget *tagWidget : findChildren()) { - allTags.append(tagWidget->getTagName()); - } - - // Remove duplicates by calling 'removeDuplicates' - allTags.removeDuplicates(); - - return allTags; -} diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h deleted file mode 100644 index ada94a244..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file visual_deck_storage_tag_filter_widget.h - * @ingroup VisualDeckStorageWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H -#define VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H - -#include "deck_preview/deck_preview_widget.h" - -#include - -class VisualDeckStorageWidget; -class VisualDeckStorageTagFilterWidget : public QWidget -{ - Q_OBJECT - - VisualDeckStorageWidget *parent; - - [[nodiscard]] QSet gatherAllTags() const; - void removeTagsNotInList(const QSet &tags); - void addTagsIfNotPresent(const QSet &tags); - void addTagIfNotPresent(const QString &tag); - void sortTags(); - -public: - explicit VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent); - [[nodiscard]] QStringList getAllKnownTags() const; - void filterDecksBySelectedTags(const QList &deckPreviews) const; - -public slots: - void refreshTags(); - void showEvent(QShowEvent *event) override; -}; - -#endif // VISUAL_DECK_STORAGE_TAG_FILTER_WIDGET_H diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp deleted file mode 100644 index bfc425993..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "visual_deck_storage_widget.h" - -#include "../../../client/settings/cache_settings.h" -#include "../quick_settings/settings_button_widget.h" -#include "deck_preview/deck_preview_widget.h" -#include "visual_deck_storage_folder_display_widget.h" -#include "visual_deck_storage_search_widget.h" -#include "visual_deck_storage_sort_widget.h" -#include "visual_deck_storage_tag_filter_widget.h" - -#include -#include -#include -#include -#include - -VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), folderWidget(nullptr) -{ - deckListModel = new DeckListModel(this); - deckListModel->setObjectName("visualDeckModel"); - - layout = new QVBoxLayout(this); - layout->setSpacing(0); - layout->setContentsMargins(9, 0, 9, 5); - setLayout(layout); - - // search bar row - searchAndSortContainer = new QWidget(this); - searchAndSortLayout = new QHBoxLayout(searchAndSortContainer); - searchAndSortLayout->setSpacing(3); - searchAndSortLayout->setContentsMargins(9, 0, 9, 0); - searchAndSortContainer->setLayout(searchAndSortLayout); - - deckPreviewColorIdentityFilterWidget = new DeckPreviewColorIdentityFilterWidget(this); - sortWidget = new VisualDeckStorageSortWidget(this); - searchWidget = new VisualDeckStorageSearchWidget(this); - - refreshButton = new QToolButton(this); - refreshButton->setIcon(QPixmap("theme:icons/reload")); - refreshButton->setFixedSize(32, 32); - connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible); - - quickSettingsWidget = new VisualDeckStorageQuickSettingsWidget(this); - connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showFoldersChanged, this, - &VisualDeckStorageWidget::updateShowFolders); - connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged, this, - &VisualDeckStorageWidget::updateTagsVisibility); - - searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget); - searchAndSortLayout->addWidget(sortWidget); - searchAndSortLayout->addWidget(searchWidget); - searchAndSortLayout->addWidget(refreshButton); - searchAndSortLayout->addWidget(quickSettingsWidget); - - // tag filter box - tagFilterWidget = new VisualDeckStorageTagFilterWidget(this); - updateTagsVisibility(SettingsCache::instance().getVisualDeckStorageShowTagFilter()); - - deckPreviewSelectionAnimationEnabled = SettingsCache::instance().getVisualDeckStorageSelectionAnimation(); - connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageSelectionAnimationChanged, this, - &VisualDeckStorageWidget::updateSelectionAnimationEnabled); - - // deck area - scrollArea = new QScrollArea(this); - scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollArea->setWidgetResizable(true); - - // putting everything together - layout->addWidget(searchAndSortContainer); - layout->addWidget(tagFilterWidget); - layout->addWidget(scrollArea); - - connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this, - &VisualDeckStorageWidget::createRootFolderWidget); - - databaseLoadIndicator = new QLabel(this); - databaseLoadIndicator->setAlignment(Qt::AlignCenter); - - retranslateUi(); - - // Don't waste time processing the cards if they're going to get refreshed anyway once the db finishes loading - if (CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok) { - createRootFolderWidget(); - databaseLoadIndicator->setVisible(false); - } else { - scrollArea->setWidget(databaseLoadIndicator); - } -} - -void VisualDeckStorageWidget::refreshIfPossible() -{ - if (scrollArea->widget() != databaseLoadIndicator) { - createRootFolderWidget(); - } -} - -void VisualDeckStorageWidget::showEvent(QShowEvent *event) -{ - QWidget::showEvent(event); - if (scrollArea->widget() == folderWidget) { - scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width()); - scrollArea->widget()->adjustSize(); - } -} - -void VisualDeckStorageWidget::resizeEvent(QResizeEvent *event) -{ - QWidget::resizeEvent(event); - if (scrollArea->widget() == folderWidget) { - scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width()); - scrollArea->widget()->adjustSize(); - } -} - -void VisualDeckStorageWidget::retranslateUi() -{ - databaseLoadIndicator->setText(tr("Loading database ...")); - - refreshButton->setToolTip(tr("Refresh loaded files")); - quickSettingsWidget->setToolTip(tr("Visual Deck Storage Settings")); -} - -/** - * Gets a const pointer to the quick settings so that the values can be accessed. - */ -const VisualDeckStorageQuickSettingsWidget *VisualDeckStorageWidget::settings() const -{ - return quickSettingsWidget; -} - -/** - * Reapplies all sort and filter options by calling the appropriate update methods. - */ -void VisualDeckStorageWidget::reapplySortAndFilters() -{ - updateSortOrder(); - updateTagFilter(); - updateColorFilter(); - updateSearchFilter(); -} - -void VisualDeckStorageWidget::createRootFolderWidget() -{ - folderWidget = new VisualDeckStorageFolderDisplayWidget(this, this, SettingsCache::instance().getDeckPath(), false, - quickSettingsWidget->getShowFolders()); - - scrollArea->setWidget(folderWidget); // this automatically destroys the old folderWidget - scrollArea->widget()->setMaximumWidth(scrollArea->viewport()->width()); - scrollArea->widget()->adjustSize(); - - /* We have to schedule a QTimer here so that the sorting logic doesn't try to access widgets that haven't been - * processed by the event loop yet. Otherwise, deck sorting will intermittently segfault on some systems. - */ - QTimer::singleShot(0, this, &VisualDeckStorageWidget::reapplySortAndFilters); -} - -void VisualDeckStorageWidget::updateShowFolders(bool enabled) -{ - if (folderWidget) { - folderWidget->updateShowFolders(enabled); - QTimer::singleShot(0, this, &VisualDeckStorageWidget::reapplySortAndFilters); - } -} - -void VisualDeckStorageWidget::updateSortOrder() -{ - if (folderWidget) { - sortWidget->sortFolder(folderWidget); - for (VisualDeckStorageFolderDisplayWidget *subFolderWidget : - folderWidget->findChildren()) { - sortWidget->sortFolder(subFolderWidget); - } - } -} - -void VisualDeckStorageWidget::updateTagFilter() -{ - if (folderWidget) { - tagFilterWidget->filterDecksBySelectedTags(folderWidget->findChildren()); - folderWidget->updateVisibility(); - } -} - -void VisualDeckStorageWidget::updateColorFilter() -{ - if (folderWidget) { - deckPreviewColorIdentityFilterWidget->filterWidgets(folderWidget->findChildren()); - folderWidget->updateVisibility(); - } -} - -void VisualDeckStorageWidget::updateSearchFilter() -{ - if (folderWidget) { - searchWidget->filterWidgets(folderWidget->findChildren(), searchWidget->getSearchText()); - folderWidget->updateVisibility(); - } -} - -void VisualDeckStorageWidget::updateTagsVisibility(const bool visible) -{ - if (visible) { - tagFilterWidget->setVisible(true); - - } else { - tagFilterWidget->setHidden(true); - } -} - -void VisualDeckStorageWidget::updateSelectionAnimationEnabled(const bool enabled) -{ - deckPreviewSelectionAnimationEnabled = enabled; -} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h deleted file mode 100644 index b13c51700..000000000 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file visual_deck_storage_widget.h - * @ingroup VisualDeckStorageWidgets - * @brief TODO: Document this. - */ - -#ifndef VISUAL_DECK_STORAGE_WIDGET_H -#define VISUAL_DECK_STORAGE_WIDGET_H - -#include "../../deck_loader/deck_loader.h" -#include "../cards/card_size_widget.h" -#include "../quick_settings/settings_button_widget.h" -#include "deck_preview/deck_preview_color_identity_filter_widget.h" -#include "visual_deck_storage_folder_display_widget.h" -#include "visual_deck_storage_quick_settings_widget.h" -#include "visual_deck_storage_search_widget.h" -#include "visual_deck_storage_sort_widget.h" -#include "visual_deck_storage_tag_filter_widget.h" - -#include - -class QSpinBox; -class VisualDeckStorageSearchWidget; -class VisualDeckStorageSortWidget; -class VisualDeckStorageTagFilterWidget; -class VisualDeckStorageFolderDisplayWidget; -class DeckPreviewColorIdentityFilterWidget; -class VisualDeckStorageWidget final : public QWidget -{ - Q_OBJECT -public: - explicit VisualDeckStorageWidget(QWidget *parent); - void refreshIfPossible(); - void retranslateUi(); - - VisualDeckStorageTagFilterWidget *tagFilterWidget; - bool deckPreviewSelectionAnimationEnabled; - - [[nodiscard]] const VisualDeckStorageQuickSettingsWidget *settings() const; - -public slots: - void createRootFolderWidget(); // Refresh the display of cards based on the current sorting option - void updateShowFolders(bool enabled); - void updateTagFilter(); - void updateColorFilter(); - void updateSearchFilter(); - void updateTagsVisibility(bool visible); - void updateSelectionAnimationEnabled(bool enabled); - void updateSortOrder(); - void resizeEvent(QResizeEvent *event) override; - void showEvent(QShowEvent *event) override; - -signals: - void bannerCardsRefreshed(); - void deckLoadRequested(const QString &filePath); - void openDeckEditor(const LoadedDeck &deck); - -private: - QVBoxLayout *layout; - QWidget *searchAndSortContainer; - QHBoxLayout *searchAndSortLayout; - DeckListModel *deckListModel; - QLabel *databaseLoadIndicator; - VisualDeckStorageSortWidget *sortWidget; - VisualDeckStorageSearchWidget *searchWidget; - DeckPreviewColorIdentityFilterWidget *deckPreviewColorIdentityFilterWidget; - QToolButton *refreshButton; - VisualDeckStorageQuickSettingsWidget *quickSettingsWidget; - QScrollArea *scrollArea; - VisualDeckStorageFolderDisplayWidget *folderWidget; - - void reapplySortAndFilters(); -}; - -#endif // VISUAL_DECK_STORAGE_WIDGET_H