From e774d25f7aff7806117eed49494e4abd1a8d588e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 8 Dec 2023 11:32:26 +0100 Subject: [PATCH] Implemented UI to show a state of printers in PrusaConnect --- src/libslic3r/Preset.cpp | 6 ++ src/libslic3r/Preset.hpp | 2 + src/slic3r/GUI/GUI_App.cpp | 74 ++++++++-------------- src/slic3r/GUI/GUI_App.hpp | 3 +- src/slic3r/GUI/Plater.cpp | 2 + src/slic3r/GUI/PresetComboBoxes.cpp | 96 +++++++++++++++++++++++++++++ src/slic3r/GUI/PresetComboBoxes.hpp | 2 + src/slic3r/GUI/Sidebar.cpp | 10 +++ src/slic3r/GUI/Sidebar.hpp | 1 + src/slic3r/GUI/UserAccount.hpp | 31 ++++++++-- 10 files changed, 170 insertions(+), 57 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index bc428a73f2..3f26b3f35c 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1211,6 +1211,12 @@ Preset* PresetCollection::find_preset(const std::string &name, bool first_visibl first_visible_if_not_found ? &this->first_visible() : nullptr; } +size_t PresetCollection::get_preset_idx_by_name(const std::string name) const +{ + auto it = this->find_preset_internal(name); + return it != m_presets.end() ? it - m_presets.begin() : size_t(-1); +} + // Return index of the first visible preset. Certainly at least the '- default -' preset shall be visible. size_t PresetCollection::first_visible_idx() const { diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 0594bb672e..13f1185031 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -437,6 +437,8 @@ public: const Preset* find_preset(const std::string &name, bool first_visible_if_not_found = false, bool respect_active_preset = true) const { return const_cast(this)->find_preset(name, first_visible_if_not_found, respect_active_preset); } + size_t get_preset_idx_by_name(const std::string preset_name) const; + size_t first_visible_idx() const; // Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible. // If one of the prefered_alternates is compatible, select it. diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index db0eeb7bbd..7880d07606 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3676,71 +3676,45 @@ void GUI_App::open_wifi_config_dialog(bool forced, const wxString& drive_path/* m_wifi_config_dialog_shown = false; } -void GUI_App::select_printer_with_load(Preset* prst, const std::string& preset_name, const std::string& model_name, const std::string& nozzle_name, const std::string& nozzle) +bool GUI_App::select_printer_from_connect(const Preset* preset) { - assert(prst); - if (prst->is_visible) - bool suc = get_tab(Preset::Type::TYPE_PRINTER)->select_preset(preset_name); - else { - AppConfig appconfig_new(AppConfig::EAppMode::Editor); - appconfig_new.set_vendors(*app_config); - prst->vendor->models; - if (auto it = std::find_if(prst->vendor->models.begin(), prst->vendor->models.end(), [model_name](const VendorProfile::PrinterModel& a) { - if (a.name == model_name) - return true; - else - return false; - }); it != prst->vendor->models.end()) - { - appconfig_new.set_variant("PrusaResearch", it->id, nozzle, true); - app_config->set_vendors(appconfig_new); + assert(preset); - preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, - { it->id, nozzle, "", "" }); - load_current_presets(); - } + bool is_installed{ false }; + + if (!preset->is_visible) { + size_t preset_id = preset_bundle->printers.get_preset_idx_by_name(preset->name); + assert(preset_id != size_t(-1)); + preset_bundle->printers.select_preset(preset_id); + is_installed = true; } + + get_tab(Preset::Type::TYPE_PRINTER)->select_preset(preset->name); + return is_installed; } void GUI_App::handle_web_request(std::string cmd) { BOOST_LOG_TRIVIAL(error) << "Handling web request: " << cmd; // return to plater - //this->mainframe->select_tab(size_t(0)); + this->mainframe->select_tab(size_t(0)); // parse message std::string model_name = plater()->get_user_account()->get_model_from_json(cmd); std::string nozzle = plater()->get_user_account()->get_nozzle_from_json(cmd); - std::string nozzle_name = nozzle.empty() ? "" : (nozzle +" nozzle"); assert(!model_name.empty()); - assert(!nozzle_name.empty()); - if (model_name.empty() && nozzle_name.empty()) + if (model_name.empty()) return; + // select printer - std::string preset_name = nozzle.empty() ? model_name : format("%1% %2%",model_name, nozzle_name); - Preset* prst = preset_bundle->printers.find_preset(preset_name, false); - if (!prst) { - model_name = std::string(*preset_bundle->printers.get_preset_name_renamed(model_name)); - preset_name = nozzle.empty() ? model_name : format("%1% %2%", model_name, nozzle_name); - prst = preset_bundle->printers.find_preset(preset_name, false); - } - if (!prst) { - preset_name = model_name; - prst = preset_bundle->printers.find_preset(preset_name, false); - } - if (prst) { - select_printer_with_load(prst, preset_name, model_name, nozzle_name, nozzle); - // notification - std::string out = GUI::format("Select Printer:\n%1%", preset_name); - this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::PrusaAuthUserID); - this->plater()->get_notification_manager()->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out); - } else { - // notification - std::string out = GUI::format("Printer not found:\n%1%", preset_name); - this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::PrusaAuthUserID); - this->plater()->get_notification_manager()->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out); - } - - + const Preset* preset = preset_bundle->printers.find_system_preset_by_model_and_variant(model_name, nozzle); + bool is_installed = preset && select_printer_from_connect(preset); + // notification + std::string out = preset ? + (is_installed ? GUI::format(_L("Installed and Select Printer:\n%1%"), preset->name) : + GUI::format(_L("Select Printer:\n%1%"), preset->name) ): + GUI::format(_L("Printer not found:\n%1%"), model_name); + this->plater()->get_notification_manager()->close_notification_of_type(NotificationType::PrusaAuthUserID); + this->plater()->get_notification_manager()->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out); } } // GUI diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 28963c9dea..007ba7f8d9 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -413,7 +413,8 @@ public: void request_user_logout() {} int request_user_unbind(std::string dev_id) { return 0; } void handle_web_request(std::string cmd); - void select_printer_with_load(Preset* prst, const std::string& preset_name, const std::string& printer_name, const std::string& nozzle_name, const std::string& nozzle ); + // return true if preset vas invisible and we have to installed it to make it selectable + bool select_printer_from_connect(const Preset* printer_preset); void handle_script_message(std::string msg) {} void request_model_download(std::string import_json) {} void download_project(std::string project_id) {} diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 1c2ff8e7de..94926e7643 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -913,6 +913,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) std::string out = GUI::format( "Printers in your PrusaConnect team:\n%1%", text); this->notification_manager->close_notification_of_type(NotificationType::PrusaAuthUserID); this->notification_manager->push_notification(NotificationType::PrusaAuthUserID, NotificationManager::NotificationLevel::ImportantNotificationLevel, out); + + sidebar->update_printer_presets_combobox(); }); wxGetApp().other_instance_message_handler()->init(this->q); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index c40978b03d..875c6ad778 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -44,6 +45,7 @@ #include "BitmapCache.hpp" #include "PhysicalPrinterDialog.hpp" #include "MsgDialog.hpp" +#include "UserAccount.hpp" #include "Widgets/ComboBox.hpp" @@ -618,6 +620,12 @@ bool PresetComboBox::selection_is_changed_according_to_physical_printers() // *** PlaterPresetComboBox *** // --------------------------------- +static bool is_active_connect() +{ + auto user_account = wxGetApp().plater()->get_user_account(); + return user_account && user_account->is_logged(); +} + PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset_type) : PresetComboBox(parent, preset_type, wxSize(15 * wxGetApp().em_unit(), -1)) { @@ -657,6 +665,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset else switch_to_tab(); }); + + if (m_type == Preset::TYPE_PRINTER) + connect_info = new wxGenericStaticText(parent, wxID_ANY, "Info about Connect for printer preset"); } PlaterPresetComboBox::~PlaterPresetComboBox() @@ -832,6 +843,83 @@ wxString PlaterPresetComboBox::get_preset_name(const Preset& preset) return from_u8(name + suffix(preset)); } + +struct PrinterStatesCount +{ + size_t offline_cnt { 0 }; + size_t busy_cnt { 0 }; + size_t available_cnt { 0 }; + size_t total { 0 }; +}; + +static PrinterStatesCount get_printe_states_count(const std::vector& states) +{ + PrinterStatesCount states_cnt; + + for (size_t i = 0; i < states.size(); i++) { + if (states[i] == 0) + continue; + + ConnectPrinterState state = static_cast(i); + + if (state == ConnectPrinterState::CONNECT_PRINTER_OFFLINE) + states_cnt.offline_cnt += states[i]; + else if (state == ConnectPrinterState::CONNECT_PRINTER_PAUSED || + state == ConnectPrinterState::CONNECT_PRINTER_STOPED || + state == ConnectPrinterState::CONNECT_PRINTER_PRINTING) + states_cnt.busy_cnt += states[i]; + else + states_cnt.available_cnt += states[i]; + } + states_cnt.total = states_cnt.offline_cnt + states_cnt.busy_cnt + states_cnt.available_cnt; + + return states_cnt; +} + +static std::string get_connect_state_suffix_for_printer(const Preset& printer_preset) +{ + // process real data from Connect + if (auto printer_state_map = wxGetApp().plater()->get_user_account()->get_printer_state_map(); + !printer_state_map.empty()) { + + for (const auto& [printer_model_id, states] : printer_state_map) { + if (printer_model_id == printer_preset.config.opt_string("printer_model")) { + + PrinterStatesCount states_cnt = get_printe_states_count(states); + + if (states_cnt.available_cnt > 0) + return "_available"; + if (states_cnt.busy_cnt > 0) + return "_busy"; + return "_offline"; + } + } + } + + return ""; +} + +static wxString get_connect_info_line(const Preset& printer_preset) +{ + if (auto printer_state_map = wxGetApp().plater()->get_user_account()->get_printer_state_map(); + !printer_state_map.empty()) { + + for (const auto& [printer_model_id, states] : printer_state_map) { + if (printer_model_id == printer_preset.config.opt_string("printer_model")) { + + PrinterStatesCount states_cnt = get_printe_states_count(states); + + return format_wxstr(_L("Available: %1%, Offline: %2%, Busy: %3%. Total: %4% printers"), + format("%1%" , states_cnt.available_cnt), + format("%1%" , states_cnt.offline_cnt), + format("%1%", states_cnt.busy_cnt), + format("%1%", states_cnt.total)); + } + } + } + return " "; // to correct update of strinh height don't use empty string +} + // Only the compatible presets are shown. // If an incompatible preset is selected, it is shown as well. void PlaterPresetComboBox::update() @@ -904,6 +992,12 @@ void PlaterPresetComboBox::update() std::string bitmap_key, filament_rgb, extruder_rgb, material_rgb; std::string bitmap_type_name = bitmap_key = m_type == Preset::TYPE_PRINTER && preset.printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name; + if (m_type == Preset::TYPE_PRINTER) { + bitmap_type_name = bitmap_key += get_connect_state_suffix_for_printer(preset); + if (is_selected) + connect_info->SetLabelMarkup(get_connect_info_line(preset)); + } + bool single_bar = false; if (m_type == Preset::TYPE_FILAMENT) { @@ -1032,6 +1126,8 @@ void PlaterPresetComboBox::update() validate_selection(data.selected); } } + + connect_info->Show(is_active_connect()); } if (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_FILAMENT || m_type == Preset::TYPE_SLA_MATERIAL) { diff --git a/src/slic3r/GUI/PresetComboBoxes.hpp b/src/slic3r/GUI/PresetComboBoxes.hpp index 421d96d481..5a9821b7de 100644 --- a/src/slic3r/GUI/PresetComboBoxes.hpp +++ b/src/slic3r/GUI/PresetComboBoxes.hpp @@ -16,6 +16,7 @@ class wxString; class wxTextCtrl; class wxStaticText; +class wxGenericStaticText; class ScalableButton; class wxBoxSizer; class wxComboBox; @@ -153,6 +154,7 @@ public: ~PlaterPresetComboBox(); ScalableButton* edit_btn { nullptr }; + wxGenericStaticText* connect_info { nullptr }; void set_extruder_idx(const int extr_idx) { m_extruder_idx = extr_idx; } int get_extruder_idx() const { return m_extruder_idx; } diff --git a/src/slic3r/GUI/Sidebar.cpp b/src/slic3r/GUI/Sidebar.cpp index 11eabb7f0a..87d026794d 100644 --- a/src/slic3r/GUI/Sidebar.cpp +++ b/src/slic3r/GUI/Sidebar.cpp @@ -32,6 +32,7 @@ #include #include #include +#include "wx/generic/stattextg.h" #ifdef _WIN32 #include #include @@ -381,6 +382,9 @@ Sidebar::Sidebar(Plater *parent) wxBOTTOM, 1); (void)margin_5; // supress unused capture warning #endif // __WXGTK3__ + if ((*combo)->connect_info) + sizer_presets->Add((*combo)->connect_info, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, + int(0.3 * wxGetApp().em_unit())); } else { sizer_filaments->Add(combo_and_btn_sizer, 0, wxEXPAND | #ifdef __WXGTK3__ @@ -603,6 +607,12 @@ void Sidebar::update_all_preset_comboboxes() } } +void Sidebar::update_printer_presets_combobox() +{ + m_combo_printer->update(); + Layout(); +} + void Sidebar::update_presets(Preset::Type preset_type) { PresetBundle &preset_bundle = *wxGetApp().preset_bundle; diff --git a/src/slic3r/GUI/Sidebar.hpp b/src/slic3r/GUI/Sidebar.hpp index 826a2015ed..2ec2af653f 100644 --- a/src/slic3r/GUI/Sidebar.hpp +++ b/src/slic3r/GUI/Sidebar.hpp @@ -133,6 +133,7 @@ public: void update_objects_list_extruder_column(size_t extruders_count); void update_presets(Preset::Type preset_type); void update_mode_markers(); + void update_printer_presets_combobox(); void msw_rescale(); void sys_color_changed(); diff --git a/src/slic3r/GUI/UserAccount.hpp b/src/slic3r/GUI/UserAccount.hpp index a598f8257f..ae5b1f9e14 100644 --- a/src/slic3r/GUI/UserAccount.hpp +++ b/src/slic3r/GUI/UserAccount.hpp @@ -12,9 +12,12 @@ namespace GUI{ enum class ConnectPrinterState { CONNECT_PRINTER_OFFLINE, - CONNECT_PRINTER_IDLE, CONNECT_PRINTER_PRINTING, + CONNECT_PRINTER_PAUSED,//? + CONNECT_PRINTER_STOPED,//? + CONNECT_PRINTER_IDLE, CONNECT_PRINTER_FINISHED, + CONNECT_PRINTER_READY, //? CONNECT_PRINTER_STATE_COUNT }; @@ -61,17 +64,33 @@ private: ConnectPrinterStateMap m_printer_map; const std::map printer_type_and_name_table = { - {"1.3.0", "Original Prusa i3 MK3"}, - {"1.3.1", "Original Prusa i3 MK3S & MK3S+"}, - {"1.4.0", "Original Prusa MK4"}, - {"2.1.0", "Original Prusa MINI & MINI+"}, + {"1.3.0", "MK3" }, + {"1.3.1", "MK3S" }, + {"1.4.0", "MK4" }, + {"2.1.0", "MINI" }, + // ysFIXME : needs to add Connect ids for next printers + {"0.0.0", "MK4IS" }, + {"0.0.0", "MK3SMMU2S" }, + {"0.0.0", "MK3MMU2" }, + {"0.0.0", "XL" }, + {"0.0.0", "MK2.5S" }, + {"0.0.0", "MK2.5" }, + {"0.0.0", "MK2.5SMMU2S" }, + {"0.0.0", "MK2.5MMU2" }, + {"0.0.0", "MK2S" }, + {"0.0.0", "MK2SMM" }, + {"0.0.0", "SL1" }, + {"0.0.0", "SL1S" }, }; const std::map printer_state_table = { {"OFFLINE" , ConnectPrinterState::CONNECT_PRINTER_OFFLINE}, - {"IDLE" , ConnectPrinterState::CONNECT_PRINTER_IDLE}, {"PRINTING" , ConnectPrinterState::CONNECT_PRINTER_PRINTING}, + {"PAUSED" , ConnectPrinterState::CONNECT_PRINTER_PAUSED}, + {"STOPED" , ConnectPrinterState::CONNECT_PRINTER_STOPED}, + {"IDLE" , ConnectPrinterState::CONNECT_PRINTER_IDLE}, {"FINISHED" , ConnectPrinterState::CONNECT_PRINTER_FINISHED}, + {"READY" , ConnectPrinterState::CONNECT_PRINTER_READY}, }; }; }} // namespace slic3r::GUI