From 55b6f2a58806f3bbcaef5d83d9c77a3677218f65 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Wed, 24 Jan 2024 23:18:52 +0800 Subject: [PATCH] QoL: Port profile value transfer on profile diff dialog from PrusaSlicer (#3737) * DiffDialog: Implemented a transfer of options from one preset to another Related to [Feature Request] #5384 - Copy values in Profile comparaison dialog Cherry-picked from prusa3d/PrusaSlicer@0b8d7380ff4b360e3aefa8d1153cb1641668844d Co-authored-by: YuSanka * Remove save button * Sync with latest PS * Use Orca button style * Show tips about trasnfer disabled --------- Co-authored-by: YuSanka --- src/libslic3r/PresetBundle.hpp | 13 ++ src/slic3r/GUI/ConfigWizard.cpp | 4 +- src/slic3r/GUI/GUI_App.cpp | 9 +- src/slic3r/GUI/MainFrame.cpp | 36 ++- src/slic3r/GUI/MainFrame.hpp | 1 + src/slic3r/GUI/Plater.cpp | 5 +- src/slic3r/GUI/Preferences.cpp | 2 +- src/slic3r/GUI/PresetComboBoxes.cpp | 1 - src/slic3r/GUI/Tab.cpp | 59 ++++- src/slic3r/GUI/Tab.hpp | 19 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 294 +++++++++++++++++++----- src/slic3r/GUI/UnsavedChangesDialog.hpp | 87 ++++--- src/slic3r/GUI/WebGuideDialog.cpp | 2 +- 13 files changed, 423 insertions(+), 109 deletions(-) diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 9af153b49c3..0050561286d 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -1,3 +1,8 @@ +///|/ Copyright (c) Prusa Research 2017 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, David Kocík @kocikdav, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2019 John Drake @foxox +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_PresetBundle_hpp_ #define slic3r_PresetBundle_hpp_ @@ -7,6 +12,7 @@ #include #include +#include #include #define DEFAULT_USER_FOLDER_NAME "default" @@ -247,6 +253,13 @@ class PresetBundle static const char *BBL_DEFAULT_PRINTER_MODEL; static const char *BBL_DEFAULT_PRINTER_VARIANT; static const char *BBL_DEFAULT_FILAMENT; + + static std::array types_list(PrinterTechnology pt) { + if (pt == ptFFF) + return { Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT }; + return { Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }; + } + private: //std::pair load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule); //BBS: add json related logic diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index a34a7cd46ea..1768d8cd473 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -2405,9 +2405,9 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese bool check_unsaved_preset_changes = false; if (check_unsaved_preset_changes) header = _L("All user presets will be deleted."); - int act_btns = UnsavedChangesDialog::ActionButtons::KEEP; + int act_btns = ActionButtons::KEEP; if (!check_unsaved_preset_changes) - act_btns |= UnsavedChangesDialog::ActionButtons::SAVE; + act_btns |= ActionButtons::SAVE; // Install bundles from resources if needed: std::vector install_bundles; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 2273a91f2c9..afd76b546ae 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3758,8 +3758,7 @@ void GUI_App::request_user_logout() bool transfer_preset_changes = false; wxString header = _L("Some presets are modified.") + "\n" + _L("You can keep the modifield presets to the new project, discard or save changes as new presets."); - using ab = UnsavedChangesDialog::ActionButtons; - wxGetApp().check_and_keep_current_preset_changes(_L("User logged out"), header, ab::KEEP | ab::SAVE, &transfer_preset_changes); + wxGetApp().check_and_keep_current_preset_changes(_L("User logged out"), header, ActionButtons::KEEP | ActionButtons::SAVE, &transfer_preset_changes); m_device_manager->clean_user_info(); GUI::wxGetApp().sidebar().load_ams_list({}, {}); @@ -5606,11 +5605,11 @@ std::vector> GUI_App::get_selected_presets( bool GUI_App::check_and_save_current_preset_changes(const wxString& caption, const wxString& header, bool remember_choice/* = true*/, bool dont_save_insted_of_discard/* = false*/) { if (has_current_preset_changes()) { - int act_buttons = UnsavedChangesDialog::ActionButtons::SAVE; + int act_buttons = ActionButtons::SAVE; if (dont_save_insted_of_discard) - act_buttons |= UnsavedChangesDialog::ActionButtons::DONT_SAVE; + act_buttons |= ActionButtons::DONT_SAVE; if (remember_choice) - act_buttons |= UnsavedChangesDialog::ActionButtons::REMEMBER_CHOISE; + act_buttons |= ActionButtons::REMEMBER_CHOISE; UnsavedChangesDialog dlg(caption, header, "", act_buttons); if (dlg.ShowModal() == wxID_CANCEL) return false; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 17a753186ad..288e8a579e2 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -611,8 +611,41 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ wxGetApp().persist_window_geometry(this, true); wxGetApp().persist_window_geometry(&m_settings_dialog, true); + // bind events from DiffDlg + + bind_diff_dialog(); +} + +void MainFrame::bind_diff_dialog() +{ + auto get_tab = [](Preset::Type type) { + Tab* null_tab = nullptr; + for (Tab* tab : wxGetApp().tabs_list) + if (tab->type() == type) + return tab; + return null_tab; + }; + + auto transfer = [this, get_tab](Preset::Type type) { + get_tab(type)->transfer_options(diff_dialog.get_left_preset_name(type), + diff_dialog.get_right_preset_name(type), + diff_dialog.get_selected_options(type)); + }; + + auto process_options = [this](std::function process) { + const Preset::Type diff_dlg_type = diff_dialog.view_type(); + if (diff_dlg_type == Preset::TYPE_INVALID) { + for (const Preset::Type& type : diff_dialog.types_list() ) + process(type); + } + else + process(diff_dlg_type); + }; + + diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [process_options, transfer](SimpleEvent&) { process_options(transfer); }); } + #ifdef __WIN32__ WXLRESULT MainFrame::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) @@ -3599,9 +3632,6 @@ void MainFrame::RunScript(wxString js) void MainFrame::technology_changed() { - // upadte DiffDlg - diff_dialog.update_presets(); - // update menu titles PrinterTechnology pt = plater()->printer_technology(); if (int id = m_menubar->FindMenu(pt == ptFFF ? _omitL("Material Settings") : _L("Filament Settings")); id != wxNOT_FOUND) diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 28ff66fd957..14f11f1a2b1 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -131,6 +131,7 @@ class MainFrame : public DPIFrame bool can_delete() const; bool can_delete_all() const; bool can_reslice() const; + void bind_diff_dialog(); // BBS wxBoxSizer* create_side_tools(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 20f65758a0a..67d3022d54a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -8299,10 +8299,9 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_ wxString header = _L("Some presets are modified.") + "\n" + (yes_or_no ? _L("You can keep the modified presets to the new project or discard them") : _L("You can keep the modifield presets to the new project, discard or save changes as new presets.")); - using ab = UnsavedChangesDialog::ActionButtons; - int act_buttons = ab::KEEP | ab::REMEMBER_CHOISE; + int act_buttons = ActionButtons::KEEP | ActionButtons::REMEMBER_CHOISE; if (!yes_or_no) - act_buttons |= ab::SAVE; + act_buttons |= ActionButtons::SAVE; return wxGetApp().check_and_keep_current_preset_changes(_L("Creating a new project"), header, act_buttons, &transfer_preset_changes); }; int result; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index a4b4edf5a1e..40b3dc7fb3a 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -222,7 +222,7 @@ wxBoxSizer *PreferencesDialog::create_item_language_combobox( auto check = [this](bool yes_or_no) { // if (yes_or_no) // return true; - int act_btns = UnsavedChangesDialog::ActionButtons::SAVE; + int act_btns = ActionButtons::SAVE; return wxGetApp().check_and_keep_current_preset_changes(_L("Switching application language"), _L("Switching application language while some presets are modified."), act_btns); }; diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index c0e59741b32..2ecbb5e0826 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -37,7 +37,6 @@ #include "../Utils/FixModelByWin10.hpp" #include "../Utils/UndoRedo.hpp" #include "BitmapCache.hpp" -#include "SavePresetDialog.hpp" #include "MsgDialog.hpp" #include "ParamsDialog.hpp" diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0ee5c1a36bc..9e23aec99a1 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1,3 +1,22 @@ +///|/ Copyright (c) Prusa Research 2017 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, Tomáš Mészáros @tamasmeszaros, David Kocík @kocikdav, Enrico Turri @enricoturri1966, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2021 Martin Budden +///|/ Copyright (c) 2021 Ilya @xorza +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2019 Matthias Urlichs @smurfix +///|/ Copyright (c) 2019 Thomas Moore +///|/ Copyright (c) 2019 Sijmen Schoon +///|/ Copyright (c) 2018 Martin Loidl @LoidlM +///|/ +///|/ ported from lib/Slic3r/GUI/Tab.pm: +///|/ Copyright (c) Prusa Research 2016 - 2018 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena +///|/ Copyright (c) 2015 - 2017 Joseph Lenox @lordofhyphens +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2016 Chow Loong Jin @hyperair +///|/ Copyright (c) 2012 QuantumConcepts +///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ // #include "libslic3r/GCodeSender.hpp" //#include "slic3r/Utils/Serial.hpp" #include "Tab.hpp" @@ -1692,9 +1711,9 @@ void Tab::apply_searcher() wxGetApp().sidebar().get_searcher().apply(m_config, m_type, m_mode); } -void Tab::cache_config_diff(const std::vector& selected_options) +void Tab::cache_config_diff(const std::vector& selected_options, const DynamicPrintConfig* config/* = nullptr*/) { - m_cache_config.apply_only(m_presets->get_edited_preset().config, selected_options); + m_cache_config.apply_only(config ? *config : m_presets->get_edited_preset().config, selected_options); } void Tab::apply_config_from_cache() @@ -5076,6 +5095,32 @@ void Tab::compare_preset() wxGetApp().mainframe->diff_dialog.show(m_type); } +void Tab::transfer_options(const std::string &name_from, const std::string &name_to, std::vector options) +{ + if (options.empty()) + return; + + Preset* preset_from = m_presets->find_preset(name_from); + Preset* preset_to = m_presets->find_preset(name_to); + + if (m_type == Preset::TYPE_PRINTER) { + auto it = std::find(options.begin(), options.end(), "extruders_count"); + if (it != options.end()) { + // erase "extruders_count" option from the list + options.erase(it); + // cache the extruders count + static_cast(this)->cache_extruder_cnt(&preset_from->config); + } + } + cache_config_diff(options, &preset_from->config); + + if (name_to != m_presets->get_edited_preset().name ) + select_preset(preset_to->name); + + apply_config_from_cache(); + load_current_preset(); +} + // Save the current preset into file. // This removes the "dirty" flag of the preset, possibly creates a new preset under a new name, // and activates the new preset. @@ -5513,13 +5558,15 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent) return sizer; } -void TabPrinter::cache_extruder_cnt() +void TabPrinter::cache_extruder_cnt(const DynamicPrintConfig* config/* = nullptr*/) { - if (m_presets->get_edited_preset().printer_technology() == ptSLA) + const DynamicPrintConfig& cached_config = config ? *config : m_presets->get_edited_preset().config; + if (Preset::printer_technology(cached_config) == ptSLA) return; - // BBS. Get extruder count from preset instead of m_extruders_count. - m_cache_extruder_count = dynamic_cast((m_presets->get_edited_preset().config).option("nozzle_diameter"))->values.size(); + // get extruders count + auto* nozzle_diameter = dynamic_cast(cached_config.option("nozzle_diameter")); + m_cache_extruder_count = nozzle_diameter->values.size(); //m_extruders_count; } bool TabPrinter::apply_extruder_cnt_from_cache() diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index c33d76ea573..f04f3033607 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -1,3 +1,17 @@ +///|/ Copyright (c) Prusa Research 2017 - 2023 Oleksandra Iushchenko @YuSanka, Tomáš Mészáros @tamasmeszaros, Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2019 John Drake @foxox +///|/ Copyright (c) 2018 Martin Loidl @LoidlM +///|/ +///|/ ported from lib/Slic3r/GUI/Tab.pm: +///|/ Copyright (c) Prusa Research 2016 - 2018 Vojtěch Bubník @bubnikv, Lukáš Matěna @lukasmatena +///|/ Copyright (c) 2015 - 2017 Joseph Lenox @lordofhyphens +///|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel +///|/ Copyright (c) 2016 Chow Loong Jin @hyperair +///|/ Copyright (c) 2012 QuantumConcepts +///|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_Tab_hpp_ #define slic3r_Tab_hpp_ @@ -338,6 +352,7 @@ class Tab: public wxPanel void OnKeyDown(wxKeyEvent& event); void compare_preset(); + void transfer_options(const std::string&name_from, const std::string&name_to, std::vector options); //BBS: add project embedded preset relate logic void save_preset(std::string name = std::string(), bool detach = false, bool save_to_project = false, bool from_input = false, std::string input_name = ""); //void save_preset(std::string name = std::string(), bool detach = false); @@ -396,7 +411,7 @@ class Tab: public wxPanel void update_wiping_button_visibility(); void activate_option(const std::string& opt_key, const wxString& category); void apply_searcher(); - void cache_config_diff(const std::vector& selected_options); + void cache_config_diff(const std::vector& selected_options, const DynamicPrintConfig* config = nullptr); void apply_config_from_cache(); void show_timelapse_warning_dialog(); @@ -625,7 +640,7 @@ class TabPrinter : public Tab bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; } wxSizer* create_bed_shape_widget(wxWindow* parent); - void cache_extruder_cnt(); + void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr); bool apply_extruder_cnt_from_cache(); }; diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 5da3aaae4da..710898e72f7 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1,3 +1,9 @@ +///|/ Copyright (c) Prusa Research 2020 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv, Enrico Turri @enricoturri1966, David Kocík @kocikdav +///|/ Copyright (c) 2021 Pascal de Bruijn @pmjdebruijn +///|/ Copyright (c) 2021 Sebastian Hammerl +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "UnsavedChangesDialog.hpp" #include @@ -5,7 +11,6 @@ #include #include #include -#include #include @@ -22,10 +27,6 @@ #include "MainFrame.hpp" #include "MsgDialog.hpp" -//#define FTS_FUZZY_MATCH_IMPLEMENTATION -//#include "fts_fuzzy_match.h" - -#include "BitmapCache.hpp" #include "PresetComboBoxes.hpp" #include "Widgets/RoundedRectangle.hpp" #include "Widgets/CheckBox.hpp" @@ -42,6 +43,9 @@ namespace Slic3r { namespace GUI { +wxDEFINE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent); + + // ---------------------------------------------------------------------------- // ModelNode: a node inside DiffModel // ---------------------------------------------------------------------------- @@ -105,8 +109,8 @@ ModelNode::ModelNode(ModelNode* parent, const wxString& text, const std::string& ModelNode::ModelNode(ModelNode* parent, const wxString& text) : m_parent_win(parent->m_parent_win), m_parent(parent), - m_text(text), - m_icon_name("node_dot") + m_icon_name("node_dot"), + m_text(text) { UpdateIcons(); } @@ -143,11 +147,11 @@ ModelNode::ModelNode(ModelNode* parent, const wxString& text, const wxString& ol m_parent(parent), m_old_color(old_value.StartsWith("#") ? old_value : ""), m_new_color(new_value.StartsWith("#") ? new_value : ""), - m_container(false), - m_text(text), m_icon_name("empty"), + m_text(text), m_old_value(old_value), - m_new_value(new_value) + m_new_value(new_value), + m_container(false) { // check if old/new_value is color if (m_old_color.IsEmpty()) { @@ -487,7 +491,7 @@ unsigned int DiffModel::GetChildren(const wxDataViewItem& parent, wxDataViewItem for (const std::unique_ptr& child : children) array.Add(wxDataViewItem((void*)child.get())); - return array.size(); + return array.Count(); } @@ -573,7 +577,7 @@ void DiffModel::Clear() static std::string get_pure_opt_key(std::string opt_key) { - int pos = opt_key.find("#"); + const int pos = opt_key.find("#"); if (pos > 0) boost::erase_tail(opt_key, opt_key.size() - pos); return opt_key; @@ -1824,35 +1828,11 @@ static std::string get_selection(PresetComboBox* preset_combo) return into_u8(preset_combo->GetString(preset_combo->GetSelection())); } -DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) - : DPIDialog(mainframe, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - m_pr_technology(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology()) +void DiffPresetDialog::create_presets_sizer() { -#if defined(__WXMSW__) - // ys_FIXME! temporary workaround for correct font scaling - // Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts, - // From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT - this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); -#endif // __WXMSW__ - - int border = 10; - int em = em_unit(); - SetBackgroundColour(*wxWHITE); - assert(wxGetApp().preset_bundle); - - m_preset_bundle_left = std::make_unique(*wxGetApp().preset_bundle); - m_preset_bundle_right = std::make_unique(*wxGetApp().preset_bundle); - - //m_top_info_line = new wxStaticText(this, wxID_ANY, "Select presets to compare"); - m_top_info_line = new wxStaticText(this, wxID_ANY, _L("Select presets to compare")); - m_top_info_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); - - m_bottom_info_line = new wxStaticText(this, wxID_ANY, ""); - m_bottom_info_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold()); - - wxBoxSizer* presets_sizer = new wxBoxSizer(wxVERTICAL); + m_presets_sizer = new wxBoxSizer(wxVERTICAL); - for (auto new_type : { Preset::TYPE_PRINT, Preset::TYPE_FILAMENT, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL, Preset::TYPE_PRINTER }) + for (auto new_type : { Preset::TYPE_PRINT, Preset::TYPE_SLA_PRINT, Preset::TYPE_FILAMENT, Preset::TYPE_SLA_MATERIAL, Preset::TYPE_PRINTER }) { const PresetCollection* collection = get_preset_collection(new_type); wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); @@ -1860,13 +1840,13 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) PresetComboBox* presets_right; ScalableButton* equal_bmp = new ScalableButton(this, wxID_ANY, "equal"); - auto add_preset_combobox = [collection, sizer, new_type, em, this](PresetComboBox** cb_, PresetBundle* preset_bundle) { - *cb_ = new PresetComboBox(this, new_type, wxSize(em * 35, -1), preset_bundle); + auto add_preset_combobox = [collection, sizer, new_type, this](PresetComboBox** cb_, PresetBundle* preset_bundle) { + *cb_ = new PresetComboBox(this, new_type, wxSize(em_unit() * 35, -1), preset_bundle); PresetComboBox* cb = (*cb_); cb->set_selection_changed_function([this, new_type, preset_bundle, cb](int selection) { if (m_view_type == Preset::TYPE_INVALID) { - std::string preset_name = cb->GetString(selection).ToUTF8().data(); - update_compatibility(Preset::remove_suffix_modified(preset_name), new_type, preset_bundle); + std::string preset_name = Preset::remove_suffix_modified(cb->GetString(selection).ToUTF8().data()); + update_compatibility(preset_name, new_type, preset_bundle); } update_tree(); }); @@ -1879,7 +1859,7 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) add_preset_combobox(&presets_left, m_preset_bundle_left.get()); sizer->Add(equal_bmp, 0, wxRIGHT | wxLEFT | wxALIGN_CENTER_VERTICAL, 5); add_preset_combobox(&presets_right, m_preset_bundle_right.get()); - presets_sizer->Add(sizer, 1, wxTOP, 5); + m_presets_sizer->Add(sizer, 1, wxTOP, 5); equal_bmp->Show(new_type == Preset::TYPE_PRINTER); m_preset_combos.push_back({ presets_left, equal_bmp, presets_right }); @@ -1892,7 +1872,10 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) update_tree(); }); } +} +void DiffPresetDialog::create_show_all_presets_chb() +{ m_show_all_presets = new wxCheckBox(this, wxID_ANY, _L("Show all presets (including incompatible)")); m_show_all_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { bool show_all = m_show_all_presets->GetValue(); @@ -1905,27 +1888,189 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) if (m_view_type == Preset::TYPE_INVALID) update_tree(); }); +} + +void DiffPresetDialog::create_info_lines() +{ + const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); + + m_top_info_line = new wxStaticText(this, wxID_ANY, _L("Select presets to compare")); + m_top_info_line->SetFont(font); + + m_bottom_info_line = new wxStaticText(this, wxID_ANY, ""); + m_bottom_info_line->SetFont(font); +} - m_tree = new DiffViewCtrl(this, wxSize(em * 65, em * 40)); +void DiffPresetDialog::create_tree() +{ + m_tree = new DiffViewCtrl(this, wxSize(em_unit() * 65, em_unit() * 40)); + m_tree->AppendToggleColumn_(L"\u2714", DiffModel::colToggle, wxLinux ? 9 : 6); m_tree->AppendBmpTextColumn("", DiffModel::colIconText, 35); m_tree->AppendBmpTextColumn("Left Preset Value", DiffModel::colOldValue, 15); m_tree->AppendBmpTextColumn("Right Preset Value",DiffModel::colNewValue, 15); m_tree->Hide(); + m_tree->GetColumn(DiffModel::colToggle)->SetHidden(true); +} - wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); +std::array DiffPresetDialog::types_list() const +{ + return PresetBundle::types_list(m_pr_technology); +} - topSizer->Add(m_top_info_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 2 * border); - topSizer->Add(presets_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); - topSizer->Add(m_show_all_presets, 0, wxEXPAND | wxALL, border); - topSizer->Add(m_bottom_info_line, 0, wxEXPAND | wxALL, 2 * border); - topSizer->Add(m_tree, 1, wxEXPAND | wxALL, border); +void DiffPresetDialog::create_buttons() +{ + wxFont font = this->GetFont().Scaled(1.4f); + StateColor btn_bg_green(std::pair(wxColour(206, 206, 206), StateColor::Disabled), + std::pair(wxColour(0, 137, 123), StateColor::Pressed), + std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + m_buttons = new wxBoxSizer(wxHORIZONTAL); - this->SetMinSize(wxSize(80 * em, 30 * em)); + auto show_in_bottom_info = [this](const wxString& ext_line, wxEvent* e = nullptr) { + m_bottom_info_line->SetLabel(ext_line); + m_bottom_info_line->Show(true); + Layout(); + if (e) e->Skip(); + }; + + // Transfer + m_transfer_btn = new Button(this, L("Transfer")); + m_transfer_btn->SetBackgroundColor(btn_bg_green); + m_transfer_btn->SetBorderColor(wxColour(0, 150, 136)); + m_transfer_btn->SetTextColor(wxColour("#FFFFFE")); + m_transfer_btn->SetMinSize(wxSize(-1, -1)); + m_transfer_btn->SetCornerRadius(FromDIP(12)); + + m_transfer_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { button_event(Action::Transfer);}); + + + auto enable_transfer = [this](const Preset::Type& type) { + const Preset& main_edited_preset = get_preset_collection(type, wxGetApp().preset_bundle)->get_edited_preset(); + if (main_edited_preset.is_dirty) + return main_edited_preset.name == get_right_preset_name(type); + return true; + }; + m_transfer_btn->Bind(wxEVT_UPDATE_UI, [this, enable_transfer, show_in_bottom_info](wxUpdateUIEvent& evt) { + bool enable = m_tree->has_selection(); + if (enable) { + if (m_view_type == Preset::TYPE_INVALID) { + for (const Preset::Type& type : types_list()) + if (!enable_transfer(type)) { + enable = false; + break; + } + } + else + enable = enable_transfer(m_view_type); + + if (!enable && m_transfer_btn->IsShown()) { + show_in_bottom_info(_L("You can only transfer to current active profile because it has been modified.")); + } + } + evt.Enable(enable); + }); + m_transfer_btn->Bind(wxEVT_ENTER_WINDOW, [show_in_bottom_info](wxMouseEvent& e) { + show_in_bottom_info(_L("Transfer the selected options from left preset to the right.\n" + "Note: New modified presets will be selected in settings tabs after close this dialog."), &e); }); + + // Cancel + m_cancel_btn = new Button(this, L("Cancel")); + m_cancel_btn->SetTextColor(wxColour(107, 107, 107)); + m_cancel_btn->SetMinSize(wxSize(-1, -1)); + m_cancel_btn->SetCornerRadius(FromDIP(12)); + + m_cancel_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { button_event(Action::Discard);}); + + for (Button* btn : { m_transfer_btn, m_cancel_btn }) { + btn->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { update_bottom_info(); Layout(); e.Skip(); }); + m_buttons->Add(btn, 1, wxLEFT, 5); + btn->SetFont(font); + } + + m_buttons->Show(false); +} + +void DiffPresetDialog::create_edit_sizer() +{ + // Add check box for the edit mode + m_use_for_transfer = new wxCheckBox(this, wxID_ANY, _L("Transfer values from left to right")); + m_use_for_transfer->SetToolTip(_L("If enabled, this dialog can be used for transver selected values from left to right preset.")); + m_use_for_transfer->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { + bool use = m_use_for_transfer->GetValue(); + m_tree->GetColumn(DiffModel::colToggle)->SetHidden(!use); + if (m_tree->IsShown()) { + m_buttons->Show(use); + Fit(); + Refresh(); + } + else + this->Layout(); + }); + + // Add Buttons + create_buttons(); + + // Create and fill edit sizer + m_edit_sizer = new wxBoxSizer(wxHORIZONTAL); + m_edit_sizer->Add(m_use_for_transfer, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5); + m_edit_sizer->AddSpacer(em_unit() * 10); + m_edit_sizer->Add(m_buttons, 1, wxLEFT, 5); + m_edit_sizer->Show(false); +} + +void DiffPresetDialog::complete_dialog_creation() +{ + wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); + + int border = 10; + topSizer->Add(m_top_info_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 2 * border); + topSizer->Add(m_presets_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); + topSizer->Add(m_show_all_presets, 0, wxEXPAND | wxALL, border); + topSizer->Add(m_tree, 1, wxEXPAND | wxALL, border); + topSizer->Add(m_bottom_info_line, 0, wxEXPAND | wxALL, 2 * border); + topSizer->Add(m_edit_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 2 * border); + + this->SetMinSize(wxSize(80 * em_unit(), 30 * em_unit())); this->SetSizer(topSizer); topSizer->SetSizeHints(this); wxGetApp().UpdateDlgDarkUI(this); } +DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe) + : DPIDialog(mainframe, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + m_pr_technology(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology()) +{ +#if defined(__WXMSW__) + // ys_FIXME! temporary workaround for correct font scaling + // Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts, + // From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT + this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); +#endif // __WXMSW__ + + // Init bundles + + assert(wxGetApp().preset_bundle); + + m_preset_bundle_left = std::make_unique(*wxGetApp().preset_bundle); + m_preset_bundle_right = std::make_unique(*wxGetApp().preset_bundle); + + // Create UI items + + SetBackgroundColour(*wxWHITE); + + create_info_lines(); + + create_presets_sizer(); + + create_show_all_presets_chb(); + + create_tree(); + + create_edit_sizer(); + + complete_dialog_creation(); +} + void DiffPresetDialog::update_controls_visibility(Preset::Type type /* = Preset::TYPE_INVALID*/) { for (auto preset_combos : m_preset_combos) { @@ -1951,6 +2096,8 @@ void DiffPresetDialog::update_bundles_from_app() { *m_preset_bundle_left = *wxGetApp().preset_bundle; *m_preset_bundle_right = *wxGetApp().preset_bundle; + + m_pr_technology = m_preset_bundle_left.get()->printers.get_edited_preset().printer_technology(); } void DiffPresetDialog::show(Preset::Type type /* = Preset::TYPE_INVALID*/) @@ -1974,8 +2121,6 @@ void DiffPresetDialog::show(Preset::Type type /* = Preset::TYPE_INVALID*/) void DiffPresetDialog::update_presets(Preset::Type type) { - m_pr_technology = m_preset_bundle_left.get()->printers.get_edited_preset().printer_technology(); - update_bundles_from_app(); update_controls_visibility(type); @@ -1999,6 +2144,14 @@ void DiffPresetDialog::update_presets(Preset::Type type) update_tree(); } +void DiffPresetDialog::update_bottom_info(wxString bottom_info) +{ + const bool show_bottom_info = !m_tree->IsShown(); + if (show_bottom_info) + m_bottom_info_line->SetLabel(bottom_info); + m_bottom_info_line->Show(show_bottom_info); +} + void DiffPresetDialog::update_tree() { Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher(); @@ -2091,9 +2244,12 @@ void DiffPresetDialog::update_tree() bool tree_was_shown = m_tree->IsShown(); m_tree->Show(show_tree); - if (!show_tree) - m_bottom_info_line->SetLabel(bottom_info); - m_bottom_info_line->Show(!show_tree); + + bool can_transfer_options = m_view_type == Preset::TYPE_INVALID || get_left_preset_name(m_view_type) != get_right_preset_name(m_view_type); + m_edit_sizer->Show(show_tree && can_transfer_options); + m_buttons->Show(m_edit_sizer->IsShown(size_t(0)) && m_use_for_transfer->GetValue()); + + update_bottom_info(bottom_info); if (tree_was_shown == m_tree->IsShown()) Layout(); @@ -2110,7 +2266,9 @@ void DiffPresetDialog::on_dpi_changed(const wxRect&) { int em = em_unit(); - msw_buttons_rescale(this, em, { wxID_CANCEL}); + msw_buttons_rescale(this, em, {wxID_CANCEL}); + for (auto btn : {m_transfer_btn, m_cancel_btn}) + if (btn) btn->SetMinSize(UNSAVE_CHANGE_DIALOG_BUTTON_SIZE); const wxSize& size = wxSize(80 * em, 30 * em); SetMinSize(size); @@ -2140,6 +2298,7 @@ void DiffPresetDialog::on_sys_color_changed() preset_combos.equal_bmp->msw_rescale(); preset_combos.presets_right->msw_rescale(); } + // msw_rescale updates just icons, so use it m_tree->Rescale(); Refresh(); @@ -2203,6 +2362,25 @@ void DiffPresetDialog::update_compatibility(const std::string& preset_name, Pres } } +void DiffPresetDialog::button_event(Action act) +{ + Hide(); + if (act == Action::Transfer) + wxPostEvent(this, SimpleEvent(EVT_DIFF_DIALOG_TRANSFER)); +} + +std::string DiffPresetDialog::get_left_preset_name(Preset::Type type) +{ + PresetComboBox* cb = m_preset_combos[int(type - Preset::TYPE_PRINT)].presets_left; + return Preset::remove_suffix_modified(get_selection(cb)); +} + +std::string DiffPresetDialog::get_right_preset_name(Preset::Type type) +{ + PresetComboBox* cb = m_preset_combos[int(type - Preset::TYPE_PRINT)].presets_right; + return Preset::remove_suffix_modified(get_selection(cb)); +} + } } // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/UnsavedChangesDialog.hpp b/src/slic3r/GUI/UnsavedChangesDialog.hpp index b1bfbd0eb4c..c60eabe1932 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.hpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.hpp @@ -1,3 +1,7 @@ +///|/ Copyright (c) Prusa Research 2020 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv, David Kocík @kocikdav +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #ifndef slic3r_UnsavedChangesDialog_hpp_ #define slic3r_UnsavedChangesDialog_hpp_ @@ -17,6 +21,8 @@ class wxStaticText; namespace Slic3r { namespace GUI{ +wxDECLARE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent); + // ---------------------------------------------------------------------------- // ModelNode: a node inside DiffModel // ---------------------------------------------------------------------------- @@ -101,7 +107,7 @@ class ModelNode ModelNode* GetParent() { return m_parent; } ModelNodePtrArray& GetChildren() { return m_children; } ModelNode* GetNthChild(unsigned int n) { return m_children[n].get(); } - unsigned int GetChildCount() const { return m_children.size(); } + unsigned int GetChildCount() const { return (unsigned int)(m_children.size()); } void Append(std::unique_ptr child) { m_children.emplace_back(std::move(child)); } @@ -148,7 +154,7 @@ class DiffModel : public wxDataViewModel }; DiffModel(wxWindow* parent); - ~DiffModel(){}; + ~DiffModel() override = default; void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } @@ -228,6 +234,21 @@ class DiffViewCtrl : public wxDataViewCtrl std::vector selected_options(); }; +// Discard and Cancel buttons are always but next buttons are optional +enum ActionButtons { + TRANSFER = 1, + KEEP = 2, + SAVE = 4, + DONT_SAVE = 8, + REMEMBER_CHOISE = 0x10000 +}; + +enum class Action { + Undef, + Transfer, + Discard, + Save +}; //------------------------------------------ // UnsavedChangesDialog @@ -275,13 +296,6 @@ class UnsavedChangesDialog : public DPIDialog std::string m_app_config_key; - enum class Action { - Undef, - Transfer, // Or KEEP - Save, - Discard, - }; - static constexpr char ActTransfer[] = "transfer"; static constexpr char ActDiscard[] = "discard"; static constexpr char ActSave[] = "save"; @@ -314,20 +328,12 @@ class UnsavedChangesDialog : public DPIDialog std::string m_new_selected_preset_name; public: - // Discard and Cancel buttons are always but next buttons are optional - enum ActionButtons { - TRANSFER = 1, - KEEP = 2, - SAVE = 4, - DONT_SAVE = 8, - REMEMBER_CHOISE = 0x10000 - }; // show unsaved changes when preset is switching UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, bool no_transfer = false); // show unsaved changes for all another cases UnsavedChangesDialog(const wxString& caption, const wxString& header, const std::string& app_config_key, int act_buttons); - ~UnsavedChangesDialog(){}; + ~UnsavedChangesDialog() override = default; int ShowModal(); @@ -394,7 +400,7 @@ class FullCompareDialog : public wxDialog public: FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& new_value, const wxString& old_value_header, const wxString& new_value_header); - ~FullCompareDialog(){}; + ~FullCompareDialog() override = default; }; @@ -404,19 +410,36 @@ class FullCompareDialog : public wxDialog class DiffPresetDialog : public DPIDialog { DiffViewCtrl* m_tree { nullptr }; + wxBoxSizer* m_presets_sizer { nullptr }; wxStaticText* m_top_info_line { nullptr }; wxStaticText* m_bottom_info_line { nullptr }; wxCheckBox* m_show_all_presets { nullptr }; + wxCheckBox* m_use_for_transfer { nullptr }; + Button* m_transfer_btn { nullptr }; + Button* m_cancel_btn { nullptr }; + wxBoxSizer* m_buttons { nullptr }; + wxBoxSizer* m_edit_sizer { nullptr }; Preset::Type m_view_type { Preset::TYPE_INVALID }; PrinterTechnology m_pr_technology; std::unique_ptr m_preset_bundle_left; std::unique_ptr m_preset_bundle_right; - void update_tree(); - void update_bundles_from_app(); - void update_controls_visibility(Preset::Type type = Preset::TYPE_INVALID); - void update_compatibility(const std::string& preset_name, Preset::Type type, PresetBundle* preset_bundle); + void create_buttons(); + void create_edit_sizer(); + void complete_dialog_creation(); + void create_presets_sizer(); + void create_info_lines(); + void create_tree(); + void create_show_all_presets_chb(); + + void update_bottom_info(wxString bottom_info = ""); + void update_tree(); + void update_bundles_from_app(); + void update_controls_visibility(Preset::Type type = Preset::TYPE_INVALID); + void update_compatibility(const std::string& preset_name, Preset::Type type, PresetBundle* preset_bundle); + + void button_event(Action act); struct DiffPresets { @@ -428,11 +451,21 @@ class DiffPresetDialog : public DPIDialog std::vector m_preset_combos; public: - DiffPresetDialog(MainFrame* mainframe); - ~DiffPresetDialog(){}; + DiffPresetDialog(MainFrame*mainframe); + ~DiffPresetDialog() override = default; + + void show(Preset::Type type = Preset::TYPE_INVALID); + void update_presets(Preset::Type type = Preset::TYPE_INVALID); + + Preset::Type view_type() const { return m_view_type; } + PrinterTechnology printer_technology() const { return m_pr_technology; } + + std::string get_left_preset_name(Preset::Type type); + std::string get_right_preset_name(Preset::Type type); + + std::vector get_selected_options(Preset::Type type) const { return std::move(m_tree->options(type, true)); } - void show(Preset::Type type = Preset::TYPE_INVALID); - void update_presets(Preset::Type type = Preset::TYPE_INVALID); + std::array types_list() const; protected: void on_dpi_changed(const wxRect& suggested_rect) override; diff --git a/src/slic3r/GUI/WebGuideDialog.cpp b/src/slic3r/GUI/WebGuideDialog.cpp index 8e71a0ecf1b..2ca91bd3b2c 100644 --- a/src/slic3r/GUI/WebGuideDialog.cpp +++ b/src/slic3r/GUI/WebGuideDialog.cpp @@ -771,7 +771,7 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle check_unsaved_preset_changes = (enabled_vendors != old_enabled_vendors) || (enabled_filaments != old_enabled_filaments); wxString header = _L("The configuration package is changed in previous Config Guide"); wxString caption = _L("Configuration package changed"); - int act_btns = UnsavedChangesDialog::ActionButtons::KEEP|UnsavedChangesDialog::ActionButtons::SAVE; + int act_btns = ActionButtons::KEEP|ActionButtons::SAVE; if (check_unsaved_preset_changes && !wxGetApp().check_and_keep_current_preset_changes(caption, header, act_btns, &apply_keeped_changes))