1 #ifndef slic3r_ConfigWizard_private_hpp_ 2 #define slic3r_ConfigWizard_private_hpp_ 3 4 #include "ConfigWizard.hpp" 5 6 #include <vector> 7 #include <set> 8 #include <unordered_map> 9 #include <functional> 10 #include <boost/filesystem.hpp> 11 #include <boost/log/trivial.hpp> 12 13 #include <wx/sizer.h> 14 #include <wx/panel.h> 15 #include <wx/button.h> 16 #include <wx/choice.h> 17 #include <wx/spinctrl.h> 18 #include <wx/textctrl.h> 19 #include <wx/listbox.h> 20 #include <wx/checklst.h> 21 #include <wx/radiobut.h> 22 #include <wx/html/htmlwin.h> 23 24 #include "libslic3r/PrintConfig.hpp" 25 #include "libslic3r/PresetBundle.hpp" 26 #include "slic3r/Utils/PresetUpdater.hpp" 27 #include "BedShapeDialog.hpp" 28 #include "GUI.hpp" 29 #include "wxExtensions.hpp" 30 31 32 namespace fs = boost::filesystem; 33 34 namespace Slic3r { 35 namespace GUI { 36 37 enum { 38 WRAP_WIDTH = 500, 39 MODEL_MIN_WRAP = 150, 40 41 DIALOG_MARGIN = 15, 42 INDEX_MARGIN = 40, 43 BTN_SPACING = 10, 44 INDENT_SPACING = 30, 45 VERTICAL_SPACING = 10, 46 47 MAX_COLS = 4, 48 ROW_SPACING = 75, 49 }; 50 51 52 53 // Configuration data structures extensions needed for the wizard 54 55 enum Technology { 56 // Bitflag equivalent of PrinterTechnology 57 T_FFF = 0x1, 58 T_SLA = 0x2, 59 T_ANY = ~0, 60 }; 61 62 struct Bundle 63 { 64 std::unique_ptr<PresetBundle> preset_bundle; 65 VendorProfile* vendor_profile{ nullptr }; 66 bool is_in_resources{ false }; 67 bool is_prusa_bundle{ false }; 68 69 Bundle() = default; 70 Bundle(Bundle&& other); 71 72 // Returns false if not loaded. Reason for that is logged as boost::log error. 73 bool load(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false); 74 vendor_idSlic3r::GUI::Bundle75 const std::string& vendor_id() const { return vendor_profile->id; } 76 }; 77 78 struct BundleMap : std::unordered_map<std::string /* = vendor ID */, Bundle> 79 { 80 static BundleMap load(); 81 82 Bundle& prusa_bundle(); 83 const Bundle& prusa_bundle() const; 84 }; 85 86 struct Materials 87 { 88 Technology technology; 89 // use vector for the presets to purpose of save of presets sorting in the bundle 90 std::vector<const Preset*> presets; 91 // String is alias of material, size_t number of compatible counters 92 std::vector<std::pair<std::string, size_t>> compatibility_counter; 93 std::set<std::string> types; 94 std::set<const Preset*> printers; 95 MaterialsSlic3r::GUI::Materials96 Materials(Technology technology) : technology(technology) {} 97 98 void push(const Preset *preset); 99 void add_printer(const Preset* preset); 100 void clear(); containtsSlic3r::GUI::Materials101 bool containts(const Preset *preset) const { 102 //return std::find(presets.begin(), presets.end(), preset) != presets.end(); 103 return std::find_if(presets.begin(), presets.end(), 104 [preset](const Preset* element) { return element == preset; }) != presets.end(); 105 106 } 107 get_omnipresentSlic3r::GUI::Materials108 bool get_omnipresent(const Preset* preset) { 109 return get_printer_counter(preset) == printers.size(); 110 } 111 get_presets_by_aliasSlic3r::GUI::Materials112 const std::vector<const Preset*> get_presets_by_alias(const std::string name) { 113 std::vector<const Preset*> ret_vec; 114 for (auto it = presets.begin(); it != presets.end(); ++it) { 115 if ((*it)->alias == name) 116 ret_vec.push_back((*it)); 117 } 118 return ret_vec; 119 } 120 121 122 get_printer_counterSlic3r::GUI::Materials123 size_t get_printer_counter(const Preset* preset) { 124 for (auto it : compatibility_counter) { 125 if (it.first == preset->alias) 126 return it.second; 127 } 128 return 0; 129 } 130 131 const std::string& appconfig_section() const; 132 const std::string& get_type(const Preset *preset) const; 133 const std::string& get_vendor(const Preset *preset) const; 134 filter_presetsSlic3r::GUI::Materials135 template<class F> void filter_presets(const Preset* printer, const std::string& type, const std::string& vendor, F cb) { 136 for (auto preset : presets) { 137 const Preset& prst = *(preset); 138 const Preset& prntr = *printer; 139 if ((printer == nullptr || is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor))) && 140 (type.empty() || get_type(preset) == type) && 141 (vendor.empty() || get_vendor(preset) == vendor)) { 142 143 cb(preset); 144 } 145 } 146 } 147 148 static const std::string UNKNOWN; 149 static const std::string& get_filament_type(const Preset *preset); 150 static const std::string& get_filament_vendor(const Preset *preset); 151 static const std::string& get_material_type(const Preset *preset); 152 static const std::string& get_material_vendor(const Preset *preset); 153 }; 154 155 156 struct PrinterPickerEvent; 157 158 // GUI elements 159 160 typedef std::function<bool(const VendorProfile::PrinterModel&)> ModelFilter; 161 162 struct PrinterPicker: wxPanel 163 { 164 struct Checkbox : wxCheckBox 165 { CheckboxSlic3r::GUI::PrinterPicker::Checkbox166 Checkbox(wxWindow *parent, const wxString &label, const std::string &model, const std::string &variant) : 167 wxCheckBox(parent, wxID_ANY, label), 168 model(model), 169 variant(variant) 170 {} 171 172 std::string model; 173 std::string variant; 174 }; 175 176 const std::string vendor_id; 177 std::vector<Checkbox*> cboxes; 178 std::vector<Checkbox*> cboxes_alt; 179 180 PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig, const ModelFilter &filter); 181 PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxString title, size_t max_cols, const AppConfig &appconfig); 182 183 void select_all(bool select, bool alternates = false); 184 void select_one(size_t i, bool select); 185 bool any_selected() const; 186 std::set<std::string> get_selected_models() const ; 187 get_widthSlic3r::GUI::PrinterPicker188 int get_width() const { return width; } get_button_indexesSlic3r::GUI::PrinterPicker189 const std::vector<int>& get_button_indexes() { return m_button_indexes; } 190 191 static const std::string PRINTER_PLACEHOLDER; 192 private: 193 int width; 194 std::vector<int> m_button_indexes; 195 196 void on_checkbox(const Checkbox *cbox, bool checked); 197 }; 198 199 struct ConfigWizardPage: wxPanel 200 { 201 ConfigWizard *parent; 202 const wxString shortname; 203 wxBoxSizer *content; 204 const unsigned indent; 205 206 ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname, unsigned indent = 0); 207 virtual ~ConfigWizardPage(); 208 209 template<class T> appendSlic3r::GUI::ConfigWizardPage210 T* append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) 211 { 212 content->Add(thing, proportion, flag, border); 213 return thing; 214 } 215 216 wxStaticText* append_text(wxString text); 217 void append_spacer(int space); 218 wizard_pSlic3r::GUI::ConfigWizardPage219 ConfigWizard::priv *wizard_p() const { return parent->p.get(); } 220 apply_custom_configSlic3r::GUI::ConfigWizardPage221 virtual void apply_custom_config(DynamicPrintConfig &config) {} set_run_reasonSlic3r::GUI::ConfigWizardPage222 virtual void set_run_reason(ConfigWizard::RunReason run_reason) {} on_activateSlic3r::GUI::ConfigWizardPage223 virtual void on_activate() {} 224 }; 225 226 struct PageWelcome: ConfigWizardPage 227 { 228 wxStaticText *welcome_text; 229 wxCheckBox *cbox_reset; 230 231 PageWelcome(ConfigWizard *parent); 232 reset_user_profileSlic3r::GUI::PageWelcome233 bool reset_user_profile() const { return cbox_reset != nullptr ? cbox_reset->GetValue() : false; } 234 235 virtual void set_run_reason(ConfigWizard::RunReason run_reason) override; 236 }; 237 238 struct PagePrinters: ConfigWizardPage 239 { 240 std::vector<PrinterPicker *> printer_pickers; 241 Technology technology; 242 bool install; 243 244 PagePrinters(ConfigWizard *parent, 245 wxString title, 246 wxString shortname, 247 const VendorProfile &vendor, 248 unsigned indent, Technology technology); 249 250 void select_all(bool select, bool alternates = false); 251 int get_width() const; 252 bool any_selected() const; 253 std::set<std::string> get_selected_models(); 254 get_vendor_idSlic3r::GUI::PagePrinters255 std::string get_vendor_id() const { return printer_pickers.empty() ? "" : printer_pickers[0]->vendor_id; } 256 257 virtual void set_run_reason(ConfigWizard::RunReason run_reason) override; 258 }; 259 260 // Here we extend wxListBox and wxCheckListBox 261 // to make the client data API much easier to use. 262 template<class T, class D> struct DataList : public T 263 { DataListSlic3r::GUI::DataList264 DataList(wxWindow *parent) : T(parent, wxID_ANY) {} DataListSlic3r::GUI::DataList265 DataList(wxWindow* parent, int style) : T(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, style) {} 266 267 // Note: We're _not_ using wxLB_SORT here because it doesn't do the right thing, 268 // eg. "ABS" is sorted before "(All)" 269 appendSlic3r::GUI::DataList270 int append(const std::string &label, const D *data) { 271 void *ptr = reinterpret_cast<void*>(const_cast<D*>(data)); 272 return this->Append(from_u8(label), ptr); 273 } 274 appendSlic3r::GUI::DataList275 int append(const wxString &label, const D *data) { 276 void *ptr = reinterpret_cast<void*>(const_cast<D*>(data)); 277 return this->Append(label, ptr); 278 } 279 get_dataSlic3r::GUI::DataList280 const D& get_data(int n) { 281 return *reinterpret_cast<const D*>(this->GetClientData(n)); 282 } 283 findSlic3r::GUI::DataList284 int find(const D &data) { 285 for (unsigned i = 0; i < this->GetCount(); i++) { 286 if (get_data(i) == data) { return i; } 287 } 288 289 return wxNOT_FOUND; 290 } 291 sizeSlic3r::GUI::DataList292 int size() { return this->GetCount(); } 293 on_mouse_moveSlic3r::GUI::DataList294 void on_mouse_move(const wxPoint& position) { 295 int item = T::HitTest(position); 296 297 if(item == wxHitTest::wxHT_WINDOW_INSIDE) 298 BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_INSIDE"; 299 else if (item == wxHitTest::wxHT_WINDOW_OUTSIDE) 300 BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_OUTSIDE"; 301 else if(item == wxHitTest::wxHT_WINDOW_CORNER) 302 BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_CORNER"; 303 else if (item == wxHitTest::wxHT_WINDOW_VERT_SCROLLBAR) 304 BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_VERT_SCROLLBAR"; 305 else if (item == wxHitTest::wxHT_NOWHERE) 306 BOOST_LOG_TRIVIAL(error) << "hit test wxHT_NOWHERE"; 307 else if (item == wxHitTest::wxHT_MAX) 308 BOOST_LOG_TRIVIAL(error) << "hit test wxHT_MAX"; 309 else 310 BOOST_LOG_TRIVIAL(error) << "hit test: " << item; 311 } 312 }; 313 314 typedef DataList<wxListBox, std::string> StringList; 315 typedef DataList<wxCheckListBox, std::string> PresetList; 316 317 struct ProfilePrintData 318 { 319 std::reference_wrapper<const std::string> name; 320 bool omnipresent; 321 bool checked; ProfilePrintDataSlic3r::GUI::ProfilePrintData322 ProfilePrintData(const std::string& n, bool o, bool c) : name(n), omnipresent(o), checked(c) {} 323 }; 324 325 struct PageMaterials: ConfigWizardPage 326 { 327 Materials *materials; 328 StringList *list_printer, *list_type, *list_vendor; 329 PresetList *list_profile; 330 int sel_printer_count_prev, sel_printer_item_prev, sel_type_prev, sel_vendor_prev; 331 bool presets_loaded; 332 333 wxFlexGridSizer *grid; 334 wxHtmlWindow* html_window; 335 336 int compatible_printers_width = { 100 }; 337 std::string empty_printers_label; 338 bool first_paint = { false }; 339 static const std::string EMPTY; 340 int last_hovered_item = { -1 } ; 341 342 PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name); 343 344 void reload_presets(); 345 void update_lists(int sel1, int sel2, int sel3); 346 void on_material_highlighted(int sel_material); 347 void on_material_hovered(int sel_material); 348 void select_material(int i); 349 void select_all(bool select); 350 void clear(); 351 void set_compatible_printers_html_window(const std::vector<std::string>& printer_names, bool all_printers = false); 352 void clear_compatible_printers_label(); 353 354 void sort_list_data(StringList* list, bool add_All_item, bool material_type_ordering); 355 void sort_list_data(PresetList* list, const std::vector<ProfilePrintData>& data); 356 357 void on_paint(); 358 void on_mouse_move_on_profiles(wxMouseEvent& evt); 359 void on_mouse_enter_profiles(wxMouseEvent& evt); 360 void on_mouse_leave_profiles(wxMouseEvent& evt); 361 virtual void on_activate() override; 362 }; 363 364 struct PageCustom: ConfigWizardPage 365 { 366 PageCustom(ConfigWizard *parent); 367 custom_wantedSlic3r::GUI::PageCustom368 bool custom_wanted() const { return cb_custom->GetValue(); } profile_nameSlic3r::GUI::PageCustom369 std::string profile_name() const { return into_u8(tc_profile_name->GetValue()); } 370 371 private: 372 static const char* default_profile_name; 373 374 wxCheckBox *cb_custom; 375 wxTextCtrl *tc_profile_name; 376 wxString profile_name_prev; 377 378 }; 379 380 struct PageUpdate: ConfigWizardPage 381 { 382 bool version_check; 383 bool preset_update; 384 385 PageUpdate(ConfigWizard *parent); 386 }; 387 388 struct PageReloadFromDisk : ConfigWizardPage 389 { 390 bool full_pathnames; 391 392 PageReloadFromDisk(ConfigWizard* parent); 393 }; 394 395 #if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN 396 #ifdef _WIN32 397 struct PageFilesAssociation : ConfigWizardPage 398 { 399 private: 400 wxCheckBox* cb_3mf{ nullptr }; 401 wxCheckBox* cb_stl{ nullptr }; 402 // wxCheckBox* cb_gcode; 403 404 public: 405 PageFilesAssociation(ConfigWizard* parent); 406 associate_3mfSlic3r::GUI::PageFilesAssociation407 bool associate_3mf() const { return cb_3mf->IsChecked(); } associate_stlSlic3r::GUI::PageFilesAssociation408 bool associate_stl() const { return cb_stl->IsChecked(); } 409 // bool associate_gcode() const { return cb_gcode->IsChecked(); } 410 }; 411 #endif // _WIN32 412 #endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN 413 414 struct PageMode: ConfigWizardPage 415 { 416 wxRadioButton *radio_simple; 417 wxRadioButton *radio_advanced; 418 wxRadioButton *radio_expert; 419 420 wxCheckBox *check_inch; 421 422 PageMode(ConfigWizard *parent); 423 424 void serialize_mode(AppConfig *app_config) const; 425 426 virtual void on_activate(); 427 }; 428 429 struct PageVendors: ConfigWizardPage 430 { 431 PageVendors(ConfigWizard *parent); 432 }; 433 434 struct PageFirmware: ConfigWizardPage 435 { 436 const ConfigOptionDef &gcode_opt; 437 wxChoice *gcode_picker; 438 439 PageFirmware(ConfigWizard *parent); 440 virtual void apply_custom_config(DynamicPrintConfig &config); 441 }; 442 443 struct PageBedShape: ConfigWizardPage 444 { 445 BedShapePanel *shape_panel; 446 447 PageBedShape(ConfigWizard *parent); 448 virtual void apply_custom_config(DynamicPrintConfig &config); 449 }; 450 451 struct PageDiameters: ConfigWizardPage 452 { 453 wxSpinCtrlDouble *spin_nozzle; 454 wxSpinCtrlDouble *spin_filam; 455 456 PageDiameters(ConfigWizard *parent); 457 virtual void apply_custom_config(DynamicPrintConfig &config); 458 }; 459 460 struct PageTemperatures: ConfigWizardPage 461 { 462 wxSpinCtrlDouble *spin_extr; 463 wxSpinCtrlDouble *spin_bed; 464 465 PageTemperatures(ConfigWizard *parent); 466 virtual void apply_custom_config(DynamicPrintConfig &config); 467 }; 468 469 // hypothetically, each vendor can has printers both of technologies (FFF and SLA) 470 typedef std::map<std::string /* = vendor ID */, 471 std::pair<PagePrinters* /* = FFF page */, 472 PagePrinters* /* = SLA page */>> Pages3rdparty; 473 474 475 class ConfigWizardIndex: public wxPanel 476 { 477 public: 478 ConfigWizardIndex(wxWindow *parent); 479 480 void add_page(ConfigWizardPage *page); 481 void add_label(wxString label, unsigned indent = 0); 482 active_item() const483 size_t active_item() const { return item_active; } 484 ConfigWizardPage* active_page() const; active_is_last() const485 bool active_is_last() const { return item_active < items.size() && item_active == last_page; } 486 487 void go_prev(); 488 void go_next(); 489 void go_to(size_t i); 490 void go_to(const ConfigWizardPage *page); 491 492 void clear(); 493 void msw_rescale(); 494 em() const495 int em() const { return em_w; } 496 497 static const size_t NO_ITEM = size_t(-1); 498 private: 499 struct Item 500 { 501 wxString label; 502 unsigned indent; 503 ConfigWizardPage *page; // nullptr page => label-only item 504 operator ==Slic3r::GUI::ConfigWizardIndex::Item505 bool operator==(ConfigWizardPage *page) const { return this->page == page; } 506 }; 507 508 int em_w; 509 int em_h; 510 ScalableBitmap bg; 511 ScalableBitmap bullet_black; 512 ScalableBitmap bullet_blue; 513 ScalableBitmap bullet_white; 514 wxStaticBitmap* logo; 515 516 std::vector<Item> items; 517 size_t item_active; 518 ssize_t item_hover; 519 size_t last_page; 520 item_height() const521 int item_height() const { return std::max(bullet_black.bmp().GetSize().GetHeight(), em_w) + em_w; } 522 523 void on_paint(wxPaintEvent &evt); 524 void on_mouse_move(wxMouseEvent &evt); 525 }; 526 527 wxDEFINE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); 528 529 530 531 // ConfigWizard private data 532 533 typedef std::map<std::string, std::set<std::string>> PresetAliases; 534 535 struct ConfigWizard::priv 536 { 537 ConfigWizard *q; 538 ConfigWizard::RunReason run_reason = RR_USER; 539 AppConfig appconfig_new; // Backing for vendor/model/variant and material selections in the GUI 540 BundleMap bundles; // Holds all loaded config bundles, the key is the vendor names. 541 // Materials refers to Presets in those bundles by pointers. 542 // Also we update the is_visible flag in printer Presets according to the 543 // PrinterPickers state. 544 Materials filaments; // Holds available filament presets and their types & vendors 545 Materials sla_materials; // Ditto for SLA materials 546 PresetAliases aliases_fff; // Map of aliase to preset names 547 PresetAliases aliases_sla; // Map of aliase to preset names 548 std::unique_ptr<DynamicPrintConfig> custom_config; // Backing for custom printer definition 549 bool any_fff_selected; // Used to decide whether to display Filaments page 550 bool any_sla_selected; // Used to decide whether to display SLA Materials page 551 bool custom_printer_selected; 552 553 wxScrolledWindow *hscroll = nullptr; 554 wxBoxSizer *hscroll_sizer = nullptr; 555 wxBoxSizer *btnsizer = nullptr; 556 ConfigWizardPage *page_current = nullptr; 557 ConfigWizardIndex *index = nullptr; 558 wxButton *btn_sel_all = nullptr; 559 wxButton *btn_prev = nullptr; 560 wxButton *btn_next = nullptr; 561 wxButton *btn_finish = nullptr; 562 wxButton *btn_cancel = nullptr; 563 564 PageWelcome *page_welcome = nullptr; 565 PagePrinters *page_fff = nullptr; 566 PagePrinters *page_msla = nullptr; 567 PageMaterials *page_filaments = nullptr; 568 PageMaterials *page_sla_materials = nullptr; 569 PageCustom *page_custom = nullptr; 570 PageUpdate *page_update = nullptr; 571 PageReloadFromDisk *page_reload_from_disk = nullptr; 572 #if ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN 573 #ifdef _WIN32 574 PageFilesAssociation* page_files_association = nullptr; 575 #endif // _WIN32 576 #endif // ENABLE_CUSTOMIZABLE_FILES_ASSOCIATION_ON_WIN 577 PageMode *page_mode = nullptr; 578 PageVendors *page_vendors = nullptr; 579 Pages3rdparty pages_3rdparty; 580 581 // Custom setup pages 582 PageFirmware *page_firmware = nullptr; 583 PageBedShape *page_bed = nullptr; 584 PageDiameters *page_diams = nullptr; 585 PageTemperatures *page_temps = nullptr; 586 587 // Pointers to all pages (regardless or whether currently part of the ConfigWizardIndex) 588 std::vector<ConfigWizardPage*> all_pages; 589 privSlic3r::GUI::ConfigWizard::priv590 priv(ConfigWizard *q) 591 : q(q) 592 , appconfig_new(AppConfig::EAppMode::Editor) 593 , filaments(T_FFF) 594 , sla_materials(T_SLA) 595 {} 596 597 void load_pages(); 598 void init_dialog_size(); 599 600 void load_vendors(); 601 void add_page(ConfigWizardPage *page); 602 void enable_next(bool enable); 603 void set_start_page(ConfigWizard::StartPage start_page); 604 void create_3rdparty_pages(); 605 void set_run_reason(RunReason run_reason); 606 void update_materials(Technology technology); 607 608 void on_custom_setup(const bool custom_wanted); 609 void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt); 610 void select_default_materials_for_printer_model(const VendorProfile::PrinterModel &printer_model, Technology technology); 611 void select_default_materials_for_printer_models(Technology technology, const std::set<const VendorProfile::PrinterModel*> &printer_models); 612 void on_3rdparty_install(const VendorProfile *vendor, bool install); 613 614 bool on_bnt_finish(); 615 bool check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id = std::string()); 616 bool apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater); 617 // #ys_FIXME_alise 618 void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add); 619 620 bool check_fff_selected(); // Used to decide whether to display Filaments page 621 bool check_sla_selected(); // Used to decide whether to display SLA Materials page 622 emSlic3r::GUI::ConfigWizard::priv623 int em() const { return index->em(); } 624 }; 625 626 } 627 } 628 629 #endif 630