From 3fcf194e39e93d36bc164acffbf7f4ad2c67fb6f Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 13 Mar 2018 12:39:57 +0100 Subject: [PATCH 01/10] ConfigWizard: Basic structure / WIP --- lib/Slic3r/GUI.pm | 20 +- lib/Slic3r/GUI/MainFrame.pm | 8 +- resources/icons/printers/MK2S.png | Bin 0 -> 58794 bytes resources/icons/printers/MK2SMM.png | Bin 0 -> 57081 bytes resources/icons/printers/MK3.png | Bin 0 -> 64194 bytes resources/profiles/PrusaResearch.ini | 8 +- xs/CMakeLists.txt | 5 + xs/src/libslic3r/Utils.hpp | 2 + xs/src/slic3r/GUI/AppConfig.cpp | 2 +- xs/src/slic3r/GUI/ConfigWizard.cpp | 433 +++++++++++++++++++++ xs/src/slic3r/GUI/ConfigWizard.hpp | 38 ++ xs/src/slic3r/GUI/ConfigWizard_private.hpp | 162 ++++++++ xs/src/slic3r/GUI/GUI.cpp | 15 + xs/src/slic3r/GUI/GUI.hpp | 4 + xs/src/slic3r/GUI/Preferences.cpp | 1 + xs/src/slic3r/GUI/Preset.hpp | 9 +- xs/src/slic3r/GUI/PresetBundle.cpp | 31 +- xs/src/slic3r/GUI/PresetBundle.hpp | 1 + xs/src/slic3r/Utils/PresetUpdate.cpp | 104 +++++ xs/src/slic3r/Utils/PresetUpdate.hpp | 38 ++ xs/xsp/GUI.xsp | 3 + xs/xsp/Utils_PresetUpdate.xsp | 18 + xs/xsp/my.map | 3 + 23 files changed, 881 insertions(+), 24 deletions(-) create mode 100644 resources/icons/printers/MK2S.png create mode 100644 resources/icons/printers/MK2SMM.png create mode 100644 resources/icons/printers/MK3.png create mode 100644 xs/src/slic3r/GUI/ConfigWizard.cpp create mode 100644 xs/src/slic3r/GUI/ConfigWizard.hpp create mode 100644 xs/src/slic3r/GUI/ConfigWizard_private.hpp create mode 100644 xs/src/slic3r/Utils/PresetUpdate.cpp create mode 100644 xs/src/slic3r/Utils/PresetUpdate.hpp create mode 100644 xs/xsp/Utils_PresetUpdate.xsp diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 4ec388c14..0c5e87429 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -101,6 +101,8 @@ sub OnInit { $self->{app_config}->set('version', $Slic3r::VERSION); $self->{app_config}->save; + my $slic3r_update_avail = $self->{app_config}->get("version_check") && $self->{app_config}->get("version_online") != $Slic3r::VERSION; + Slic3r::GUI::set_app_config($self->{app_config}); Slic3r::GUI::load_language(); @@ -111,6 +113,7 @@ sub OnInit { warn $@ . "\n"; show_error(undef, $@); } + # TODO: check previously downloaded updates $run_wizard = 1 if $self->{preset_bundle}->has_defauls_only; Slic3r::GUI::set_preset_bundle($self->{preset_bundle}); @@ -134,14 +137,19 @@ sub OnInit { $self->{app_config}->save if $self->{app_config}->dirty; }); - if ($run_wizard) { - # On OSX the UI was not initialized correctly if the wizard was called - # before the UI was up and running. - $self->CallAfter(sub { + # On OSX the UI was not initialized correctly if the wizard was called + # before the UI was up and running. + $self->CallAfter(sub { + if ($slic3r_update_avail) { + # TODO + } elsif ($run_wizard) { # Run the config wizard, don't offer the "reset user profile" checkbox. $self->{mainframe}->config_wizard(1); - }); - } + } + + # XXX: recreate_GUI ??? + Slic3r::PresetUpdater::download($self->{app_config}, $self->{preset_bundle}); + }); # The following event is emited by the C++ menu implementation of application language change. EVT_COMMAND($self, -1, $LANGUAGE_CHANGE_EVENT, sub{ diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index b2f51b9e1..68fc96339 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -95,7 +95,7 @@ sub new { }); $self->update_ui_from_settings; - + return $self; } @@ -643,6 +643,12 @@ sub config_wizard { my ($self, $fresh_start) = @_; # Exit wizard if there are unsaved changes and the user cancels the action. return unless $self->check_unsaved_changes; + + + # TODO: Offer "reset user profile" + Slic3r::GUI::open_config_wizard(); + return; + # Enumerate the profiles bundled with the Slic3r installation under resources/profiles. my $directory = Slic3r::resources_dir() . "/profiles"; my @profiles = (); diff --git a/resources/icons/printers/MK2S.png b/resources/icons/printers/MK2S.png new file mode 100644 index 0000000000000000000000000000000000000000..925447cf201911308d2a4788e6a0f8fd6f9db2c6 GIT binary patch literal 58794 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 DH{Xdt literal 0 HcmV?d00001 diff --git a/resources/icons/printers/MK2SMM.png b/resources/icons/printers/MK2SMM.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ff161259d9752504ad959c87d0e8529ad97541 GIT binary patch literal 57081 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 literal 0 HcmV?d00001 diff --git a/resources/icons/printers/MK3.png b/resources/icons/printers/MK3.png new file mode 100644 index 0000000000000000000000000000000000000000..5279ba01e060d81738565c5fd99c11e06fbef540 GIT binary patch literal 64194 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�WrFjD4RdqUre@ogt*oytQM-njETd@mVx1yo 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

H`@`RyGv2V%cRm zB3AgRoS99FaA*JaJF3;LSMN3m=6GJltr65d8uPZ+g6jrBL}C8c*uw3>bL(4p&%yn* z1L!=|>Nlac8C>4j2 zL@Kf(2V*EpivaRK4Zkrq&<;=-W7uVvy}0;-3pn(tb!=~fSG@d1Ty?`NN4)smEEyf; zU2i#x-(2~h{PLGqKJt=d=iPVZ7eD{`k!h{QOs~7?qyPTyiNC0;6h)m#Ya%7-&UW>7 zJ8nys+fpe*mSwc+O`JD4Z;7IShBz0z|5T)rGHBkp3d+;96ql*WcDD<*Q!(p&@F*O( z!RqQ8b`13V<`5Ii$>@fKi^Jyu0u(cj{&P?K?a&qLKAx=DzQbl#^&pT30Wv>8TLi

#>L=X2CcPG;rmSx$cc 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

mM0xmn2E#!U}l&p`N$PZaZ@8&36buIP20?_pDBU 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 literal 0 HcmV?d00001 diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index fa4d48cda..0a1d26eaa 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -7,21 +7,25 @@ name = Prusa Research # This means, the server may force the Slic3r configuration to be downgraded. config_version = 0.1 # Where to get the updates from? -config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch.ini +# TODO: proper URL +# config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch.ini +config_update_url = https://gist.githubusercontent.com/vojtechkral/4d8fd4a3b8699a01ec892c264178461c/raw/e9187c3e15ceaf1a90f29b7c43cf3ccc746140f0/PrusaResearch.ini # The printer models will be shown by the Configuration Wizard in this order, # also the first model installed & the first nozzle installed will be activated after install. #TODO: One day we may differentiate variants of the nozzles / hot ends, #for example by the melt zone size, or whether the nozzle is hardened. [printer_model:MK3] +name = Original Prusa i3 MK3 variants = 0.4; 0.25; 0.6 [printer_model:MK2S] +name = Original Prusa i3 MK2S variants = 0.4; 0.25; 0.6 [printer_model:MK2SMM] # Printer model name will be shown by the installation wizard. -name = MK2S Multi Material +name = Original Prusa i3 MK2SMM variants = 0.4; 0.6 # All presets starting with asterisk, for example *common*, are intermediate and they will diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index f28db8f92..e73c8429a 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -205,12 +205,16 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/GUI/BonjourDialog.hpp ${LIBDIR}/slic3r/Utils/ASCIIFolding.cpp ${LIBDIR}/slic3r/Utils/ASCIIFolding.hpp + ${LIBDIR}/slic3r/GUI/ConfigWizard.cpp + ${LIBDIR}/slic3r/GUI/ConfigWizard.hpp ${LIBDIR}/slic3r/Utils/Http.cpp ${LIBDIR}/slic3r/Utils/Http.hpp ${LIBDIR}/slic3r/Utils/OctoPrint.cpp ${LIBDIR}/slic3r/Utils/OctoPrint.hpp ${LIBDIR}/slic3r/Utils/Bonjour.cpp ${LIBDIR}/slic3r/Utils/Bonjour.hpp + ${LIBDIR}/slic3r/Utils/PresetUpdate.cpp + ${LIBDIR}/slic3r/Utils/PresetUpdate.hpp ) add_library(admesh STATIC @@ -356,6 +360,7 @@ set(XS_XSP_FILES ${XSP_DIR}/SurfaceCollection.xsp ${XSP_DIR}/TriangleMesh.xsp ${XSP_DIR}/Utils_OctoPrint.xsp + ${XSP_DIR}/Utils_PresetUpdate.xsp ${XSP_DIR}/XS.xsp ) foreach (file ${XS_XSP_FILES}) diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp index 27e7fad6b..7e2fe3180 100644 --- a/xs/src/libslic3r/Utils.hpp +++ b/xs/src/libslic3r/Utils.hpp @@ -3,6 +3,8 @@ #include +#include "libslic3r.h" + namespace Slic3r { extern void set_logging_level(unsigned int level); diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index e32b645b4..4bdf88dda 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -42,7 +42,7 @@ void AppConfig::set_defaults() set("no_defaults", "1"); if (get("show_incompatible_presets").empty()) set("show_incompatible_presets", "0"); - // Version check is enabled by default in the config, but it is not implemented yet. + // Version check is enabled by default in the config, but it is not implemented yet. // XXX if (get("version_check").empty()) set("version_check", "1"); // Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers. diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp new file mode 100644 index 000000000..3cad789b6 --- /dev/null +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -0,0 +1,433 @@ +#include "ConfigWizard_private.hpp" + +#include // XXX +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "libslic3r/Utils.hpp" +#include "PresetBundle.hpp" +#include "GUI.hpp" + +namespace fs = boost::filesystem; + +namespace Slic3r { +namespace GUI { + + +// Wizard page base + +ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname) : + wxPanel(parent), + parent(parent), + shortname(std::move(shortname)), + p_prev(nullptr), + p_next(nullptr) +{ + auto *sizer = new wxBoxSizer(wxVERTICAL); + + auto *text = new wxStaticText(this, wxID_ANY, std::move(title), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + auto font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + font.SetWeight(wxFONTWEIGHT_BOLD); + font.SetPointSize(14); + text->SetFont(font); + sizer->Add(text, 0, wxALIGN_LEFT, 0); + sizer->AddSpacer(10); + + content = new wxBoxSizer(wxVERTICAL); + sizer->Add(content, 1); + + SetSizer(sizer); + + this->Hide(); + + Bind(wxEVT_SIZE, [this](wxSizeEvent &event) { + this->Layout(); + event.Skip(); + }); +} + +ConfigWizardPage::~ConfigWizardPage() {} + +ConfigWizardPage* ConfigWizardPage::chain(ConfigWizardPage *page) +{ + if (p_next != nullptr) { p_next->p_prev = nullptr; } + p_next = page; + if (page != nullptr) { + if (page->p_prev != nullptr) { page->p_prev->p_next = nullptr; } + page->p_prev = this; + } + + return page; +} + +void ConfigWizardPage::append_text(wxString text) +{ + auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + widget->Wrap(CONTENT_WIDTH); + widget->SetMinSize(wxSize(CONTENT_WIDTH, -1)); + // content->Add(widget, 1, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10); + content->Add(widget, 0, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10); +} + +void ConfigWizardPage::append_widget(wxWindow *widget, int proportion) +{ + content->Add(widget, proportion, wxEXPAND | wxTOP | wxBOTTOM, 10); +} + +void ConfigWizardPage::append_spacer(int space) +{ + content->AddSpacer(space); +} + +bool ConfigWizardPage::Show(bool show) +{ + if (extra_buttons() != nullptr) { extra_buttons()->Show(show); } + return wxPanel::Show(show); +} + +void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable); } + + +// Wizard pages + +PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) : + ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))), + others_buttons(new wxPanel(parent)), + variants_checked(0) +{ + append_text(_(L("Hello, welcome to Slic3r Prusa Edition! TODO: This text."))); + + const auto &vendors = bundle.vendors; + const auto vendor_prusa = std::find(vendors.cbegin(), vendors.cend(), VendorProfile("PrusaResearch")); + + // TODO: preload checkiness from app config + + if (vendor_prusa != vendors.cend()) { + const auto &models = vendor_prusa->models; + + auto *printer_picker = new wxPanel(this); + auto *printer_grid = new wxFlexGridSizer(models.size(), 0, 20); + printer_grid->SetFlexibleDirection(wxVERTICAL); + printer_picker->SetSizer(printer_grid); + + auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + namefont.SetWeight(wxFONTWEIGHT_BOLD); + + for (auto model = models.cbegin(); model != models.cend(); ++model) { + auto *panel = new wxPanel(printer_picker); + auto *sizer = new wxBoxSizer(wxVERTICAL); + panel->SetSizer(sizer); + + auto *title = new wxStaticText(panel, wxID_ANY, model->name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + title->SetFont(namefont); + sizer->Add(title, 0, wxBOTTOM, 3); + + auto bitmap_file = wxString::Format("printers/%s.png", model->id); + wxBitmap bitmap(GUI::from_u8(Slic3r::var(bitmap_file.ToStdString())), wxBITMAP_TYPE_PNG); + auto *bitmap_widget = new wxStaticBitmap(panel, wxID_ANY, bitmap); + sizer->Add(bitmap_widget, 0, wxBOTTOM, 3); + + sizer->AddSpacer(20); + + for (const auto &variant : model->variants) { + auto *cbox = new wxCheckBox(panel, wxID_ANY, wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle")))); + sizer->Add(cbox, 0, wxBOTTOM, 3); + cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { + this->variants_checked += event.IsChecked() ? 1 : -1; + this->on_variant_checked(); + }); + } + + printer_grid->Add(panel); + } + + append_widget(printer_picker); + } + + { + auto *sizer = new wxBoxSizer(wxHORIZONTAL); + auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors"))); + auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup"))); + + sizer->Add(other_vendors); + sizer->AddSpacer(BTN_SPACING); + sizer->Add(custom_setup); + + other_vendors->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_other_vendors(); }); + custom_setup->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_custom_setup(); }); + + others_buttons->SetSizer(sizer); + } +} + +void PageWelcome::on_page_set() +{ + chain(wizard_p()->page_update); + on_variant_checked(); +} + +void PageWelcome::on_variant_checked() +{ + enable_next(variants_checked > 0); +} + +PageUpdate::PageUpdate(ConfigWizard *parent) : + ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))) +{ + append_text(_(L("TODO: text"))); + auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for Slic3r updates"))); + box_slic3r->SetValue(true); + append_widget(box_slic3r); + + append_text(_(L("TODO: text"))); + auto *box_presets = new wxCheckBox(this, wxID_ANY, _(L("Update built-in Presets automatically"))); + box_presets->SetValue(true); + append_widget(box_presets); +} + +void PageUpdate::presets_update_enable(bool enable) +{ + // TODO +} + +PageVendors::PageVendors(ConfigWizard *parent) : + ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) +{} + +PageFirmware::PageFirmware(ConfigWizard *parent) : + ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))) +{} + +PageBedShape::PageBedShape(ConfigWizard *parent) : + ConfigWizardPage(parent, _(L("Bed Shape and Size")), _(L("Bed Shape"))) +{} + +PageDiameters::PageDiameters(ConfigWizard *parent) : + ConfigWizardPage(parent, _(L("Filament and Nozzle Diameter")), _(L("Print Diameters"))) +{} + +PageTemperatures::PageTemperatures(ConfigWizard *parent) : + ConfigWizardPage(parent, _(L("Bed and Extruder Temperature")), _(L("Temperatures"))) +{} + + +// Index + +ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) : + wxPanel(parent), + bg(GUI::from_u8(Slic3r::var("Slic3r_192px_transparent.png")), wxBITMAP_TYPE_PNG), + bullet_black(GUI::from_u8(Slic3r::var("bullet_black.png")), wxBITMAP_TYPE_PNG), + bullet_blue(GUI::from_u8(Slic3r::var("bullet_blue.png")), wxBITMAP_TYPE_PNG), + bullet_white(GUI::from_u8(Slic3r::var("bullet_white.png")), wxBITMAP_TYPE_PNG) +{ + SetMinSize(bg.GetSize()); + Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this); + + wxClientDC dc(this); + text_height = dc.GetCharHeight(); +} + +void ConfigWizardIndex::load_items(ConfigWizardPage *firstpage) +{ + items.clear(); + item_active = items.cend(); + + for (auto *page = firstpage; page != nullptr; page = page->page_next()) { + items.emplace_back(page->shortname); + } + + Refresh(); +} + +void ConfigWizardIndex::set_active(ConfigWizardPage *page) +{ + item_active = std::find(items.cbegin(), items.cend(), page->shortname); + Refresh(); +} + +void ConfigWizardIndex::on_paint(wxPaintEvent & evt) +{ + enum { + MARGIN = 10, + SPACING = 5, + }; + + const auto size = GetClientSize(); + const auto h = size.GetHeight(); + const auto w = size.GetWidth(); + if (h == 0 || w == 0) { return; } + + wxPaintDC dc(this); + dc.DrawBitmap(bg, 0, h - bg.GetHeight(), false); + + const auto bullet_w = bullet_black.GetSize().GetWidth(); + const auto bullet_h = bullet_black.GetSize().GetHeight(); + const int yoff_icon = bullet_h < text_height ? (text_height - bullet_h) / 2 : 0; + const int yoff_text = bullet_h > text_height ? (bullet_h - text_height) / 2 : 0; + const int yinc = std::max(bullet_h, text_height) + SPACING; + + unsigned y = 0; + for (auto it = items.cbegin(); it != items.cend(); ++it) { + if (it < item_active) { dc.DrawBitmap(bullet_black, MARGIN, y + yoff_icon, false); } + if (it == item_active) { dc.DrawBitmap(bullet_blue, MARGIN, y + yoff_icon, false); } + if (it > item_active) { dc.DrawBitmap(bullet_white, MARGIN, y + yoff_icon, false); } + dc.DrawText(*it, MARGIN + bullet_w + SPACING, y + yoff_text); + y += yinc; + } +} + + + +// priv + +void ConfigWizard::priv::index_refresh() +{ + index->load_items(page_welcome); +} + +void ConfigWizard::priv::add_page(ConfigWizardPage *page) +{ + topsizer->Add(page, 0, wxEXPAND); + + auto *extra_buttons = page->extra_buttons(); + if (extra_buttons != nullptr) { + btnsizer->Prepend(extra_buttons, 0); + } +} + +void ConfigWizard::priv::set_page(ConfigWizardPage *page) +{ + if (page == nullptr) { return; } + if (page_current != nullptr) { page_current->Hide(); } + page_current = page; + enable_next(true); + + page->on_page_set(); + index->load_items(page_welcome); + index->set_active(page); + page->Show(); + + btn_prev->Enable(page->page_prev() != nullptr); + btn_next->Show(page->page_next() != nullptr); + btn_finish->Show(page->page_next() == nullptr); + + q->Layout(); +} + +void ConfigWizard::priv::enable_next(bool enable) +{ + btn_next->Enable(enable); + btn_finish->Enable(enable); +} + +void ConfigWizard::priv::on_other_vendors() +{ + page_welcome + ->chain(page_vendors) + ->chain(page_update); + set_page(page_vendors); +} + +void ConfigWizard::priv::on_custom_setup() +{ + page_welcome->chain(page_firmware); + page_temps->chain(page_update); + set_page(page_firmware); +} + +// Public + +ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) : + wxDialog(parent, wxID_ANY, _(L("Configuration Assistant")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + p(new priv(this)) +{ + p->index = new ConfigWizardIndex(this); + + auto *vsizer = new wxBoxSizer(wxVERTICAL); + p->topsizer = new wxBoxSizer(wxHORIZONTAL); + auto *hline = new wxStaticLine(this); + p->btnsizer = new wxBoxSizer(wxHORIZONTAL); + + p->topsizer->Add(p->index, 0, wxEXPAND); + p->topsizer->AddSpacer(INDEX_MARGIN); + + // TODO: btn labels vs default w/ icons ... use arrows from resources? (no apply icon) + // Also: http://docs.wxwidgets.org/3.0/page_stockitems.html + p->btn_prev = new wxButton(this, wxID_BACKWARD, _(L("< &Back"))); + p->btn_next = new wxButton(this, wxID_FORWARD, _(L("&Next >"))); + p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish"))); + p->btn_cancel = new wxButton(this, wxID_CANCEL); + p->btnsizer->AddStretchSpacer(); + p->btnsizer->Add(p->btn_prev, 0, wxLEFT, BTN_SPACING); + p->btnsizer->Add(p->btn_next, 0, wxLEFT, BTN_SPACING); + p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING); + p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING); + + p->add_page(p->page_welcome = new PageWelcome(this, bundle)); + p->add_page(p->page_update = new PageUpdate(this)); + p->add_page(p->page_vendors = new PageVendors(this)); + p->add_page(p->page_firmware = new PageFirmware(this)); + p->add_page(p->page_bed = new PageBedShape(this)); + p->add_page(p->page_diams = new PageDiameters(this)); + p->add_page(p->page_temps = new PageTemperatures(this)); + p->index_refresh(); + + p->page_welcome->chain(p->page_update); + p->page_firmware + ->chain(p->page_bed) + ->chain(p->page_diams) + ->chain(p->page_temps); + + vsizer->Add(p->topsizer, 1, wxEXPAND | wxALL, DIALOG_MARGIN); + vsizer->Add(hline, 0, wxEXPAND); + vsizer->Add(p->btnsizer, 0, wxEXPAND | wxALL, DIALOG_MARGIN); + + p->set_page(p->page_welcome); + SetSizerAndFit(vsizer); + SetMinSize(GetSize()); + + p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); + p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); }); +} + +ConfigWizard::~ConfigWizard() {} + +void ConfigWizard::run(wxWindow *parent) +{ + PresetBundle bundle; + + const auto profiles_dir = fs::path(resources_dir()) / "profiles"; + for (fs::directory_iterator it(profiles_dir); it != fs::directory_iterator(); ++it) { + if (it->path().extension() == ".ini") { + bundle.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); + } + } + + // XXX + for (const auto &vendor : bundle.vendors) { + std::cerr << "vendor: " << vendor.name << std::endl; + std::cerr << " URL: " << vendor.config_update_url << std::endl; + for (const auto &model : vendor.models) { + std::cerr << "\tmodel: " << model.id << " (" << model.name << ")" << std::endl; + for (const auto &variant : model.variants) { + std::cerr << "\t\tvariant: " << variant.name << std::endl; + } + } + } + + ConfigWizard wizard(parent, bundle); + wizard.ShowModal(); +} + + +} +} diff --git a/xs/src/slic3r/GUI/ConfigWizard.hpp b/xs/src/slic3r/GUI/ConfigWizard.hpp new file mode 100644 index 000000000..1b14e29be --- /dev/null +++ b/xs/src/slic3r/GUI/ConfigWizard.hpp @@ -0,0 +1,38 @@ +#ifndef slic3r_ConfigWizard_hpp_ +#define slic3r_ConfigWizard_hpp_ + +#include + +#include + +namespace Slic3r { + +class PresetBundle; + +namespace GUI { + + +class ConfigWizard: public wxDialog +{ +public: + ConfigWizard(wxWindow *parent, const PresetBundle &bundle); + ConfigWizard(ConfigWizard &&) = delete; + ConfigWizard(const ConfigWizard &) = delete; + ConfigWizard &operator=(ConfigWizard &&) = delete; + ConfigWizard &operator=(const ConfigWizard &) = delete; + ~ConfigWizard(); + + static void run(wxWindow *parent); +private: + struct priv; + std::unique_ptr p; + + friend class ConfigWizardPage; +}; + + + +} +} + +#endif diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp new file mode 100644 index 000000000..ba028c0e8 --- /dev/null +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -0,0 +1,162 @@ +#ifndef slic3r_ConfigWizard_private_hpp_ +#define slic3r_ConfigWizard_private_hpp_ + +#include "ConfigWizard.hpp" + +#include + +#include +#include +#include + + +namespace Slic3r { +namespace GUI { + + +enum { + DIALOG_MARGIN = 15, + INDEX_MARGIN = 40, + BTN_SPACING = 10, +}; + +struct ConfigWizardPage: wxPanel +{ + enum { + CONTENT_WIDTH = 500, + }; + + ConfigWizard *parent; + const wxString shortname; + wxBoxSizer *content; + + ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname); + + virtual ~ConfigWizardPage(); + + ConfigWizardPage *page_prev() const { return p_prev; } + ConfigWizardPage *page_next() const { return p_next; } + ConfigWizardPage* chain(ConfigWizardPage *page); + + void append_text(wxString text); + void append_widget(wxWindow *widget, int proportion = 0); + void append_spacer(int space); + + ConfigWizard::priv *wizard_p() const { return parent->p.get(); } + + virtual bool Show(bool show = true); + virtual bool Hide() { return Show(false); } + virtual wxPanel* extra_buttons() { return nullptr; } + virtual void on_page_set() {} + + void enable_next(bool enable); +private: + ConfigWizardPage *p_prev; + ConfigWizardPage *p_next; +}; + +struct PageWelcome: ConfigWizardPage +{ + wxPanel *others_buttons; + unsigned variants_checked; + + PageWelcome(ConfigWizard *parent, const PresetBundle &bundle); + + virtual wxPanel* extra_buttons() { return others_buttons; } + virtual void on_page_set(); + + void on_variant_checked(); +}; + +struct PageUpdate: ConfigWizardPage +{ + PageUpdate(ConfigWizard *parent); + + void presets_update_enable(bool enable); +}; + +struct PageVendors: ConfigWizardPage +{ + PageVendors(ConfigWizard *parent); +}; + +struct PageFirmware: ConfigWizardPage +{ + PageFirmware(ConfigWizard *parent); +}; + +struct PageBedShape: ConfigWizardPage +{ + PageBedShape(ConfigWizard *parent); +}; + +struct PageDiameters: ConfigWizardPage +{ + PageDiameters(ConfigWizard *parent); +}; + +struct PageTemperatures: ConfigWizardPage +{ + PageTemperatures(ConfigWizard *parent); +}; + + +class ConfigWizardIndex: public wxPanel +{ +public: + ConfigWizardIndex(wxWindow *parent); + + void load_items(ConfigWizardPage *firstpage); + void set_active(ConfigWizardPage *page); +private: + const wxBitmap bg; + const wxBitmap bullet_black; + const wxBitmap bullet_blue; + const wxBitmap bullet_white; + int text_height; + + std::vector items; + std::vector::const_iterator item_active; + + void on_paint(wxPaintEvent & evt); +}; + +struct ConfigWizard::priv +{ + ConfigWizard *q; + wxBoxSizer *topsizer = nullptr; + wxBoxSizer *btnsizer = nullptr; + ConfigWizardPage *page_current = nullptr; + ConfigWizardIndex *index = nullptr; + wxButton *btn_prev = nullptr; + wxButton *btn_next = nullptr; + wxButton *btn_finish = nullptr; + wxButton *btn_cancel = nullptr; + + PageWelcome *page_welcome = nullptr; + PageUpdate *page_update = nullptr; + PageVendors *page_vendors = nullptr; + PageFirmware *page_firmware = nullptr; + PageBedShape *page_bed = nullptr; + PageDiameters *page_diams = nullptr; + PageTemperatures *page_temps = nullptr; + + priv(ConfigWizard *q) : q(q) {} + + void add_page(ConfigWizardPage *page); + void index_refresh(); + void set_page(ConfigWizardPage *page); + void go_prev() { if (page_current != nullptr) { set_page(page_current->page_prev()); } } + void go_next() { if (page_current != nullptr) { set_page(page_current->page_next()); } } + void enable_next(bool enable); + + void on_other_vendors(); + void on_custom_setup(); +}; + + + +} +} + +#endif diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 3eca4e707..53288067c 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -44,6 +44,7 @@ #include "TabIface.hpp" #include "AppConfig.hpp" #include "Utils.hpp" +#include "ConfigWizard.hpp" #include "Preferences.hpp" #include "PresetBundle.hpp" @@ -352,6 +353,20 @@ void add_debug_menu(wxMenuBar *menu, int event_language_change) //#endif } +void open_config_wizard() +{ + if (g_wxMainFrame == nullptr) { + throw std::runtime_error("Main frame not set"); + } + + // auto *wizard = new ConfigWizard(static_cast(g_wxMainFrame)); // FIXME: lifetime + + // wizard->run(); + ConfigWizard::run(g_wxMainFrame); + + // show_info(g_wxMainFrame, "After wizard", "After wizard"); +} + void open_preferences_dialog(int event_preferences) { auto dlg = new PreferencesDialog(g_wxMainFrame, event_preferences); diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 362b15307..1f93e18e9 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -73,6 +73,7 @@ void break_to_debugger(); // Passing the wxWidgets GUI classes instantiated by the Perl part to C++. void set_wxapp(wxApp *app); void set_main_frame(wxFrame *main_frame); +// wxFrame* get_main_frame(); void set_tab_panel(wxNotebook *tab_panel); void set_app_config(AppConfig *app_config); void set_preset_bundle(PresetBundle *preset_bundle); @@ -84,6 +85,9 @@ wxColour* get_sys_label_clr(); void add_debug_menu(wxMenuBar *menu, int event_language_change); +// Opens the first-time configuration wizard +void open_config_wizard(); + // Create "Preferences" dialog after selecting menu "Preferences" in Perl part void open_preferences_dialog(int event_preferences); diff --git a/xs/src/slic3r/GUI/Preferences.cpp b/xs/src/slic3r/GUI/Preferences.cpp index 0009b17ec..6731cd394 100644 --- a/xs/src/slic3r/GUI/Preferences.cpp +++ b/xs/src/slic3r/GUI/Preferences.cpp @@ -14,6 +14,7 @@ void PreferencesDialog::build() m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; }; + // TODO // $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( // opt_id = > 'version_check', // type = > 'bool', diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index 3634c5dd9..78e15bada 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -40,7 +40,7 @@ public: struct PrinterModel { PrinterModel() {} - PrinterModel(const std::string &name) : name(name) {} + std::string id; std::string name; bool enabled = true; std::vector variants; @@ -51,11 +51,10 @@ public: return nullptr; } const PrinterVariant* variant(const std::string &name) const { return const_cast(this)->variant(name); } - - bool operator< (const PrinterModel &rhs) const { return this->name < rhs.name; } - bool operator==(const PrinterModel &rhs) const { return this->name == rhs.name; } }; - std::set models; + std::vector models; + + VendorProfile(std::string id) : id(std::move(id)) {} size_t num_variants() const { size_t n = 0; for (auto &model : models) n += model.variants.size(); return n; } diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 7131bf771..241f0433e 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -4,6 +4,7 @@ #include "PresetBundle.hpp" #include "BitmapCache.hpp" +#include #include #include #include @@ -104,6 +105,7 @@ void PresetBundle::setup_directories() std::initializer_list paths = { data_dir, data_dir / "vendor", + data_dir / "cache", #ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR // Store the print/filament/printer presets into a "presets" directory. data_dir / "presets", @@ -198,6 +200,7 @@ static inline std::string remove_ini_suffix(const std::string &name) // If the "vendor" section is missing, enable all models and variants of the particular vendor. void PresetBundle::load_installed_printers(const AppConfig &config) { + // TODO // m_storage } @@ -667,7 +670,7 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree) static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorProfile &vendor_profile) { const std::string printer_model_key = "printer_model:"; - for (auto §ion : tree) + for (auto §ion : tree) { if (section.first == "vendor") { // Load the names of the active presets. for (auto &kvp : section.second) { @@ -682,7 +685,8 @@ static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorP } } else if (boost::starts_with(section.first, printer_model_key)) { VendorProfile::PrinterModel model; - model.name = section.first.substr(printer_model_key.size()); + model.id = section.first.substr(printer_model_key.size()); + model.name = section.second.get("name", model.id); section.second.get("variants", ""); std::vector variants; if (Slic3r::unescape_strings_cstyle(section.second.get("variants", ""), variants)) { @@ -693,9 +697,10 @@ static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorP } else { // Log error? } - if (! model.name.empty() && ! model.variants.empty()) - vendor_profile.models.insert(model); + if (! model.id.empty() && ! model.variants.empty()) + vendor_profile.models.push_back(std::move(model)); } + } } // Load a config bundle file, into presets and store the loaded presets into separate files @@ -719,12 +724,11 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla pt::ptree tree; boost::nowide::ifstream ifs(path); pt::read_ini(ifs, tree); - // Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed. - flatten_configbundle_hierarchy(tree); const VendorProfile *vendor_profile = nullptr; - if (flags & LOAD_CFGBNDLE_SYSTEM) { - VendorProfile vp; + if (flags & (LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY)) { + boost::filesystem::path fspath(path); + VendorProfile vp(fspath.stem().native()); load_vendor_profile(tree, vp); if (vp.name.empty()) throw std::runtime_error(std::string("Vendor Config Bundle is not valid: Missing vendor name key.")); @@ -732,6 +736,13 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla return 0; vendor_profile = &(*this->vendors.insert(vp).first); } + + if (flags & LOAD_CFGBUNDLE_VENDOR_ONLY) { + return 0; + } + + // 1.5) Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed. + flatten_configbundle_hierarchy(tree); // 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files. std::vector loaded_prints; @@ -803,7 +814,9 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla section.first << "\" defines no printer variant, it will be ignored."; continue; } - auto it_model = vendor_profile->models.find(VendorProfile::PrinterModel(printer_model)); + auto it_model = std::find_if(vendor_profile->models.cbegin(), vendor_profile->models.cend(), + [&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; } + ); if (it_model == vendor_profile->models.end()) { BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" << section.first << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored."; diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp index f481ba374..4949e0e03 100644 --- a/xs/src/slic3r/GUI/PresetBundle.hpp +++ b/xs/src/slic3r/GUI/PresetBundle.hpp @@ -81,6 +81,7 @@ public: LOAD_CFGBNDLE_RESET_USER_PROFILE = 2, // Load a system config bundle. LOAD_CFGBNDLE_SYSTEM = 4, + LOAD_CFGBUNDLE_VENDOR_ONLY = 8, }; // Load the config bundle, store it to the user profile directory by default. size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE); diff --git a/xs/src/slic3r/Utils/PresetUpdate.cpp b/xs/src/slic3r/Utils/PresetUpdate.cpp new file mode 100644 index 000000000..0e4c62af9 --- /dev/null +++ b/xs/src/slic3r/Utils/PresetUpdate.cpp @@ -0,0 +1,104 @@ +#include "PresetUpdate.hpp" + +#include // XXX +#include +#include +#include + +#include "libslic3r/Utils.hpp" +#include "slic3r/GUI/PresetBundle.hpp" +#include "slic3r/Utils/Http.hpp" + +namespace fs = boost::filesystem; + + +namespace Slic3r { + + +struct PresetUpdater::priv +{ + PresetBundle *bundle; + fs::path cache_path; + std::thread thread; + + priv(PresetBundle *bundle); + + void download(); +}; + + +PresetUpdater::priv::priv(PresetBundle *bundle) : + bundle(bundle), + cache_path(fs::path(Slic3r::data_dir()) / "cache") +{} + +void PresetUpdater::priv::download() +{ + std::cerr << "PresetUpdater::priv::download()" << std::endl; + + std::cerr << "Bundle vendors: " << bundle->vendors.size() << std::endl; + for (const auto &vendor : bundle->vendors) { + std::cerr << "vendor: " << vendor.name << std::endl; + std::cerr << " URL: " << vendor.config_update_url << std::endl; + + // TODO: Proper caching + + auto target_path = cache_path / vendor.id; + target_path += ".ini"; + std::cerr << "target_path: " << target_path << std::endl; + + Http::get(vendor.config_update_url) + .on_complete([&](std::string body, unsigned http_status) { + std::cerr << "Got ini: " << http_status << ", body: " << body.size() << std::endl; + fs::fstream file(target_path, std::ios::out | std::ios::binary | std::ios::trunc); + file.write(body.c_str(), body.size()); + }) + .on_error([](std::string body, std::string error, unsigned http_status) { + // TODO: what about errors? + std::cerr << "Error: " << http_status << ", " << error << std::endl; + }) + .perform_sync(); + } +} + +PresetUpdater::PresetUpdater(PresetBundle *preset_bundle) : p(new priv(preset_bundle)) {} + + +// Public + +PresetUpdater::~PresetUpdater() +{ + if (p && p->thread.joinable()) { + p->thread.detach(); + } +} + +void PresetUpdater::download(AppConfig *app_config, PresetBundle *preset_bundle) +{ + std::cerr << "PresetUpdater::download()" << std::endl; + + auto self = std::make_shared(preset_bundle); + auto thread = std::thread([self](){ + self->p->download(); + }); + self->p->thread = std::move(thread); +} + + +// TODO: remove +namespace Utils { + +void preset_update_check() +{ + std::cerr << "preset_update_check()" << std::endl; + + // TODO: + // 1. Get a version tag or the whole bundle from the web + // 2. Store into temporary location (?) + // 3. ??? + // 4. Profit! +} + +} + +} diff --git a/xs/src/slic3r/Utils/PresetUpdate.hpp b/xs/src/slic3r/Utils/PresetUpdate.hpp new file mode 100644 index 000000000..431134097 --- /dev/null +++ b/xs/src/slic3r/Utils/PresetUpdate.hpp @@ -0,0 +1,38 @@ +#ifndef slic3r_PresetUpdate_hpp_ +#define slic3r_PresetUpdate_hpp_ + +#include + +namespace Slic3r { + + +class AppConfig; +class PresetBundle; + +class PresetUpdater +{ +public: + PresetUpdater(PresetBundle *preset_bundle); + PresetUpdater(PresetUpdater &&) = delete; + PresetUpdater(const PresetUpdater &) = delete; + PresetUpdater &operator=(PresetUpdater &&) = delete; + PresetUpdater &operator=(const PresetUpdater &) = delete; + ~PresetUpdater(); + + static void download(AppConfig *app_config, PresetBundle *preset_bundle); +private: + struct priv; + std::unique_ptr p; +}; + + +// TODO: Remove +namespace Utils { + +void preset_update_check(); + +} + +} + +#endif diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 1376ff164..5115eda64 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -54,6 +54,9 @@ int combochecklist_get_flags(SV *ui) void set_app_config(AppConfig *app_config) %code%{ Slic3r::GUI::set_app_config(app_config); %}; +void open_config_wizard() + %code%{ Slic3r::GUI::open_config_wizard(); %}; + void open_preferences_dialog(int preferences_event) %code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %}; diff --git a/xs/xsp/Utils_PresetUpdate.xsp b/xs/xsp/Utils_PresetUpdate.xsp new file mode 100644 index 000000000..3596b7c86 --- /dev/null +++ b/xs/xsp/Utils_PresetUpdate.xsp @@ -0,0 +1,18 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "slic3r/Utils/PresetUpdate.hpp" +%} + +%name{Slic3r::PresetUpdater} class PresetUpdater { + static void download(PresetBundle *preset_bundle); +}; + + +# TODO: remove: + +%package{Slic3r::Utils}; + +void preset_update_check() + %code%{ Slic3r::Utils::preset_update_check(); %}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 87a8d8d86..d817af052 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -235,6 +235,9 @@ PresetHints* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T TabIface* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T +# TODO: remove: +# ConfigWizard* O_OBJECT_SLIC3R +# Ref O_OBJECT_SLIC3R_T OctoPrint* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T From 57e47a3296c94e9ed879e5bf281aef69f1942409 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 28 Mar 2018 11:36:36 +0200 Subject: [PATCH 02/10] AppConfig: Support for vendor / model / variant enable state --- lib/Slic3r/GUI.pm | 24 ++- xs/CMakeLists.txt | 6 +- xs/src/perlglue.cpp | 1 + xs/src/slic3r/GUI/AppConfig.cpp | 75 +++++++++- xs/src/slic3r/GUI/AppConfig.hpp | 16 ++ xs/src/slic3r/Utils/PresetUpdate.cpp | 104 ------------- xs/src/slic3r/Utils/PresetUpdater.cpp | 137 ++++++++++++++++++ .../{PresetUpdate.hpp => PresetUpdater.hpp} | 12 +- xs/xsp/GUI_AppConfig.xsp | 1 + xs/xsp/Utils_PresetUpdate.xsp | 18 --- xs/xsp/Utils_PresetUpdater.xsp | 11 ++ xs/xsp/my.map | 4 + 12 files changed, 267 insertions(+), 142 deletions(-) delete mode 100644 xs/src/slic3r/Utils/PresetUpdate.cpp create mode 100644 xs/src/slic3r/Utils/PresetUpdater.cpp rename xs/src/slic3r/Utils/{PresetUpdate.hpp => PresetUpdater.hpp} (71%) delete mode 100644 xs/xsp/Utils_PresetUpdate.xsp create mode 100644 xs/xsp/Utils_PresetUpdater.xsp diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 0c5e87429..495dd9ecc 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -70,6 +70,8 @@ our $grey = Wx::Colour->new(200,200,200); our $LANGUAGE_CHANGE_EVENT = Wx::NewEventType; # 2) To inform about a change of Preferences. our $PREFERENCES_EVENT = Wx::NewEventType; +# To inform AppConfig about Slic3r version available online +our $VERSION_ONLINE_EVENT = Wx::NewEventType; sub OnInit { my ($self) = @_; @@ -101,7 +103,9 @@ sub OnInit { $self->{app_config}->set('version', $Slic3r::VERSION); $self->{app_config}->save; - my $slic3r_update_avail = $self->{app_config}->get("version_check") && $self->{app_config}->get("version_online") != $Slic3r::VERSION; + # my $version_check = $self->{app_config}->get('version_check'); + $self->{preset_updater} = Slic3r::PresetUpdater->new($VERSION_ONLINE_EVENT, $self->{app_config}); + my $slic3r_update = $self->{app_config}->slic3r_update_avail; Slic3r::GUI::set_app_config($self->{app_config}); Slic3r::GUI::load_language(); @@ -140,15 +144,17 @@ sub OnInit { # On OSX the UI was not initialized correctly if the wizard was called # before the UI was up and running. $self->CallAfter(sub { - if ($slic3r_update_avail) { + # XXX: recreate_GUI ??? + if ($slic3r_update) { # TODO - } elsif ($run_wizard) { + } + # XXX: ? + if ($run_wizard) { # Run the config wizard, don't offer the "reset user profile" checkbox. $self->{mainframe}->config_wizard(1); } - # XXX: recreate_GUI ??? - Slic3r::PresetUpdater::download($self->{app_config}, $self->{preset_bundle}); + $self->{preset_updater}->download($self->{preset_bundle}); }); # The following event is emited by the C++ menu implementation of application language change. @@ -161,6 +167,14 @@ sub OnInit { $self->update_ui_from_settings; }); + # The following event is emited by PresetUpdater (C++) + EVT_COMMAND($self, -1, $VERSION_ONLINE_EVENT, sub { + my ($self, $event) = @_; + my $version = $event->GetString; + $self->{app_config}->set('version_online', $version); + $self->{app_config}->save; + }); + return 1; } diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index e73c8429a..3ce499d2b 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -213,8 +213,8 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/Utils/OctoPrint.hpp ${LIBDIR}/slic3r/Utils/Bonjour.cpp ${LIBDIR}/slic3r/Utils/Bonjour.hpp - ${LIBDIR}/slic3r/Utils/PresetUpdate.cpp - ${LIBDIR}/slic3r/Utils/PresetUpdate.hpp + ${LIBDIR}/slic3r/Utils/PresetUpdater.cpp + ${LIBDIR}/slic3r/Utils/PresetUpdater.hpp ) add_library(admesh STATIC @@ -360,7 +360,7 @@ set(XS_XSP_FILES ${XSP_DIR}/SurfaceCollection.xsp ${XSP_DIR}/TriangleMesh.xsp ${XSP_DIR}/Utils_OctoPrint.xsp - ${XSP_DIR}/Utils_PresetUpdate.xsp + ${XSP_DIR}/Utils_PresetUpdater.xsp ${XSP_DIR}/XS.xsp ) foreach (file ${XS_XSP_FILES}) diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index d7c9a590a..9706ced2c 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -64,6 +64,7 @@ REGISTER_CLASS(PresetCollection, "GUI::PresetCollection"); REGISTER_CLASS(PresetBundle, "GUI::PresetBundle"); REGISTER_CLASS(PresetHints, "GUI::PresetHints"); REGISTER_CLASS(TabIface, "GUI::Tab"); +REGISTER_CLASS(PresetUpdater, "PresetUpdater"); REGISTER_CLASS(OctoPrint, "OctoPrint"); SV* ConfigBase__as_hash(ConfigBase* THIS) diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index 4bdf88dda..e951beb44 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -1,5 +1,3 @@ -#include - #include "../../libslic3r/libslic3r.h" #include "../../libslic3r/Utils.hpp" #include "AppConfig.hpp" @@ -9,15 +7,20 @@ #include #include #include +#include #include #include #include #include #include +#include namespace Slic3r { +static const std::string VENDOR_PREFIX = "vendor:"; +static const std::string MODEL_PREFIX = "model:"; + void AppConfig::reset() { m_storage.clear(); @@ -45,6 +48,8 @@ void AppConfig::set_defaults() // Version check is enabled by default in the config, but it is not implemented yet. // XXX if (get("version_check").empty()) set("version_check", "1"); + if (get("preset_update").empty()) + set("preset_update", "1"); // Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers. // https://github.com/prusa3d/Slic3r/issues/233 if (get("use_legacy_opengl").empty()) @@ -67,6 +72,19 @@ void AppConfig::load() if (! data.empty()) // If there is a non-empty data, then it must be a top-level (without a section) config entry. m_storage[""][section.first] = data; + } else if (boost::starts_with(section.first, VENDOR_PREFIX)) { + // This is a vendor section listing enabled model / variants + const auto vendor_name = section.first.substr(VENDOR_PREFIX.size()); + auto &vendor = m_vendors[vendor_name]; + for (const auto &kvp : section.second) { + if (! boost::starts_with(kvp.first, MODEL_PREFIX)) { continue; } + const auto model_name = kvp.first.substr(MODEL_PREFIX.size()); + std::vector variants; + if (! unescape_strings_cstyle(kvp.second.data(), variants)) { continue; } + for (const auto &variant : variants) { + vendor[model_name].insert(variant); + } + } } else { // This must be a section name. Read the entries of a section. std::map &storage = m_storage[section.first]; @@ -96,10 +114,53 @@ void AppConfig::save() for (const std::pair &kvp : category.second) c << kvp.first << " = " << kvp.second << std::endl; } + // Write vendor sections + for (const auto &vendor : m_vendors) { + size_t size_sum = 0; + for (const auto &model : vendor.second) { size_sum += model.second.size(); } + if (size_sum == 0) { continue; } + + c << std::endl << "[" << VENDOR_PREFIX << vendor.first << "]" << std::endl; + + for (const auto &model : vendor.second) { + if (model.second.size() == 0) { continue; } + const std::vector variants(model.second.begin(), model.second.end()); + const auto escaped = escape_strings_cstyle(variants); + c << MODEL_PREFIX << model.first << " = " << escaped << std::endl; + } + } c.close(); m_dirty = false; } +bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const +{ + std::cerr << "AppConfig::get_variant(" << vendor << ", " << model << ", " << variant << ") "; + + const auto it_v = m_vendors.find(vendor); + if (it_v == m_vendors.end()) { return false; } + const auto it_m = it_v->second.find(model); + return it_m == it_v->second.end() ? false : it_m->second.find(variant) != it_m->second.end(); +} + +void AppConfig::set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable) +{ + if (enable) { + if (get_variant(vendor, model, variant)) { return; } + m_vendors[vendor][model].insert(variant); + } else { + auto it_v = m_vendors.find(vendor); + if (it_v == m_vendors.end()) { return; } + auto it_m = it_v->second.find(model); + if (it_m == it_v->second.end()) { return; } + auto it_var = it_m->second.find(variant); + if (it_var == it_m->second.end()) { return; } + it_m->second.erase(it_var); + } + // If we got here, there was an update + m_dirty = true; +} + std::string AppConfig::get_last_dir() const { const auto it = m_storage.find("recent"); @@ -156,6 +217,16 @@ void AppConfig::reset_selections() } } +bool AppConfig::version_check_enabled() const +{ + return get("version_check") == "1"; +} + +bool AppConfig::slic3r_update_avail() const +{ + return version_check_enabled() && get("version_online") != SLIC3R_VERSION; +} + std::string AppConfig::config_path() { return (boost::filesystem::path(Slic3r::data_dir()) / "slic3r.ini").make_preferred().string(); diff --git a/xs/src/slic3r/GUI/AppConfig.hpp b/xs/src/slic3r/GUI/AppConfig.hpp index 9b1d5a712..4ccd51304 100644 --- a/xs/src/slic3r/GUI/AppConfig.hpp +++ b/xs/src/slic3r/GUI/AppConfig.hpp @@ -1,9 +1,12 @@ #ifndef slic3r_AppConfig_hpp_ #define slic3r_AppConfig_hpp_ +#include #include #include +#include "libslic3r/Config.hpp" + namespace Slic3r { class AppConfig @@ -65,6 +68,13 @@ public: void clear_section(const std::string §ion) { m_storage[section].clear(); } + // TODO: remove / upgrade + // ConfigOptionStrings get_strings(const std::string §ion, const std::string &key) const; + // void set_strings(const std::string §ion, const std::string &key, const ConfigOptionStrings &value); + // TODO: + bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const; + void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); + // return recent/skein_directory or recent/config_directory or empty string. std::string get_last_dir() const; void update_config_dir(const std::string &dir); @@ -78,6 +88,10 @@ public: // the first non-default preset when called. void reset_selections(); + // Whether the Slic3r version available online differs from this one + bool version_check_enabled() const; + bool slic3r_update_avail() const; + // Get the default config path from Slic3r::data_dir(). static std::string config_path(); @@ -87,6 +101,8 @@ public: private: // Map of section, name -> value std::map> m_storage; + // Map of enabled vendors / models / variants + std::map>> m_vendors; // Has any value been modified since the config.ini has been last saved or loaded? bool m_dirty; }; diff --git a/xs/src/slic3r/Utils/PresetUpdate.cpp b/xs/src/slic3r/Utils/PresetUpdate.cpp deleted file mode 100644 index 0e4c62af9..000000000 --- a/xs/src/slic3r/Utils/PresetUpdate.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "PresetUpdate.hpp" - -#include // XXX -#include -#include -#include - -#include "libslic3r/Utils.hpp" -#include "slic3r/GUI/PresetBundle.hpp" -#include "slic3r/Utils/Http.hpp" - -namespace fs = boost::filesystem; - - -namespace Slic3r { - - -struct PresetUpdater::priv -{ - PresetBundle *bundle; - fs::path cache_path; - std::thread thread; - - priv(PresetBundle *bundle); - - void download(); -}; - - -PresetUpdater::priv::priv(PresetBundle *bundle) : - bundle(bundle), - cache_path(fs::path(Slic3r::data_dir()) / "cache") -{} - -void PresetUpdater::priv::download() -{ - std::cerr << "PresetUpdater::priv::download()" << std::endl; - - std::cerr << "Bundle vendors: " << bundle->vendors.size() << std::endl; - for (const auto &vendor : bundle->vendors) { - std::cerr << "vendor: " << vendor.name << std::endl; - std::cerr << " URL: " << vendor.config_update_url << std::endl; - - // TODO: Proper caching - - auto target_path = cache_path / vendor.id; - target_path += ".ini"; - std::cerr << "target_path: " << target_path << std::endl; - - Http::get(vendor.config_update_url) - .on_complete([&](std::string body, unsigned http_status) { - std::cerr << "Got ini: " << http_status << ", body: " << body.size() << std::endl; - fs::fstream file(target_path, std::ios::out | std::ios::binary | std::ios::trunc); - file.write(body.c_str(), body.size()); - }) - .on_error([](std::string body, std::string error, unsigned http_status) { - // TODO: what about errors? - std::cerr << "Error: " << http_status << ", " << error << std::endl; - }) - .perform_sync(); - } -} - -PresetUpdater::PresetUpdater(PresetBundle *preset_bundle) : p(new priv(preset_bundle)) {} - - -// Public - -PresetUpdater::~PresetUpdater() -{ - if (p && p->thread.joinable()) { - p->thread.detach(); - } -} - -void PresetUpdater::download(AppConfig *app_config, PresetBundle *preset_bundle) -{ - std::cerr << "PresetUpdater::download()" << std::endl; - - auto self = std::make_shared(preset_bundle); - auto thread = std::thread([self](){ - self->p->download(); - }); - self->p->thread = std::move(thread); -} - - -// TODO: remove -namespace Utils { - -void preset_update_check() -{ - std::cerr << "preset_update_check()" << std::endl; - - // TODO: - // 1. Get a version tag or the whole bundle from the web - // 2. Store into temporary location (?) - // 3. ??? - // 4. Profit! -} - -} - -} diff --git a/xs/src/slic3r/Utils/PresetUpdater.cpp b/xs/src/slic3r/Utils/PresetUpdater.cpp new file mode 100644 index 000000000..11064d2f0 --- /dev/null +++ b/xs/src/slic3r/Utils/PresetUpdater.cpp @@ -0,0 +1,137 @@ +#include "PresetUpdater.hpp" + +#include // XXX +#include +#include +#include +#include + +#include +#include + +#include "libslic3r/Utils.hpp" +#include "slic3r/GUI/GUI.hpp" +// #include "slic3r/GUI/AppConfig.hpp" +#include "slic3r/GUI/PresetBundle.hpp" +#include "slic3r/Utils/Http.hpp" + +namespace fs = boost::filesystem; + + +namespace Slic3r { + + +// TODO: proper URL +static const std::string SLIC3R_VERSION_URL = "https://gist.githubusercontent.com/vojtechkral/4d8fd4a3b8699a01ec892c264178461c/raw/e9187c3e15ceaf1a90f29b7c43cf3ccc746140f0/slic3rPE.version"; +enum { + SLIC3R_VERSION_BODY_MAX = 256, +}; + +struct PresetUpdater::priv +{ + int version_online_event; + bool version_check; + bool preset_update; + + fs::path cache_path; + bool cancel; + std::thread thread; + + priv(int event); + + void download(const std::set vendors) const; +}; + +PresetUpdater::priv::priv(int event) : + version_online_event(event), + version_check(false), + preset_update(false), + cache_path(fs::path(Slic3r::data_dir()) / "cache"), + cancel(false) +{} + +void PresetUpdater::priv::download(const std::set vendors) const +{ + std::cerr << "PresetUpdater::priv::download()" << std::endl; + + if (!version_check) { return; } + + // Download current Slic3r version + Http::get(SLIC3R_VERSION_URL) + .size_limit(SLIC3R_VERSION_BODY_MAX) + .on_progress([this](Http::Progress, bool &cancel) { + cancel = this->cancel; + }) + .on_complete([&](std::string body, unsigned http_status) { + boost::trim(body); + std::cerr << "Got version: " << http_status << ", body: \"" << body << '"' << std::endl; + wxCommandEvent* evt = new wxCommandEvent(version_online_event); + evt->SetString(body); + GUI::get_app()->QueueEvent(evt); + }) + .perform_sync(); + + if (!preset_update) { return; } + + // Donwload vendor preset bundles + std::cerr << "Bundle vendors: " << vendors.size() << std::endl; + for (const auto &vendor : vendors) { + std::cerr << "vendor: " << vendor.name << std::endl; + std::cerr << " URL: " << vendor.config_update_url << std::endl; + + if (cancel) { return; } + + // TODO: Proper caching + + auto target_path = cache_path / vendor.id; + target_path += ".ini"; + std::cerr << "target_path: " << target_path << std::endl; + + Http::get(vendor.config_update_url) + .on_progress([this](Http::Progress, bool &cancel) { + cancel = this->cancel; + }) + .on_complete([&](std::string body, unsigned http_status) { + std::cerr << "Got ini: " << http_status << ", body: " << body.size() << std::endl; + fs::fstream file(target_path, std::ios::out | std::ios::binary | std::ios::trunc); + file.write(body.c_str(), body.size()); + }) + .perform_sync(); + } +} + +PresetUpdater::PresetUpdater(int version_online_event, AppConfig *app_config) : + p(new priv(version_online_event)) +{ + p->preset_update = app_config->get("preset_update") == "1"; + // preset_update implies version_check: + p->version_check = p->preset_update || app_config->get("version_check") == "1"; +} + + +// Public + +PresetUpdater::~PresetUpdater() +{ + if (p && p->thread.joinable()) { + p->cancel = true; + p->thread.join(); + } +} + +void PresetUpdater::download(PresetBundle *preset_bundle) +{ + std::cerr << "PresetUpdater::download()" << std::endl; + + // Copy the whole vendors data for use in the background thread + // Unfortunatelly as of C++11, it needs to be copied again + // into the closure (but perhaps the compiler can elide this). + std::set vendors = preset_bundle->vendors; + + p->thread = std::move(std::thread([this, vendors]() { + this->p->download(std::move(vendors)); + })); +} + + +} diff --git a/xs/src/slic3r/Utils/PresetUpdate.hpp b/xs/src/slic3r/Utils/PresetUpdater.hpp similarity index 71% rename from xs/src/slic3r/Utils/PresetUpdate.hpp rename to xs/src/slic3r/Utils/PresetUpdater.hpp index 431134097..aafe9569b 100644 --- a/xs/src/slic3r/Utils/PresetUpdate.hpp +++ b/xs/src/slic3r/Utils/PresetUpdater.hpp @@ -12,27 +12,19 @@ class PresetBundle; class PresetUpdater { public: - PresetUpdater(PresetBundle *preset_bundle); + PresetUpdater(int version_online_event, AppConfig *app_config); PresetUpdater(PresetUpdater &&) = delete; PresetUpdater(const PresetUpdater &) = delete; PresetUpdater &operator=(PresetUpdater &&) = delete; PresetUpdater &operator=(const PresetUpdater &) = delete; ~PresetUpdater(); - static void download(AppConfig *app_config, PresetBundle *preset_bundle); + void download(PresetBundle *preset_bundle); private: struct priv; std::unique_ptr p; }; -// TODO: Remove -namespace Utils { - -void preset_update_check(); - } - -} - #endif diff --git a/xs/xsp/GUI_AppConfig.xsp b/xs/xsp/GUI_AppConfig.xsp index 08a88883d..de0e5a22b 100644 --- a/xs/xsp/GUI_AppConfig.xsp +++ b/xs/xsp/GUI_AppConfig.xsp @@ -43,4 +43,5 @@ void update_last_output_dir(char *dir); void reset_selections(); + bool slic3r_update_avail() const; }; diff --git a/xs/xsp/Utils_PresetUpdate.xsp b/xs/xsp/Utils_PresetUpdate.xsp deleted file mode 100644 index 3596b7c86..000000000 --- a/xs/xsp/Utils_PresetUpdate.xsp +++ /dev/null @@ -1,18 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "slic3r/Utils/PresetUpdate.hpp" -%} - -%name{Slic3r::PresetUpdater} class PresetUpdater { - static void download(PresetBundle *preset_bundle); -}; - - -# TODO: remove: - -%package{Slic3r::Utils}; - -void preset_update_check() - %code%{ Slic3r::Utils::preset_update_check(); %}; diff --git a/xs/xsp/Utils_PresetUpdater.xsp b/xs/xsp/Utils_PresetUpdater.xsp new file mode 100644 index 000000000..666379f02 --- /dev/null +++ b/xs/xsp/Utils_PresetUpdater.xsp @@ -0,0 +1,11 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "slic3r/Utils/PresetUpdater.hpp" +%} + +%name{Slic3r::PresetUpdater} class PresetUpdater { + PresetUpdater(int version_online_event, AppConfig *app_config); + void download(PresetBundle* preset_bundle); +}; diff --git a/xs/xsp/my.map b/xs/xsp/my.map index d817af052..9c0f60c1d 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -239,6 +239,10 @@ Ref O_OBJECT_SLIC3R_T # ConfigWizard* O_OBJECT_SLIC3R # Ref O_OBJECT_SLIC3R_T +PresetUpdater* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +Clone O_OBJECT_SLIC3R_T + OctoPrint* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T From e53949f2c85e06adaf7be9a96873844a8862eab6 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 29 Mar 2018 17:54:43 +0200 Subject: [PATCH 03/10] Apply printer model / variant preferences when loading presets --- lib/Slic3r/GUI.pm | 2 +- lib/Slic3r/GUI/MainFrame.pm | 6 +- resources/profiles/PrusaResearch.ini | 2 + xs/src/slic3r/GUI/AppConfig.cpp | 8 +- xs/src/slic3r/GUI/AppConfig.hpp | 5 +- xs/src/slic3r/GUI/ConfigWizard.cpp | 154 ++++++++++++++++----- xs/src/slic3r/GUI/ConfigWizard.hpp | 5 +- xs/src/slic3r/GUI/ConfigWizard_private.hpp | 30 +++- xs/src/slic3r/GUI/GUI.cpp | 9 +- xs/src/slic3r/GUI/GUI.hpp | 2 +- xs/src/slic3r/GUI/Preset.cpp | 11 ++ xs/src/slic3r/GUI/Preset.hpp | 18 ++- xs/src/slic3r/GUI/PresetBundle.cpp | 20 ++- xs/src/slic3r/GUI/PresetBundle.hpp | 2 + xs/src/slic3r/Utils/PresetUpdater.cpp | 2 +- xs/xsp/GUI.xsp | 4 +- xs/xsp/GUI_Preset.xsp | 2 +- 17 files changed, 218 insertions(+), 64 deletions(-) diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 495dd9ecc..ed2f6dfc7 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -154,7 +154,7 @@ sub OnInit { $self->{mainframe}->config_wizard(1); } - $self->{preset_updater}->download($self->{preset_bundle}); + # $self->{preset_updater}->download($self->{preset_bundle}); }); # The following event is emited by the C++ menu implementation of application language change. diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 68fc96339..4307375c8 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -646,7 +646,11 @@ sub config_wizard { # TODO: Offer "reset user profile" - Slic3r::GUI::open_config_wizard(); + Slic3r::GUI::open_config_wizard(wxTheApp->{preset_bundle}); + # Load the currently selected preset into the GUI, update the preset selection box. + foreach my $tab (values %{$self->{options_tabs}}) { # XXX: only if not cancelled? + $tab->load_current_preset; + } return; # Enumerate the profiles bundled with the Slic3r installation under resources/profiles. diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 0a1d26eaa..6dc29a96e 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -999,6 +999,7 @@ default_print_profile = 0.15mm OPTIMAL MK3 [printer:Original Prusa i3 MK3 0.25 nozzle] inherits = *common* nozzle_diameter = 0.25 +printer_variant = 0.25 end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 @@ -1009,6 +1010,7 @@ default_print_profile = 0.10mm DETAIL MK3 [printer:Original Prusa i3 MK3 0.6 nozzle] inherits = *common* nozzle_diameter = 0.6 +printer_variant = 0.6 end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index e951beb44..10a586e27 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -135,7 +135,7 @@ void AppConfig::save() bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const { - std::cerr << "AppConfig::get_variant(" << vendor << ", " << model << ", " << variant << ") "; + // std::cerr << "AppConfig::get_variant(" << vendor << ", " << model << ", " << variant << ") " << std::endl; const auto it_v = m_vendors.find(vendor); if (it_v == m_vendors.end()) { return false; } @@ -161,6 +161,12 @@ void AppConfig::set_variant(const std::string &vendor, const std::string &model, m_dirty = true; } +void AppConfig::set_vendors(const AppConfig &from) +{ + m_vendors = from.m_vendors; + m_dirty = true; +} + std::string AppConfig::get_last_dir() const { const auto it = m_storage.find("recent"); diff --git a/xs/src/slic3r/GUI/AppConfig.hpp b/xs/src/slic3r/GUI/AppConfig.hpp index 4ccd51304..e43ff51bf 100644 --- a/xs/src/slic3r/GUI/AppConfig.hpp +++ b/xs/src/slic3r/GUI/AppConfig.hpp @@ -68,12 +68,9 @@ public: void clear_section(const std::string §ion) { m_storage[section].clear(); } - // TODO: remove / upgrade - // ConfigOptionStrings get_strings(const std::string §ion, const std::string &key) const; - // void set_strings(const std::string §ion, const std::string &key, const ConfigOptionStrings &value); - // TODO: bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const; void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); + void set_vendors(const AppConfig &from); // return recent/skein_directory or recent/config_directory or empty string. std::string get_last_dir() const; diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index 3cad789b6..556b91a46 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -74,13 +74,17 @@ void ConfigWizardPage::append_text(wxString text) auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); widget->Wrap(CONTENT_WIDTH); widget->SetMinSize(wxSize(CONTENT_WIDTH, -1)); - // content->Add(widget, 1, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10); content->Add(widget, 0, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10); } -void ConfigWizardPage::append_widget(wxWindow *widget, int proportion) +void ConfigWizardPage::append_widget(wxWindow *widget, int proportion, int flag, int border) { - content->Add(widget, proportion, wxEXPAND | wxTOP | wxBOTTOM, 10); + content->Add(widget, proportion, flag, border); +} + +void ConfigWizardPage::append_sizer(wxSizer *sizer, int proportion) +{ + content->Add(sizer, proportion, wxEXPAND | wxTOP | wxBOTTOM, 10); } void ConfigWizardPage::append_spacer(int space) @@ -99,17 +103,19 @@ void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable) // Wizard pages -PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) : +// PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) : +PageWelcome::PageWelcome(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))), others_buttons(new wxPanel(parent)), variants_checked(0) { append_text(_(L("Hello, welcome to Slic3r Prusa Edition! TODO: This text."))); + const PresetBundle &bundle = wizard_p()->bundle_vendors; const auto &vendors = bundle.vendors; const auto vendor_prusa = std::find(vendors.cbegin(), vendors.cend(), VendorProfile("PrusaResearch")); - // TODO: preload checkiness from app config + const AppConfig &appconfig_vendors = wizard_p()->appconfig_vendors; if (vendor_prusa != vendors.cend()) { const auto &models = vendor_prusa->models; @@ -138,12 +144,20 @@ PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) : sizer->AddSpacer(20); + std::string model_id = model->id; + for (const auto &variant : model->variants) { + std::string variant_name = variant.name; auto *cbox = new wxCheckBox(panel, wxID_ANY, wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle")))); + bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant_name); + variants_checked += enabled; + cbox->SetValue(enabled); sizer->Add(cbox, 0, wxBOTTOM, 3); - cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { + cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) { this->variants_checked += event.IsChecked() ? 1 : -1; this->on_variant_checked(); + AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; + appconfig_vendors.set_variant("PrusaResearch", model_id, variant_name, event.IsChecked()); }); } @@ -156,6 +170,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) : { auto *sizer = new wxBoxSizer(wxHORIZONTAL); auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors"))); + other_vendors->Disable(); auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup"))); sizer->Add(other_vendors); @@ -181,17 +196,24 @@ void PageWelcome::on_variant_checked() } PageUpdate::PageUpdate(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))) + ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))), + version_check(true), + preset_update(true) { - append_text(_(L("TODO: text"))); - auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for Slic3r updates"))); - box_slic3r->SetValue(true); - append_widget(box_slic3r); + const AppConfig *app_config = GUI::get_app_config(); + append_text(_(L("TODO: text"))); + auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for Slic3r updates"))); + box_slic3r->SetValue(app_config->get("version_check") == "1"); + append_widget(box_slic3r); + append_text(_(L("TODO: text"))); auto *box_presets = new wxCheckBox(this, wxID_ANY, _(L("Update built-in Presets automatically"))); - box_presets->SetValue(true); + box_presets->SetValue(app_config->get("preset_update") == "1"); append_widget(box_presets); + + box_slic3r->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->version_check = event.IsChecked(); }); + box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); }); } void PageUpdate::presets_update_enable(bool enable) @@ -201,7 +223,42 @@ void PageUpdate::presets_update_enable(bool enable) PageVendors::PageVendors(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) -{} +{ + enum { + INDENT_SPACING = 30, + VERTICAL_SPACING = 10, + }; + + append_text(_(L("Other vendors! TODO: This text."))); + + const PresetBundle &bundle = wizard_p()->bundle_vendors; + auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + boldfont.SetWeight(wxFONTWEIGHT_BOLD); + + for (const auto &vendor : bundle.vendors) { + if (vendor.id == "PrusaResearch") { continue; } + + auto *label_vendor = new wxStaticText(this, wxID_ANY, vendor.name); + label_vendor->SetFont(boldfont); + append_thing(label_vendor, 0, 0, 0); + + for (const auto &model : vendor.models) { + auto *label_model = new wxStaticText(this, wxID_ANY, model.name); + label_model->SetFont(boldfont); + append_thing(label_model, 0, wxLEFT, INDENT_SPACING); + + for (const auto &variant : model.variants) { + auto *cbox = new wxCheckBox(this, wxID_ANY, variant.name); + append_thing(cbox, 0, wxEXPAND | wxLEFT, 2 * INDENT_SPACING); + cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { + // TODO + }); + } + } + + append_spacer(VERTICAL_SPACING); + } +} PageFirmware::PageFirmware(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))) @@ -289,6 +346,31 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt) // priv +void ConfigWizard::priv::load_vendors() +{ + const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; + // const auto profiles_dir = fs::path(resources_dir()) / "profiles"; + for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) { + if (it->path().extension() == ".ini") { + bundle_vendors.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); + } + } + + // XXX + // for (const auto &vendor : bundle_vendors.vendors) { + // std::cerr << "vendor: " << vendor.name << std::endl; + // std::cerr << " URL: " << vendor.config_update_url << std::endl; + // for (const auto &model : vendor.models) { + // std::cerr << "\tmodel: " << model.id << " (" << model.name << ")" << std::endl; + // for (const auto &variant : model.variants) { + // std::cerr << "\t\tvariant: " << variant.name << std::endl; + // } + // } + // } + + appconfig_vendors.set_vendors(*GUI::get_app_config()); +} + void ConfigWizard::priv::index_refresh() { index->load_items(page_welcome); @@ -344,12 +426,31 @@ void ConfigWizard::priv::on_custom_setup() set_page(page_firmware); } +void ConfigWizard::priv::on_finish() +{ + const bool is_custom_setup = page_welcome->page_next() == page_firmware; + + if (! is_custom_setup) { + AppConfig *app_config = GUI::get_app_config(); + app_config->set_vendors(appconfig_vendors); + + app_config->set("version_check", page_update->version_check ? "1" : "0"); + app_config->set("preset_update", page_update->preset_update ? "1" : "0"); + } else { + // TODO + } + + q->EndModal(wxID_OK); +} + // Public -ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) : +ConfigWizard::ConfigWizard(wxWindow *parent) : wxDialog(parent, wxID_ANY, _(L("Configuration Assistant")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), p(new priv(this)) { + p->load_vendors(); + p->index = new ConfigWizardIndex(this); auto *vsizer = new wxBoxSizer(wxVERTICAL); @@ -372,7 +473,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) : p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING); - p->add_page(p->page_welcome = new PageWelcome(this, bundle)); + p->add_page(p->page_welcome = new PageWelcome(this)); p->add_page(p->page_update = new PageUpdate(this)); p->add_page(p->page_vendors = new PageVendors(this)); p->add_page(p->page_firmware = new PageFirmware(this)); @@ -397,35 +498,24 @@ ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) : p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); }); + p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->on_finish(); }); } ConfigWizard::~ConfigWizard() {} -void ConfigWizard::run(wxWindow *parent) +void ConfigWizard::run(wxWindow *parent, PresetBundle *preset_bundle) { - PresetBundle bundle; - const auto profiles_dir = fs::path(resources_dir()) / "profiles"; for (fs::directory_iterator it(profiles_dir); it != fs::directory_iterator(); ++it) { if (it->path().extension() == ".ini") { - bundle.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); + PresetBundle::install_vendor_configbundle(it->path()); } } - // XXX - for (const auto &vendor : bundle.vendors) { - std::cerr << "vendor: " << vendor.name << std::endl; - std::cerr << " URL: " << vendor.config_update_url << std::endl; - for (const auto &model : vendor.models) { - std::cerr << "\tmodel: " << model.id << " (" << model.name << ")" << std::endl; - for (const auto &variant : model.variants) { - std::cerr << "\t\tvariant: " << variant.name << std::endl; - } - } + ConfigWizard wizard(parent); + if (wizard.ShowModal() == wxID_OK) { + preset_bundle->load_presets(*GUI::get_app_config()); } - - ConfigWizard wizard(parent, bundle); - wizard.ShowModal(); } diff --git a/xs/src/slic3r/GUI/ConfigWizard.hpp b/xs/src/slic3r/GUI/ConfigWizard.hpp index 1b14e29be..a06388396 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard.hpp @@ -15,14 +15,15 @@ namespace GUI { class ConfigWizard: public wxDialog { public: - ConfigWizard(wxWindow *parent, const PresetBundle &bundle); + // ConfigWizard(wxWindow *parent, const PresetBundle &bundle); + ConfigWizard(wxWindow *parent); ConfigWizard(ConfigWizard &&) = delete; ConfigWizard(const ConfigWizard &) = delete; ConfigWizard &operator=(ConfigWizard &&) = delete; ConfigWizard &operator=(const ConfigWizard &) = delete; ~ConfigWizard(); - static void run(wxWindow *parent); + static void run(wxWindow *parent, PresetBundle *preset_bundle); private: struct priv; std::unique_ptr p; diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index ba028c0e8..ab291d40f 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -9,6 +9,9 @@ #include #include +#include "AppConfig.hpp" +#include "PresetBundle.hpp" + namespace Slic3r { namespace GUI { @@ -34,14 +37,23 @@ struct ConfigWizardPage: wxPanel virtual ~ConfigWizardPage(); - ConfigWizardPage *page_prev() const { return p_prev; } - ConfigWizardPage *page_next() const { return p_next; } + ConfigWizardPage* page_prev() const { return p_prev; } + ConfigWizardPage* page_next() const { return p_next; } ConfigWizardPage* chain(ConfigWizardPage *page); void append_text(wxString text); - void append_widget(wxWindow *widget, int proportion = 0); + void append_widget(wxWindow *widget, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10); + + template + void append_thing(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) + { + content->Add(thing, proportion, flag, border); + } + + // TODO: remove: + void append_sizer(wxSizer *sizer, int proportion = 0); void append_spacer(int space); - + ConfigWizard::priv *wizard_p() const { return parent->p.get(); } virtual bool Show(bool show = true); @@ -60,7 +72,7 @@ struct PageWelcome: ConfigWizardPage wxPanel *others_buttons; unsigned variants_checked; - PageWelcome(ConfigWizard *parent, const PresetBundle &bundle); + PageWelcome(ConfigWizard *parent); virtual wxPanel* extra_buttons() { return others_buttons; } virtual void on_page_set(); @@ -70,6 +82,9 @@ struct PageWelcome: ConfigWizardPage struct PageUpdate: ConfigWizardPage { + bool version_check; + bool preset_update; + PageUpdate(ConfigWizard *parent); void presets_update_enable(bool enable); @@ -124,6 +139,9 @@ private: struct ConfigWizard::priv { ConfigWizard *q; + AppConfig appconfig_vendors; + PresetBundle bundle_vendors; + wxBoxSizer *topsizer = nullptr; wxBoxSizer *btnsizer = nullptr; ConfigWizardPage *page_current = nullptr; @@ -143,6 +161,7 @@ struct ConfigWizard::priv priv(ConfigWizard *q) : q(q) {} + void load_vendors(); void add_page(ConfigWizardPage *page); void index_refresh(); void set_page(ConfigWizardPage *page); @@ -152,6 +171,7 @@ struct ConfigWizard::priv void on_other_vendors(); void on_custom_setup(); + void on_finish(); }; diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 53288067c..80e232287 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -353,18 +353,13 @@ void add_debug_menu(wxMenuBar *menu, int event_language_change) //#endif } -void open_config_wizard() +void open_config_wizard(PresetBundle *preset_bundle) { if (g_wxMainFrame == nullptr) { throw std::runtime_error("Main frame not set"); } - // auto *wizard = new ConfigWizard(static_cast(g_wxMainFrame)); // FIXME: lifetime - - // wizard->run(); - ConfigWizard::run(g_wxMainFrame); - - // show_info(g_wxMainFrame, "After wizard", "After wizard"); + ConfigWizard::run(g_wxMainFrame, preset_bundle); } void open_preferences_dialog(int event_preferences) diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 1f93e18e9..98a124091 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -86,7 +86,7 @@ wxColour* get_sys_label_clr(); void add_debug_menu(wxMenuBar *menu, int event_language_change); // Opens the first-time configuration wizard -void open_config_wizard(); +void open_config_wizard(PresetBundle *preset_bundle); // Create "Preferences" dialog after selecting menu "Preferences" in Perl part void open_preferences_dialog(int event_preferences); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index c437f8b41..40afca144 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -2,6 +2,7 @@ #include #include "Preset.hpp" +#include "AppConfig.hpp" #include #include @@ -175,6 +176,16 @@ bool Preset::update_compatible_with_printer(const Preset &active_printer, const return this->is_compatible = is_compatible_with_printer(active_printer, extra_config); } +void Preset::set_visible_from_appconfig(const AppConfig &app_config) +{ + if (vendor == nullptr) { return; } + const std::string &model = config.opt_string("printer_model"); + const std::string &variant = config.opt_string("printer_variant"); + if (model.empty() || variant.empty()) { return; } + is_visible = app_config.get_variant(vendor->id, model, variant); + std::cerr << vendor->id << " / " << model << " / " << variant << ": visible: " << is_visible << std::endl; +} + const std::vector& Preset::print_options() { static std::vector s_opts { diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index 78e15bada..075eed9af 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -13,6 +13,8 @@ class wxItemContainer; namespace Slic3r { +class AppConfig; + enum ConfigFileType { CONFIG_FILE_TYPE_UNKNOWN, @@ -35,14 +37,14 @@ public: PrinterVariant() {} PrinterVariant(const std::string &name) : name(name) {} std::string name; - bool enabled = true; + // bool enabled = true; // TODO: remove these? }; struct PrinterModel { PrinterModel() {} std::string id; std::string name; - bool enabled = true; + // bool enabled = true; std::vector variants; PrinterVariant* variant(const std::string &name) { for (auto &v : this->variants) @@ -85,7 +87,7 @@ public: bool is_external = false; // System preset is read-only. bool is_system = false; - // Preset is visible, if it is compatible with the active Printer. + // Preset is visible, if it is compatible with the active Printer. TODO: fix // Also the "default" preset is only visible, if it is the only preset in the list. bool is_visible = true; // Has this preset been modified? @@ -131,6 +133,9 @@ public: // Mark this preset as compatible if it is compatible with active_printer. bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config); + // Set is_visible according to application config + void set_visible_from_appconfig(const AppConfig &app_config); + // Resize the extruder specific fields, initialize them with the content of the 1st extruder. void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); } @@ -162,6 +167,13 @@ public: PresetCollection(Preset::Type type, const std::vector &keys); ~PresetCollection(); + typedef std::deque::iterator Iterator; + typedef std::deque::const_iterator ConstIterator; + Iterator begin() { return m_presets.begin() + 1; } + ConstIterator begin() const { return m_presets.begin() + 1; } + Iterator end() { return m_presets.end(); } + ConstIterator end() const { return m_presets.end(); } + void reset(bool delete_files); Preset::Type type() const { return m_type; } diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 241f0433e..8645a4f2d 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -4,6 +4,7 @@ #include "PresetBundle.hpp" #include "BitmapCache.hpp" +#include // XXX #include #include #include @@ -105,7 +106,7 @@ void PresetBundle::setup_directories() std::initializer_list paths = { data_dir, data_dir / "vendor", - data_dir / "cache", + data_dir / "cache", // TODO: rename as vendor-cache? (Check usage elsewhere!) #ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR // Store the print/filament/printer presets into a "presets" directory. data_dir / "presets", @@ -200,8 +201,12 @@ static inline std::string remove_ini_suffix(const std::string &name) // If the "vendor" section is missing, enable all models and variants of the particular vendor. void PresetBundle::load_installed_printers(const AppConfig &config) { - // TODO - // m_storage + std::cerr << "load_installed_printers()" << std::endl; + + for (auto &preset : printers) { + std::cerr << "preset: printer: " << preset.name << std::endl; + preset.set_visible_from_appconfig(config); + } } // Load selections (current print, current filaments, current printer) from config.ini @@ -221,6 +226,10 @@ void PresetBundle::load_selections(const AppConfig &config) break; this->set_filament_preset(i, remove_ini_suffix(config.get("presets", name))); } + + // Update visibility of presets based on application vendor / model / variant configuration. + this->load_installed_printers(config); + // Update visibility of presets based on their compatibility with the active printer. // Always try to select a compatible print and filament preset to the current printer preset, // as the application may have been closed with an active "external" preset, which does not @@ -708,6 +717,11 @@ static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorP void PresetBundle::install_vendor_configbundle(const std::string &src_path0) { boost::filesystem::path src_path(src_path0); + install_vendor_configbundle(src_path); +} + +void PresetBundle::install_vendor_configbundle(const boost::filesystem::path &src_path) +{ boost::filesystem::copy_file(src_path, (boost::filesystem::path(data_dir()) / "vendor" / src_path.filename()).make_preferred(), boost::filesystem::copy_option::overwrite_if_exists); } diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp index 4949e0e03..4189e6c46 100644 --- a/xs/src/slic3r/GUI/PresetBundle.hpp +++ b/xs/src/slic3r/GUI/PresetBundle.hpp @@ -5,6 +5,7 @@ #include "Preset.hpp" #include +#include namespace Slic3r { @@ -88,6 +89,7 @@ public: // Install the Vendor specific config bundle into user's directory. void install_vendor_configbundle(const std::string &src_path); + static void install_vendor_configbundle(const boost::filesystem::path &src_path); // Export a config bundle file containing all the presets and the names of the active presets. void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings); diff --git a/xs/src/slic3r/Utils/PresetUpdater.cpp b/xs/src/slic3r/Utils/PresetUpdater.cpp index 11064d2f0..040d326b5 100644 --- a/xs/src/slic3r/Utils/PresetUpdater.cpp +++ b/xs/src/slic3r/Utils/PresetUpdater.cpp @@ -11,9 +11,9 @@ #include "libslic3r/Utils.hpp" #include "slic3r/GUI/GUI.hpp" -// #include "slic3r/GUI/AppConfig.hpp" #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/Utils/Http.hpp" +#include "slic3r/Utils/Semver.hpp" namespace fs = boost::filesystem; diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 5115eda64..ad7f69a2d 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -54,8 +54,8 @@ int combochecklist_get_flags(SV *ui) void set_app_config(AppConfig *app_config) %code%{ Slic3r::GUI::set_app_config(app_config); %}; -void open_config_wizard() - %code%{ Slic3r::GUI::open_config_wizard(); %}; +void open_config_wizard(PresetBundle *preset_bundle) + %code%{ Slic3r::GUI::open_config_wizard(preset_bundle); %}; void open_preferences_dialog(int preferences_event) %code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %}; diff --git a/xs/xsp/GUI_Preset.xsp b/xs/xsp/GUI_Preset.xsp index 84efdde53..1187a1cf5 100644 --- a/xs/xsp/GUI_Preset.xsp +++ b/xs/xsp/GUI_Preset.xsp @@ -147,7 +147,7 @@ PresetCollection::arrayref() void install_vendor_configbundle(const char *path) %code%{ try { - THIS->install_vendor_configbundle(path); + THIS->install_vendor_configbundle(std::string(path)); } catch (std::exception& e) { croak("Installing a vendor config bundle %s failed:\n%s\n", path, e.what()); } From 8422cf93c0e550e75a40522c56b9570c72d32169 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 5 Apr 2018 16:10:44 +0200 Subject: [PATCH 04/10] ConfigWizard: Finalize custom setup --- xs/src/libslic3r/Config.hpp | 1 + xs/src/libslic3r/PrintConfig.cpp | 2 +- xs/src/slic3r/GUI/ConfigWizard.cpp | 246 +++++++++++++++------ xs/src/slic3r/GUI/ConfigWizard_private.hpp | 40 +++- 4 files changed, 212 insertions(+), 77 deletions(-) diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index 6eb307c5c..06db9efef 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -659,6 +659,7 @@ public: ConfigOptionPoints() : ConfigOptionVector() {} explicit ConfigOptionPoints(size_t n, const Pointf &value) : ConfigOptionVector(n, value) {} explicit ConfigOptionPoints(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} + explicit ConfigOptionPoints(const std::vector &values) : ConfigOptionVector(values) {} static ConfigOptionType static_type() { return coPoints; } ConfigOptionType type() const override { return static_type(); } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 657e5a452..5795f044b 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1620,7 +1620,7 @@ PrintConfigDef::PrintConfigDef() "temperature control commands in the output."); def->cli = "temperature=i@"; def->full_label = L("Temperature"); - def->max = 0; + def->min = 0; def->max = max_temp; def->default_value = new ConfigOptionInts { 200 }; diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index 556b91a46..edf958bd8 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -74,17 +74,7 @@ void ConfigWizardPage::append_text(wxString text) auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); widget->Wrap(CONTENT_WIDTH); widget->SetMinSize(wxSize(CONTENT_WIDTH, -1)); - content->Add(widget, 0, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10); -} - -void ConfigWizardPage::append_widget(wxWindow *widget, int proportion, int flag, int border) -{ - content->Add(widget, proportion, flag, border); -} - -void ConfigWizardPage::append_sizer(wxSizer *sizer, int proportion) -{ - content->Add(sizer, proportion, wxEXPAND | wxTOP | wxBOTTOM, 10); + append(widget); } void ConfigWizardPage::append_spacer(int space) @@ -103,7 +93,6 @@ void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable) // Wizard pages -// PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) : PageWelcome::PageWelcome(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))), others_buttons(new wxPanel(parent)), @@ -164,13 +153,13 @@ PageWelcome::PageWelcome(ConfigWizard *parent) : printer_grid->Add(panel); } - append_widget(printer_picker); + append(printer_picker); } { auto *sizer = new wxBoxSizer(wxHORIZONTAL); auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors"))); - other_vendors->Disable(); + // other_vendors->Disable(); // XXX auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup"))); sizer->Add(other_vendors); @@ -201,36 +190,24 @@ PageUpdate::PageUpdate(ConfigWizard *parent) : preset_update(true) { const AppConfig *app_config = GUI::get_app_config(); - + append_text(_(L("TODO: text"))); auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for Slic3r updates"))); box_slic3r->SetValue(app_config->get("version_check") == "1"); - append_widget(box_slic3r); + append(box_slic3r); append_text(_(L("TODO: text"))); auto *box_presets = new wxCheckBox(this, wxID_ANY, _(L("Update built-in Presets automatically"))); box_presets->SetValue(app_config->get("preset_update") == "1"); - append_widget(box_presets); + append(box_presets); box_slic3r->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->version_check = event.IsChecked(); }); box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); }); } -void PageUpdate::presets_update_enable(bool enable) -{ - // TODO -} - PageVendors::PageVendors(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) { - enum { - INDENT_SPACING = 30, - VERTICAL_SPACING = 10, - }; - - append_text(_(L("Other vendors! TODO: This text."))); - const PresetBundle &bundle = wizard_p()->bundle_vendors; auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); boldfont.SetWeight(wxFONTWEIGHT_BOLD); @@ -240,16 +217,16 @@ PageVendors::PageVendors(ConfigWizard *parent) : auto *label_vendor = new wxStaticText(this, wxID_ANY, vendor.name); label_vendor->SetFont(boldfont); - append_thing(label_vendor, 0, 0, 0); + append(label_vendor, 0, 0, 0); for (const auto &model : vendor.models) { auto *label_model = new wxStaticText(this, wxID_ANY, model.name); label_model->SetFont(boldfont); - append_thing(label_model, 0, wxLEFT, INDENT_SPACING); + append(label_model, 0, wxLEFT, INDENT_SPACING); for (const auto &variant : model.variants) { auto *cbox = new wxCheckBox(this, wxID_ANY, variant.name); - append_thing(cbox, 0, wxEXPAND | wxLEFT, 2 * INDENT_SPACING); + append(cbox, 0, wxEXPAND | wxLEFT, 2 * INDENT_SPACING); cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { // TODO }); @@ -260,21 +237,169 @@ PageVendors::PageVendors(ConfigWizard *parent) : } } + PageFirmware::PageFirmware(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))) -{} + ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))), + gcode_opt(print_config_def.options["gcode_flavor"]), + gcode_picker(nullptr) +{ + append_text(_(L("Choose the type of firmware used by your printer."))); + append_text(gcode_opt.tooltip); + + wxArrayString choices; + choices.Alloc(gcode_opt.enum_labels.size()); + for (const auto &label : gcode_opt.enum_labels) { + choices.Add(label); + } + + gcode_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices); + const auto &enum_values = gcode_opt.enum_values; + auto needle = enum_values.cend(); + if (gcode_opt.default_value != nullptr) { + needle = std::find(enum_values.cbegin(), enum_values.cend(), gcode_opt.default_value->serialize()); + } + if (needle != enum_values.cend()) { + gcode_picker->SetSelection(needle - enum_values.cbegin()); + } else { + gcode_picker->SetSelection(0); + } + + append(gcode_picker); +} + +void PageFirmware::apply_custom_config(DynamicPrintConfig &config) +{ + ConfigOptionEnum opt; + + auto sel = gcode_picker->GetSelection(); + if (sel != wxNOT_FOUND && opt.deserialize(gcode_picker->GetString(sel).ToStdString())) { + config.set_key_value("gcode_flavor", &opt); + } +} PageBedShape::PageBedShape(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Bed Shape and Size")), _(L("Bed Shape"))) -{} + ConfigWizardPage(parent, _(L("Bed Shape and Size")), _(L("Bed Shape"))), + shape_panel(new BedShapePanel(this)) +{ + append_text(_(L("Set the shape of your printer's bed."))); + + shape_panel->build_panel(wizard_p()->custom_config.option("bed_shape")); + append(shape_panel); +} + +void PageBedShape::apply_custom_config(DynamicPrintConfig &config) +{ + const auto points(shape_panel->GetValue()); + auto *opt = new ConfigOptionPoints(points); + config.set_key_value("bed_shape", opt); +} PageDiameters::PageDiameters(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Filament and Nozzle Diameter")), _(L("Print Diameters"))) -{} + ConfigWizardPage(parent, _(L("Filament and Nozzle Diameters")), _(L("Print Diameters"))), + spin_nozzle(new wxSpinCtrlDouble(this, wxID_ANY)), + spin_filam(new wxSpinCtrlDouble(this, wxID_ANY)) +{ + spin_nozzle->SetDigits(2); + spin_nozzle->SetIncrement(0.1); + const auto &def_nozzle = print_config_def.options["nozzle_diameter"]; + auto *default_nozzle = dynamic_cast(def_nozzle.default_value); + spin_nozzle->SetValue(default_nozzle != nullptr && default_nozzle->size() > 0 ? default_nozzle->get_at(0) : 0.5); + + spin_filam->SetDigits(2); + spin_filam->SetIncrement(0.25); + const auto &def_filam = print_config_def.options["filament_diameter"]; + auto *default_filam = dynamic_cast(def_filam.default_value); + spin_filam->SetValue(default_filam != nullptr && default_filam->size() > 0 ? default_filam->get_at(0) : 3.0); + + append_text(_(L("Enter the diameter of your printer's hot end nozzle."))); + + auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5); + auto *text_nozzle = new wxStaticText(this, wxID_ANY, _(L("Nozzle Diameter:"))); + auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _(L("mm"))); + sizer_nozzle->AddGrowableCol(0, 1); + sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL); + sizer_nozzle->Add(spin_nozzle); + sizer_nozzle->Add(unit_nozzle, 0, wxALIGN_CENTRE_VERTICAL); + append(sizer_nozzle); + + append_spacer(VERTICAL_SPACING); + + append_text(_(L("Enter the diameter of your filament."))); + append_text(_(L("Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average."))); + + auto *sizer_filam = new wxFlexGridSizer(3, 5, 5); + auto *text_filam = new wxStaticText(this, wxID_ANY, _(L("Filament Diameter:"))); + auto *unit_filam = new wxStaticText(this, wxID_ANY, _(L("mm"))); + sizer_filam->AddGrowableCol(0, 1); + sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL); + sizer_filam->Add(spin_filam); + sizer_filam->Add(unit_filam, 0, wxALIGN_CENTRE_VERTICAL); + append(sizer_filam); +} + +void PageDiameters::apply_custom_config(DynamicPrintConfig &config) +{ + auto *opt_nozzle = new ConfigOptionFloats(1, spin_nozzle->GetValue()); + config.set_key_value("nozzle_diameter", opt_nozzle); + auto *opt_filam = new ConfigOptionFloats(1, spin_filam->GetValue()); + config.set_key_value("filament_diameter", opt_filam); +} PageTemperatures::PageTemperatures(ConfigWizard *parent) : - ConfigWizardPage(parent, _(L("Bed and Extruder Temperature")), _(L("Temperatures"))) -{} + ConfigWizardPage(parent, _(L("Extruder and Bed Temperatures")), _(L("Temperatures"))), + spin_extr(new wxSpinCtrl(this, wxID_ANY)), + spin_bed(new wxSpinCtrl(this, wxID_ANY)) +{ + spin_extr->SetIncrement(5); + const auto &def_extr = print_config_def.options["temperature"]; + spin_extr->SetRange(def_extr.min, def_extr.max); + auto *default_extr = dynamic_cast(def_extr.default_value); + spin_extr->SetValue(default_extr != nullptr && default_extr->size() > 0 ? default_extr->get_at(0) : 200); + + spin_bed->SetIncrement(5); + const auto &def_bed = print_config_def.options["bed_temperature"]; + spin_bed->SetRange(def_bed.min, def_bed.max); + auto *default_bed = dynamic_cast(def_bed.default_value); + spin_bed->SetValue(default_bed != nullptr && default_bed->size() > 0 ? default_bed->get_at(0) : 0); + + append_text(_(L("Enter the temperature needed for extruding your filament."))); + append_text(_(L("A rule of thumb is 160 to 230 °C for PLA, and 215 to 250 °C for ABS."))); + + auto *sizer_extr = new wxFlexGridSizer(3, 5, 5); + auto *text_extr = new wxStaticText(this, wxID_ANY, _(L("Extrusion Temperature:"))); + auto *unit_extr = new wxStaticText(this, wxID_ANY, _(L("°C"))); + sizer_extr->AddGrowableCol(0, 1); + sizer_extr->Add(text_extr, 0, wxALIGN_CENTRE_VERTICAL); + sizer_extr->Add(spin_extr); + sizer_extr->Add(unit_extr, 0, wxALIGN_CENTRE_VERTICAL); + append(sizer_extr); + + append_spacer(VERTICAL_SPACING); + + append_text(_(L("Enter the bed temperature needed for getting your filament to stick to your heated bed."))); + append_text(_(L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed."))); + + auto *sizer_bed = new wxFlexGridSizer(3, 5, 5); + auto *text_bed = new wxStaticText(this, wxID_ANY, _(L("Bed Temperature:"))); + auto *unit_bed = new wxStaticText(this, wxID_ANY, _(L("°C"))); + sizer_bed->AddGrowableCol(0, 1); + sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL); + sizer_bed->Add(spin_bed); + sizer_bed->Add(unit_bed, 0, wxALIGN_CENTRE_VERTICAL); + append(sizer_bed); +} + +void PageTemperatures::apply_custom_config(DynamicPrintConfig &config) +{ + auto *opt_extr = new ConfigOptionInts(1, spin_extr->GetValue()); + config.set_key_value("temperature", opt_extr); + auto *opt_extr1st = new ConfigOptionInts(1, spin_extr->GetValue()); + config.set_key_value("first_layer_temperature", opt_extr1st); + auto *opt_bed = new ConfigOptionInts(1, spin_bed->GetValue()); + config.set_key_value("bed_temperature", opt_bed); + auto *opt_bed1st = new ConfigOptionInts(1, spin_bed->GetValue()); + config.set_key_value("first_layer_bed_temperature", opt_bed1st); +} // Index @@ -349,25 +474,12 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt) void ConfigWizard::priv::load_vendors() { const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; - // const auto profiles_dir = fs::path(resources_dir()) / "profiles"; for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) { if (it->path().extension() == ".ini") { bundle_vendors.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); } } - // XXX - // for (const auto &vendor : bundle_vendors.vendors) { - // std::cerr << "vendor: " << vendor.name << std::endl; - // std::cerr << " URL: " << vendor.config_update_url << std::endl; - // for (const auto &model : vendor.models) { - // std::cerr << "\tmodel: " << model.id << " (" << model.name << ")" << std::endl; - // for (const auto &variant : model.variants) { - // std::cerr << "\t\tvariant: " << variant.name << std::endl; - // } - // } - // } - appconfig_vendors.set_vendors(*GUI::get_app_config()); } @@ -426,21 +538,22 @@ void ConfigWizard::priv::on_custom_setup() set_page(page_firmware); } -void ConfigWizard::priv::on_finish() +void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle) { const bool is_custom_setup = page_welcome->page_next() == page_firmware; if (! is_custom_setup) { - AppConfig *app_config = GUI::get_app_config(); app_config->set_vendors(appconfig_vendors); - app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); + app_config->reset_selections(); // XXX: only on "fresh start"? + preset_bundle->load_presets(*app_config); } else { - // TODO + for (ConfigWizardPage *page = page_firmware; page != nullptr; page = page->page_next()) { + page->apply_custom_config(custom_config); + } + preset_bundle->load_config("My Settings", custom_config); } - - q->EndModal(wxID_OK); } // Public @@ -450,6 +563,10 @@ ConfigWizard::ConfigWizard(wxWindow *parent) : p(new priv(this)) { p->load_vendors(); + std::unique_ptr custom_config_defaults(DynamicPrintConfig::new_from_defaults_keys({ + "gcode_flavor", "bed_shape", "nozzle_diameter", "filament_diameter", "temperature", "bed_temperature", + })); + p->custom_config.apply(*custom_config_defaults); p->index = new ConfigWizardIndex(this); @@ -461,10 +578,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent) : p->topsizer->Add(p->index, 0, wxEXPAND); p->topsizer->AddSpacer(INDEX_MARGIN); - // TODO: btn labels vs default w/ icons ... use arrows from resources? (no apply icon) - // Also: http://docs.wxwidgets.org/3.0/page_stockitems.html - p->btn_prev = new wxButton(this, wxID_BACKWARD, _(L("< &Back"))); - p->btn_next = new wxButton(this, wxID_FORWARD, _(L("&Next >"))); + p->btn_prev = new wxButton(this, wxID_BACKWARD); + p->btn_next = new wxButton(this, wxID_FORWARD); p->btn_finish = new wxButton(this, wxID_APPLY, _(L("&Finish"))); p->btn_cancel = new wxButton(this, wxID_CANCEL); p->btnsizer->AddStretchSpacer(); @@ -498,7 +613,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent) : p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); }); - p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->on_finish(); }); + // p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->on_finish(); }); + p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->EndModal(wxID_OK); }); } ConfigWizard::~ConfigWizard() {} @@ -514,7 +630,7 @@ void ConfigWizard::run(wxWindow *parent, PresetBundle *preset_bundle) ConfigWizard wizard(parent); if (wizard.ShowModal() == wxID_OK) { - preset_bundle->load_presets(*GUI::get_app_config()); + wizard.p->apply_config(GUI::get_app_config(), preset_bundle); } } diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index ab291d40f..1d9519bc3 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -8,9 +8,13 @@ #include #include #include +#include +#include +#include "libslic3r/PrintConfig.hpp" #include "AppConfig.hpp" #include "PresetBundle.hpp" +#include "BedShapeDialog.hpp" namespace Slic3r { @@ -21,6 +25,8 @@ enum { DIALOG_MARGIN = 15, INDEX_MARGIN = 40, BTN_SPACING = 10, + INDENT_SPACING = 30, + VERTICAL_SPACING = 10, }; struct ConfigWizardPage: wxPanel @@ -41,17 +47,13 @@ struct ConfigWizardPage: wxPanel ConfigWizardPage* page_next() const { return p_next; } ConfigWizardPage* chain(ConfigWizardPage *page); - void append_text(wxString text); - void append_widget(wxWindow *widget, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10); - template - void append_thing(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) + void append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) { content->Add(thing, proportion, flag, border); } - // TODO: remove: - void append_sizer(wxSizer *sizer, int proportion = 0); + void append_text(wxString text); void append_spacer(int space); ConfigWizard::priv *wizard_p() const { return parent->p.get(); } @@ -60,6 +62,7 @@ struct ConfigWizardPage: wxPanel virtual bool Hide() { return Show(false); } virtual wxPanel* extra_buttons() { return nullptr; } virtual void on_page_set() {} + virtual void apply_custom_config(DynamicPrintConfig &config) {} void enable_next(bool enable); private: @@ -84,10 +87,8 @@ struct PageUpdate: ConfigWizardPage { bool version_check; bool preset_update; - - PageUpdate(ConfigWizard *parent); - void presets_update_enable(bool enable); + PageUpdate(ConfigWizard *parent); }; struct PageVendors: ConfigWizardPage @@ -97,22 +98,37 @@ struct PageVendors: ConfigWizardPage struct PageFirmware: ConfigWizardPage { + const ConfigOptionDef &gcode_opt; + wxChoice *gcode_picker; + PageFirmware(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; struct PageBedShape: ConfigWizardPage { + BedShapePanel *shape_panel; + PageBedShape(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; struct PageDiameters: ConfigWizardPage { + wxSpinCtrlDouble *spin_nozzle; + wxSpinCtrlDouble *spin_filam; + PageDiameters(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; struct PageTemperatures: ConfigWizardPage { + wxSpinCtrl *spin_extr; + wxSpinCtrl *spin_bed; + PageTemperatures(ConfigWizard *parent); + virtual void apply_custom_config(DynamicPrintConfig &config); }; @@ -133,7 +149,7 @@ private: std::vector items; std::vector::const_iterator item_active; - void on_paint(wxPaintEvent & evt); + void on_paint(wxPaintEvent &evt); }; struct ConfigWizard::priv @@ -141,6 +157,7 @@ struct ConfigWizard::priv ConfigWizard *q; AppConfig appconfig_vendors; PresetBundle bundle_vendors; + DynamicPrintConfig custom_config; wxBoxSizer *topsizer = nullptr; wxBoxSizer *btnsizer = nullptr; @@ -171,7 +188,8 @@ struct ConfigWizard::priv void on_other_vendors(); void on_custom_setup(); - void on_finish(); + + void apply_config(AppConfig *app_config, PresetBundle *preset_bundle); }; From d1c1dcbe8f380c12120228c7318f243633b27490 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 5 Apr 2018 18:30:03 +0200 Subject: [PATCH 05/10] ConfigWizard: Factor out a PrinterPicker widget, finalize other vendors page --- .../{MK2S.png => PrusaResearch_MK2S.png} | Bin .../{MK2SMM.png => PrusaResearch_MK2SMM.png} | Bin .../{MK3.png => PrusaResearch_MK3.png} | Bin xs/src/slic3r/GUI/ConfigWizard.cpp | 220 ++++++++++++------ xs/src/slic3r/GUI/ConfigWizard_private.hpp | 16 +- 5 files changed, 159 insertions(+), 77 deletions(-) rename resources/icons/printers/{MK2S.png => PrusaResearch_MK2S.png} (100%) rename resources/icons/printers/{MK2SMM.png => PrusaResearch_MK2SMM.png} (100%) rename resources/icons/printers/{MK3.png => PrusaResearch_MK3.png} (100%) diff --git a/resources/icons/printers/MK2S.png b/resources/icons/printers/PrusaResearch_MK2S.png similarity index 100% rename from resources/icons/printers/MK2S.png rename to resources/icons/printers/PrusaResearch_MK2S.png diff --git a/resources/icons/printers/MK2SMM.png b/resources/icons/printers/PrusaResearch_MK2SMM.png similarity index 100% rename from resources/icons/printers/MK2SMM.png rename to resources/icons/printers/PrusaResearch_MK2SMM.png diff --git a/resources/icons/printers/MK3.png b/resources/icons/printers/PrusaResearch_MK3.png similarity index 100% rename from resources/icons/printers/MK3.png rename to resources/icons/printers/PrusaResearch_MK3.png diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index edf958bd8..914ebb9a1 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -23,6 +23,86 @@ namespace Slic3r { namespace GUI { +// FIXME: scrolling + + +// Printer model picker GUI control + +struct PrinterPickerEvent : public wxEvent +{ + std::string vendor_id; + std::string model_id; + std::string variant_name; + bool enable; + + PrinterPickerEvent(wxEventType eventType, int winid, std::string vendor_id, std::string model_id, std::string variant_name, bool enable) : + wxEvent(winid, eventType), + vendor_id(std::move(vendor_id)), + model_id(std::move(model_id)), + variant_name(std::move(variant_name)), + enable(enable) + {} + + virtual wxEvent *Clone() const + { + return new PrinterPickerEvent(*this); + } +}; + +wxDEFINE_EVENT(EVT_PRINTER_PICK, PrinterPickerEvent); + +PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors) : + wxPanel(parent), + variants_checked(0) +{ + const auto vendor_id = vendor.id; + const auto &models = vendor.models; + + auto *printer_grid = new wxFlexGridSizer(models.size(), 0, 20); + printer_grid->SetFlexibleDirection(wxVERTICAL); + SetSizer(printer_grid); + + auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + namefont.SetWeight(wxFONTWEIGHT_BOLD); + + for (auto model = models.cbegin(); model != models.cend(); ++model) { + auto *panel = new wxPanel(this); + auto *sizer = new wxBoxSizer(wxVERTICAL); + panel->SetSizer(sizer); + + auto *title = new wxStaticText(panel, wxID_ANY, model->name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + title->SetFont(namefont); + sizer->Add(title, 0, wxBOTTOM, 3); + + auto bitmap_file = wxString::Format("printers/%s_%s.png", vendor.id, model->id); + wxBitmap bitmap(GUI::from_u8(Slic3r::var(bitmap_file.ToStdString())), wxBITMAP_TYPE_PNG); + auto *bitmap_widget = new wxStaticBitmap(panel, wxID_ANY, bitmap); + sizer->Add(bitmap_widget, 0, wxBOTTOM, 3); + + sizer->AddSpacer(20); + + const auto model_id = model->id; + + for (const auto &variant : model->variants) { + const auto variant_name = variant.name; + auto *cbox = new wxCheckBox(panel, wxID_ANY, wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle")))); + bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant_name); + variants_checked += enabled; + cbox->SetValue(enabled); + sizer->Add(cbox, 0, wxBOTTOM, 3); + cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) { + this->variants_checked += event.IsChecked() ? 1 : -1; + PrinterPickerEvent evt(EVT_PRINTER_PICK, this->GetId(), std::move(vendor_id), std::move(model_id), std::move(variant_name), event.IsChecked()); + this->AddPendingEvent(evt); + }); + } + + printer_grid->Add(panel); + } + +} + + // Wizard page base ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxString shortname) : @@ -95,8 +175,8 @@ void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable) PageWelcome::PageWelcome(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))), - others_buttons(new wxPanel(parent)), - variants_checked(0) + printer_picker(nullptr), + others_buttons(new wxPanel(parent)) { append_text(_(L("Hello, welcome to Slic3r Prusa Edition! TODO: This text."))); @@ -104,73 +184,34 @@ PageWelcome::PageWelcome(ConfigWizard *parent) : const auto &vendors = bundle.vendors; const auto vendor_prusa = std::find(vendors.cbegin(), vendors.cend(), VendorProfile("PrusaResearch")); - const AppConfig &appconfig_vendors = wizard_p()->appconfig_vendors; - if (vendor_prusa != vendors.cend()) { const auto &models = vendor_prusa->models; - auto *printer_picker = new wxPanel(this); - auto *printer_grid = new wxFlexGridSizer(models.size(), 0, 20); - printer_grid->SetFlexibleDirection(wxVERTICAL); - printer_picker->SetSizer(printer_grid); + AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; - auto namefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - namefont.SetWeight(wxFONTWEIGHT_BOLD); - - for (auto model = models.cbegin(); model != models.cend(); ++model) { - auto *panel = new wxPanel(printer_picker); - auto *sizer = new wxBoxSizer(wxVERTICAL); - panel->SetSizer(sizer); - - auto *title = new wxStaticText(panel, wxID_ANY, model->name, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - title->SetFont(namefont); - sizer->Add(title, 0, wxBOTTOM, 3); - - auto bitmap_file = wxString::Format("printers/%s.png", model->id); - wxBitmap bitmap(GUI::from_u8(Slic3r::var(bitmap_file.ToStdString())), wxBITMAP_TYPE_PNG); - auto *bitmap_widget = new wxStaticBitmap(panel, wxID_ANY, bitmap); - sizer->Add(bitmap_widget, 0, wxBOTTOM, 3); - - sizer->AddSpacer(20); - - std::string model_id = model->id; - - for (const auto &variant : model->variants) { - std::string variant_name = variant.name; - auto *cbox = new wxCheckBox(panel, wxID_ANY, wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle")))); - bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant_name); - variants_checked += enabled; - cbox->SetValue(enabled); - sizer->Add(cbox, 0, wxBOTTOM, 3); - cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) { - this->variants_checked += event.IsChecked() ? 1 : -1; - this->on_variant_checked(); - AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; - appconfig_vendors.set_variant("PrusaResearch", model_id, variant_name, event.IsChecked()); - }); - } - - printer_grid->Add(panel); - } + printer_picker = new PrinterPicker(this, *vendor_prusa, appconfig_vendors); + printer_picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { + appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + this->on_variant_checked(); + }); append(printer_picker); } - { - auto *sizer = new wxBoxSizer(wxHORIZONTAL); - auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors"))); - // other_vendors->Disable(); // XXX - auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup"))); + const size_t num_other_vendors = vendors.size() - (vendor_prusa != vendors.cend()); + auto *sizer = new wxBoxSizer(wxHORIZONTAL); + auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors"))); + other_vendors->Enable(num_other_vendors > 0); + auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup"))); - sizer->Add(other_vendors); - sizer->AddSpacer(BTN_SPACING); - sizer->Add(custom_setup); + sizer->Add(other_vendors); + sizer->AddSpacer(BTN_SPACING); + sizer->Add(custom_setup); - other_vendors->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_other_vendors(); }); - custom_setup->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_custom_setup(); }); + other_vendors->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_other_vendors(); }); + custom_setup->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->wizard_p()->on_custom_setup(); }); - others_buttons->SetSizer(sizer); - } + others_buttons->SetSizer(sizer); } void PageWelcome::on_page_set() @@ -181,7 +222,7 @@ void PageWelcome::on_page_set() void PageWelcome::on_variant_checked() { - enable_next(variants_checked > 0); + enable_next(printer_picker != nullptr ? printer_picker->variants_checked > 0 : false); } PageUpdate::PageUpdate(ConfigWizard *parent) : @@ -208,35 +249,63 @@ PageUpdate::PageUpdate(ConfigWizard *parent) : PageVendors::PageVendors(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors"))) { + append_text(_(L("Pick another vendor supported by Slic3r PE:"))); + const PresetBundle &bundle = wizard_p()->bundle_vendors; auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); boldfont.SetWeight(wxFONTWEIGHT_BOLD); + AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; + wxArrayString choices_vendors; + for (const auto &vendor : bundle.vendors) { if (vendor.id == "PrusaResearch") { continue; } - auto *label_vendor = new wxStaticText(this, wxID_ANY, vendor.name); - label_vendor->SetFont(boldfont); - append(label_vendor, 0, 0, 0); + auto *picker = new PrinterPicker(this, vendor, appconfig_vendors); + picker->Hide(); + pickers.push_back(picker); + choices_vendors.Add(vendor.name); - for (const auto &model : vendor.models) { - auto *label_model = new wxStaticText(this, wxID_ANY, model.name); - label_model->SetFont(boldfont); - append(label_model, 0, wxLEFT, INDENT_SPACING); + picker->Bind(EVT_PRINTER_PICK, [this, &appconfig_vendors](const PrinterPickerEvent &evt) { + appconfig_vendors.set_variant(evt.vendor_id, evt.model_id, evt.variant_name, evt.enable); + this->on_variant_checked(); + }); + } - for (const auto &variant : model.variants) { - auto *cbox = new wxCheckBox(this, wxID_ANY, variant.name); - append(cbox, 0, wxEXPAND | wxLEFT, 2 * INDENT_SPACING); - cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { - // TODO - }); - } - } + auto *vendor_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices_vendors); + if (choices_vendors.GetCount() > 0) { + vendor_picker->SetSelection(0); + on_vendor_pick(0); + } - append_spacer(VERTICAL_SPACING); + vendor_picker->Bind(wxEVT_CHOICE, [this](wxCommandEvent &evt) { + this->on_vendor_pick(evt.GetInt()); + }); + + append(vendor_picker); + for (PrinterPicker *picker : pickers) { this->append(picker); } +} + +void PageVendors::on_page_set() +{ + on_variant_checked(); +} + +void PageVendors::on_vendor_pick(size_t i) +{ + for (PrinterPicker *picker : pickers) { picker->Hide(); } + if (i < pickers.size()) { + pickers[i]->Show(); + Layout(); } } +void PageVendors::on_variant_checked() +{ + size_t variants_checked = 0; + for (const PrinterPicker *picker : pickers) { variants_checked += picker->variants_checked; } + enable_next(variants_checked > 0); +} PageFirmware::PageFirmware(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware"))), @@ -613,7 +682,6 @@ ConfigWizard::ConfigWizard(wxWindow *parent) : p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); }); - // p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->on_finish(); }); p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->EndModal(wxID_OK); }); } diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index 1d9519bc3..9f9395975 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -29,6 +29,13 @@ enum { VERTICAL_SPACING = 10, }; +struct PrinterPicker: wxPanel +{ + unsigned variants_checked; + + PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors); +}; + struct ConfigWizardPage: wxPanel { enum { @@ -72,8 +79,8 @@ private: struct PageWelcome: ConfigWizardPage { + PrinterPicker *printer_picker; wxPanel *others_buttons; - unsigned variants_checked; PageWelcome(ConfigWizard *parent); @@ -93,7 +100,14 @@ struct PageUpdate: ConfigWizardPage struct PageVendors: ConfigWizardPage { + std::vector pickers; + PageVendors(ConfigWizard *parent); + + virtual void on_page_set(); + + void on_vendor_pick(size_t i); + void on_variant_checked(); }; struct PageFirmware: ConfigWizardPage From 9dcec6662e788a8ae0f04043581a1a3c44d36006 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 6 Apr 2018 12:15:28 +0200 Subject: [PATCH 06/10] ConfigWizard: Other vendor sample data, minor fixes --- resources/icons/printers/BarBaz_M1.png | Bin 0 -> 10369 bytes resources/icons/printers/BarBaz_M2.png | Bin 0 -> 10369 bytes resources/icons/printers/BarBaz_M3.png | Bin 0 -> 10369 bytes resources/icons/printers/Foobar_M1.png | Bin 0 -> 9323 bytes resources/icons/printers/Foobar_M2.png | Bin 0 -> 9323 bytes resources/icons/printers/Foobar_M3.png | Bin 0 -> 9323 bytes resources/profiles/BarBaz.ini | 985 +++++++++++++++++++++ resources/profiles/Foobar.ini | 985 +++++++++++++++++++++ xs/src/slic3r/GUI/AppConfig.cpp | 2 - xs/src/slic3r/GUI/AppConfig.hpp | 10 +- xs/src/slic3r/GUI/ConfigWizard.cpp | 21 +- xs/src/slic3r/GUI/ConfigWizard_private.hpp | 9 +- xs/xsp/my.map | 3 - 13 files changed, 1990 insertions(+), 25 deletions(-) create mode 100644 resources/icons/printers/BarBaz_M1.png create mode 100644 resources/icons/printers/BarBaz_M2.png create mode 100644 resources/icons/printers/BarBaz_M3.png create mode 100644 resources/icons/printers/Foobar_M1.png create mode 100644 resources/icons/printers/Foobar_M2.png create mode 100644 resources/icons/printers/Foobar_M3.png create mode 100644 resources/profiles/BarBaz.ini create mode 100644 resources/profiles/Foobar.ini diff --git a/resources/icons/printers/BarBaz_M1.png b/resources/icons/printers/BarBaz_M1.png new file mode 100644 index 0000000000000000000000000000000000000000..5924cc88b9ac373d5dc802ac06b82d1ad9d5015c GIT binary patch literal 10369 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 CbaD>> literal 0 HcmV?d00001 diff --git a/resources/icons/printers/Foobar_M2.png b/resources/icons/printers/Foobar_M2.png new file mode 100644 index 0000000000000000000000000000000000000000..61a76a63d1d3b39f402aea981f7adc11e346b389 GIT binary patch literal 9323 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 CbaD>> literal 0 HcmV?d00001 diff --git a/resources/icons/printers/Foobar_M3.png b/resources/icons/printers/Foobar_M3.png new file mode 100644 index 0000000000000000000000000000000000000000..61a76a63d1d3b39f402aea981f7adc11e346b389 GIT binary patch literal 9323 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 CbaD>> literal 0 HcmV?d00001 diff --git a/resources/profiles/BarBaz.ini b/resources/profiles/BarBaz.ini new file mode 100644 index 000000000..83bb15684 --- /dev/null +++ b/resources/profiles/BarBaz.ini @@ -0,0 +1,985 @@ +# Print profiles for the Prusa Research printers. + +[vendor] +# Vendor name will be shown by the Config Wizard. +name = Bar Baz +# Configuration version of this file. Config file will only be installed, if the config_version differs. +# This means, the server may force the Slic3r configuration to be downgraded. +config_version = 0.1 +# Where to get the updates from? +config_update_url = https://example.com + +# The printer models will be shown by the Configuration Wizard in this order, +# also the first model installed & the first nozzle installed will be activated after install. +#TODO: One day we may differentiate variants of the nozzles / hot ends, +#for example by the melt zone size, or whether the nozzle is hardened. +[printer_model:M1] +name = Bar Baz Model 1 +variants = 0.4; 0.25; 0.6 + +[printer_model:M2] +name = Bar Baz Model 2 +variants = 0.4; 0.25; 0.6 + +[printer_model:M3] +# Printer model name will be shown by the installation wizard. +name = Bar Baz Model 3 +variants = 0.4; 0.6 + +# All presets starting with asterisk, for example *common*, are intermediate and they will +# not make it into the user interface. + +# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle. +# All other print presets will derive from the *common* print preset. +[print:*common*] +avoid_crossing_perimeters = 0 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeters_first = 0 +external_perimeter_extrusion_width = 0.45 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +interface_shells = 0 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +overhangs = 0 +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +perimeters = 2 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirts = 1 +skirt_distance = 2 +skirt_height = 3 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_extruder = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_enforce_layers = 0 +support_material_contact_distance = 0.15 +support_material_interface_contact_loops = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 40 +travel_speed = 180 +wipe_tower = 0 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +# Print parameters common to a 0.25mm diameter nozzle. +[print:*0.25nozzle*] +external_perimeter_extrusion_width = 0.25 +extrusion_width = 0.25 +first_layer_extrusion_width = 0.25 +infill_extrusion_width = 0.25 +perimeter_extrusion_width = 0.25 +solid_infill_extrusion_width = 0.25 +top_infill_extrusion_width = 0.25 +support_material_extrusion_width = 0.18 +support_material_interface_layers = 0 +support_material_interface_spacing = 0.15 +support_material_spacing = 1 +support_material_xy_spacing = 150% + +# Print parameters common to a 0.6mm diameter nozzle. +[print:*0.6nozzle*] +external_perimeter_extrusion_width = 0.61 +extrusion_width = 0.67 +first_layer_extrusion_width = 0.65 +infill_extrusion_width = 0.7 +perimeter_extrusion_width = 0.65 +solid_infill_extrusion_width = 0.65 +top_infill_extrusion_width = 0.6 + +[print:*soluble_support*] +overhangs = 1 +skirts = 0 +support_material = 1 +support_material_contact_distance = 0 +support_material_extruder = 4 +support_material_extrusion_width = 0.45 +support_material_interface_extruder = 4 +support_material_interface_spacing = 0.1 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 1 +wipe_tower = 1 + +[print:*0.05mm*] +inherits = *common* +bottom_solid_layers = 10 +bridge_acceleration = 300 +bridge_flow_ratio = 0.7 +default_acceleration = 500 +external_perimeter_speed = 20 +fill_density = 20% +first_layer_acceleration = 500 +gap_fill_speed = 20 +infill_acceleration = 800 +infill_speed = 30 +max_print_speed = 80 +small_perimeter_speed = 15 +solid_infill_speed = 30 +support_material_extrusion_width = 0.3 +support_material_spacing = 1.5 +layer_height = 0.05 +perimeter_acceleration = 300 +perimeter_speed = 30 +perimeters = 3 +support_material_speed = 30 +top_solid_infill_speed = 20 +top_solid_layers = 15 + +[print:0.05mm ULTRADETAIL] +inherits = *0.05mm* +infill_extrusion_width = 0.5 + +[print:0.05mm ULTRADETAIL MK3] +inherits = *0.05mm* +fill_pattern = grid +top_infill_extrusion_width = 0.4 + +[print:0.05mm ULTRADETAIL 0.25 nozzle] +inherits = *0.05mm* +external_perimeter_extrusion_width = 0 +extrusion_width = 0.28 +fill_density = 20% +first_layer_extrusion_width = 0.3 +infill_extrusion_width = 0 +infill_speed = 20 +max_print_speed = 100 +perimeter_extrusion_width = 0 +perimeter_speed = 20 +small_perimeter_speed = 10 +solid_infill_extrusion_width = 0 +solid_infill_speed = 20 +support_material_speed = 20 +top_infill_extrusion_width = 0 + +[print:0.05mm ULTRADETAIL 0.25 nozzle MK3] +inherits = *0.05mm*; *0.25nozzle* +fill_pattern = grid +top_infill_extrusion_width = 0.4 + +[print:*0.10mm*] +inherits = *common* +bottom_solid_layers = 7 +bridge_flow_ratio = 0.7 +layer_height = 0.1 +perimeter_acceleration = 800 +top_solid_layers = 9 + +[print:0.10mm DETAIL] +inherits = *0.10mm* +external_perimeter_speed = 40 +infill_acceleration = 2000 +infill_speed = 60 +perimeter_speed = 50 +solid_infill_speed = 50 + +[print:0.10mm DETAIL MK3] +inherits = *0.10mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 170 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 + +[print:0.10mm DETAIL 0.25 nozzle] +inherits = *0.10mm* +bridge_acceleration = 600 +external_perimeter_speed = 20 +infill_acceleration = 1600 +infill_speed = 40 +perimeter_acceleration = 600 +perimeter_speed = 25 +small_perimeter_speed = 10 +solid_infill_speed = 40 +top_solid_infill_speed = 30 + +[print:0.10mm DETAIL 0.25 nozzle MK3] +inherits = *0.10mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 170 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 + +[print:0.10mm DETAIL 0.6 nozzle MK3] +inherits = *0.10mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 170 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 + +[print:*0.15mm*] +inherits = *common* +bottom_solid_layers = 5 +external_perimeter_speed = 40 +infill_acceleration = 2000 +infill_speed = 60 +layer_height = 0.15 +perimeter_acceleration = 800 +perimeter_speed = 50 +solid_infill_speed = 50 +top_infill_extrusion_width = 0.4 +top_solid_layers = 7 + +[print:0.15mm 100mms Linear Advance] +inherits = *0.15mm* +bridge_flow_ratio = 0.95 +external_perimeter_speed = 50 +infill_speed = 100 +max_print_speed = 150 +perimeter_speed = 60 +small_perimeter_speed = 30 +solid_infill_speed = 100 +support_material_speed = 60 +top_solid_infill_speed = 70 + +[print:0.15mm OPTIMAL] +inherits = *0.15mm* +top_infill_extrusion_width = 0.45 + +[print:0.15mm OPTIMAL 0.25 nozzle] +inherits = *0.15mm*; *0.25nozzle* +bridge_acceleration = 600 +bridge_flow_ratio = 0.7 +external_perimeter_speed = 20 +infill_acceleration = 1600 +infill_speed = 40 +perimeter_acceleration = 600 +perimeter_speed = 25 +small_perimeter_speed = 10 +solid_infill_speed = 40 +support_material_extrusion_width = 0.2 +top_solid_infill_speed = 30 + +[print:0.15mm OPTIMAL 0.6 nozzle] +inherits = *0.15mm*; *0.6nozzle* + +[print:0.15mm OPTIMAL MK3] +inherits = *0.15mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:0.15mm OPTIMAL SOLUBLE FULL] +inherits = *0.15mm*; *soluble_support* +external_perimeter_speed = 25 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +perimeter_speed = 40 +solid_infill_speed = 40 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 30 +wipe_tower = 1 + +[print:0.15mm OPTIMAL SOLUBLE INTERFACE] +inherits = 0.15mm OPTIMAL SOLUBLE FULL +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +support_material_extruder = 0 +support_material_interface_layers = 3 +support_material_with_sheath = 0 +support_material_xy_spacing = 80% + +[print:0.15mm OPTIMAL 0.25 nozzle MK3] +inherits = *0.15mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 +[print:*0.20mm*] +inherits = *common* +bottom_solid_layers = 4 +bridge_flow_ratio = 0.95 +external_perimeter_speed = 40 +infill_acceleration = 2000 +infill_speed = 60 +layer_height = 0.2 +perimeter_acceleration = 800 +perimeter_speed = 50 +solid_infill_speed = 50 +top_infill_extrusion_width = 0.4 +top_solid_layers = 5 + +[print:0.15mm OPTIMAL 0.6 nozzle MK3] +inherits = *0.15mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:0.20mm 100mms Linear Advance] +inherits = *0.20mm* +external_perimeter_speed = 50 +infill_speed = 100 +max_print_speed = 150 +perimeter_speed = 60 +small_perimeter_speed = 30 +solid_infill_speed = 100 +support_material_speed = 60 +top_solid_infill_speed = 70 + +[print:0.20mm FAST MK3] +inherits = *0.20mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:0.20mm NORMAL] +inherits = *0.20mm* + +[print:0.20mm NORMAL 0.6 nozzle] +inherits = *0.20mm*; *0.6nozzle* + +[print:0.20mm NORMAL SOLUBLE FULL] +inherits = *0.20mm*; *soluble_support* +external_perimeter_speed = 30 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +perimeter_speed = 40 +solid_infill_speed = 40 +top_solid_infill_speed = 30 + +[print:0.20mm NORMAL SOLUBLE INTERFACE] +inherits = 0.20mm NORMAL SOLUBLE FULL +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +support_material_extruder = 0 +support_material_interface_layers = 3 +support_material_with_sheath = 0 +support_material_xy_spacing = 80% + +[print:0.20mm FAST 0.6 nozzle MK3] +inherits = *0.20mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:*0.35mm*] +inherits = *common* +bottom_solid_layers = 3 +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 40 +first_layer_extrusion_width = 0.75 +infill_acceleration = 2000 +infill_speed = 60 +layer_height = 0.35 +perimeter_acceleration = 800 +perimeter_extrusion_width = 0.65 +perimeter_speed = 50 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 60 +top_solid_infill_speed = 50 +top_solid_layers = 4 + +[print:0.35mm FAST] +inherits = *0.35mm* +bridge_flow_ratio = 0.95 +first_layer_extrusion_width = 0.42 +perimeter_extrusion_width = 0.43 +solid_infill_extrusion_width = 0.7 +top_infill_extrusion_width = 0.43 + +[print:0.35mm FAST 0.6 nozzle] +inherits = *0.35mm*; *0.6nozzle* + +[print:0.35mm FAST sol full 0.6 nozzle] +inherits = *0.35mm*; *0.6nozzle*; *soluble_support* +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 30 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +perimeter_speed = 40 +support_material_extrusion_width = 0.55 +support_material_interface_layers = 3 +support_material_xy_spacing = 120% +top_infill_extrusion_width = 0.57 + +[print:0.35mm FAST sol int 0.6 nozzle] +inherits = 0.35mm FAST sol full 0.6 nozzle +support_material_extruder = 0 +support_material_interface_layers = 2 +support_material_with_sheath = 0 +support_material_xy_spacing = 150% + +[filament:*common*] +cooling = 1 +compatible_printers = +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +min_print_speed = 5 +slowdown_below_layer_time = 20 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" + +[filament:*PLA*] +inherits = *common* +bed_temperature = 60 +bridge_fan_speed = 100 +disable_fan_first_layers = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #FF3232 +filament_max_volumetric_speed = 15 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 100 +temperature = 210 + +[filament:*PET*] +inherits = *common* +bed_temperature = 90 +bridge_fan_speed = 50 +disable_fan_first_layers = 3 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_max_volumetric_speed = 8 +filament_type = PET +first_layer_bed_temperature = 85 +first_layer_temperature = 230 +max_fan_speed = 50 +min_fan_speed = 30 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:*ABS*] +inherits = *common* +bed_temperature = 110 +bridge_fan_speed = 30 +cooling = 0 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_max_volumetric_speed = 11 +filament_type = ABS +first_layer_bed_temperature = 100 +first_layer_temperature = 255 +max_fan_speed = 30 +min_fan_speed = 20 +temperature = 255 + +[filament:*FLEX*] +inherits = *common* +bridge_fan_speed = 100 +cooling = 0 +disable_fan_first_layers = 1 +extrusion_multiplier = 1.2 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #00CA0A +filament_max_volumetric_speed = 1.5 +filament_type = FLEX +first_layer_bed_temperature = 50 +first_layer_temperature = 240 +max_fan_speed = 90 +min_fan_speed = 70 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 240 + +[filament:ColorFabb Brass Bronze] +inherits = *PLA* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 10 + +[filament:ColorFabb HT] +inherits = *PET* +bed_temperature = 110 +bridge_fan_speed = 30 +cooling = 1 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 10 +first_layer_bed_temperature = 105 +first_layer_temperature = 270 +max_fan_speed = 20 +min_fan_speed = 10 +min_print_speed = 5 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 270 + +[filament:ColorFabb PLA-PHA] +inherits = *PLA* + +[filament:ColorFabb Woodfil] +inherits = *PLA* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 10 +first_layer_temperature = 200 +min_print_speed = 5 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 200 + +[filament:ColorFabb XT] +inherits = *PET* +filament_type = PLA +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +temperature = 270 + +[filament:ColorFabb XT-CF20] +inherits = *PET* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 1 +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 260 + +[filament:ColorFabb nGen] +inherits = *PET* +bridge_fan_speed = 40 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_type = NGEN +first_layer_temperature = 240 +max_fan_speed = 35 +min_fan_speed = 20 + +[filament:ColorFabb nGen flex] +inherits = *FLEX* +bed_temperature = 85 +bridge_fan_speed = 40 +cooling = 1 +disable_fan_first_layers = 3 +extrusion_multiplier = 1 +fan_below_layer_time = 10 +filament_max_volumetric_speed = 5 +first_layer_bed_temperature = 85 +first_layer_temperature = 260 +max_fan_speed = 35 +min_fan_speed = 20 +temperature = 260 + +[filament:E3D Edge] +inherits = *PET* +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" + +[filament:E3D PC-ABS] +inherits = *ABS* +first_layer_temperature = 270 +temperature = 270 + +[filament:Fillamentum ABS] +inherits = *ABS* +first_layer_temperature = 240 +temperature = 240 + +[filament:Fillamentum ASA] +inherits = *ABS* +fan_always_on = 1 +first_layer_temperature = 265 +temperature = 265 + +[filament:Fillamentum CPE HG100 HM100] +inherits = *PET* +filament_notes = "CPE HG100 , CPE HM100" +first_layer_bed_temperature = 90 +first_layer_temperature = 275 +max_fan_speed = 50 +min_fan_speed = 50 +temperature = 275 + +[filament:Fillamentum Timberfil] +inherits = *PLA* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 10 +first_layer_temperature = 190 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 190 + +[filament:Generic ABS] +inherits = *ABS* +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" + +[filament:Generic PET] +inherits = *PET* +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" + +[filament:Generic PLA] +inherits = *PLA* +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" + +[filament:Polymaker PC-Max] +inherits = *ABS* +bed_temperature = 115 +filament_colour = #3A80CA +first_layer_bed_temperature = 100 +first_layer_temperature = 270 +temperature = 270 + +[filament:Primavalue PVA] +inherits = *PLA* +cooling = 0 +fan_always_on = 0 +filament_colour = #FFFFD7 +filament_max_volumetric_speed = 10 +filament_notes = "List of materials tested with standart PVA print settings for MK2:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH" +filament_soluble = 1 +filament_type = PVA +first_layer_temperature = 195 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 195 + +[filament:Prusa ABS] +inherits = *ABS* +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" + +[filament:Prusa HIPS] +inherits = *ABS* +bridge_fan_speed = 50 +cooling = 1 +extrusion_multiplier = 0.9 +fan_always_on = 1 +fan_below_layer_time = 10 +filament_colour = #FFFFD7 +filament_soluble = 1 +filament_type = HIPS +first_layer_temperature = 220 +max_fan_speed = 20 +min_fan_speed = 20 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 220 + +[filament:Prusa PET] +inherits = *PET* +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" + +[filament:Prusa PLA] +inherits = *PLA* +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" + +[filament:SemiFlex or Flexfill 98A] +inherits = *FLEX* + +[filament:Taulman Bridge] +inherits = *common* +bed_temperature = 90 +bridge_fan_speed = 40 +cooling = 0 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #DEE0E6 +filament_max_volumetric_speed = 10 +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 60 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +min_print_speed = 5 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 250 + +[filament:Taulman T-Glase] +inherits = *PET* +bridge_fan_speed = 40 +cooling = 0 +fan_always_on = 0 +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" + +[filament:Verbatim BVOH] +inherits = *common* +bed_temperature = 60 +bridge_fan_speed = 100 +cooling = 0 +disable_fan_first_layers = 1 +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #FFFFD7 +filament_max_volumetric_speed = 10 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_soluble = 1 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 100 +min_print_speed = 15 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 210 + +[filament:Verbatim PP] +inherits = *common* +bed_temperature = 100 +bridge_fan_speed = 100 +cooling = 1 +disable_fan_first_layers = 2 +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #DEE0E6 +filament_max_volumetric_speed = 5 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA" +filament_type = PLA +first_layer_bed_temperature = 100 +first_layer_temperature = 220 +max_fan_speed = 100 +min_fan_speed = 100 +min_print_speed = 15 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 220 + +[printer:*common*] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 0 +end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +extruder_colour = #FFFF00 +extruder_offset = 0x0 +gcode_flavor = marlin +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25 +min_layer_height = 0.07 +nozzle_diameter = 0.4 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\n +printer_settings_id = +retract_before_travel = 1 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 0.8 +retract_length_toolchange = 4 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 35 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 +printer_model = M2 +printer_variant = 0.4 +default_print_profile = 0.15mm OPTIMAL +default_filament_profile = Prusa PLA + +[printer:*multimaterial*] +inherits = *common* +deretract_speed = 50 +retract_before_travel = 3 +retract_before_wipe = 60% +retract_layer_change = 0 +retract_length = 4 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 80 +single_extruder_multi_material = 1 +printer_model = M3 + +[printer:*mm-single*] +inherits = *multimaterial* +end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0 + +[printer:*mm-multi*] +inherits = *multimaterial* +end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes.\nG1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\n{endif}\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors +extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259 +nozzle_diameter = 0.4,0.4,0.4,0.4 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0 +variable_layer_height = 0 + +[printer:Original Prusa i3 MK2] +inherits = *common* + +[printer:Original Prusa i3 MK2 0.25 nozzle] +inherits = *common* +max_layer_height = 0.1 +min_layer_height = 0.05 +nozzle_diameter = 0.25 +retract_length = 1 +retract_speed = 50 +variable_layer_height = 0 +printer_variant = 0.25 +default_print_profile = 0.10mm DETAIL 0.25 nozzle + +[printer:Original Prusa i3 MK2 0.6 nozzle] +inherits = *common* +max_layer_height = 0.35 +min_layer_height = 0.1 +nozzle_diameter = 0.6 +printer_variant = 0.6 + +[printer:Original Prusa i3 MK2 MM Single Mode] +inherits = *mm-single* + +[printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle] +inherits = *mm-single* +nozzle_diameter = 0.6 +printer_variant = 0.6 + +[printer:Original Prusa i3 MK2 MultiMaterial] +inherits = *mm-multi* +nozzle_diameter = 0.4,0.4,0.4,0.4 + +[printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle] +inherits = *mm-multi* +nozzle_diameter = 0.6,0.6,0.6,0.6 +printer_variant = 0.6 + +[printer:Original Prusa i3 MK3] +inherits = *common* +end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_lift_below = 209 +start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +printer_model = M1 +default_print_profile = 0.15mm OPTIMAL MK3 + +[printer:Original Prusa i3 MK3 0.25 nozzle] +inherits = *common* +nozzle_diameter = 0.25 +printer_variant = 0.25 +end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_lift_below = 209 +start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +printer_model = M1 +default_print_profile = 0.10mm DETAIL MK3 + +[printer:Original Prusa i3 MK3 0.6 nozzle] +inherits = *common* +nozzle_diameter = 0.6 +printer_variant = 0.6 +end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_lift_below = 209 +start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +printer_model = M1 +default_print_profile = 0.15mm OPTIMAL MK3 diff --git a/resources/profiles/Foobar.ini b/resources/profiles/Foobar.ini new file mode 100644 index 000000000..21681398a --- /dev/null +++ b/resources/profiles/Foobar.ini @@ -0,0 +1,985 @@ +# Print profiles for the Prusa Research printers. + +[vendor] +# Vendor name will be shown by the Config Wizard. +name = Foo Bar +# Configuration version of this file. Config file will only be installed, if the config_version differs. +# This means, the server may force the Slic3r configuration to be downgraded. +config_version = 0.1 +# Where to get the updates from? +config_update_url = https://example.com + +# The printer models will be shown by the Configuration Wizard in this order, +# also the first model installed & the first nozzle installed will be activated after install. +#TODO: One day we may differentiate variants of the nozzles / hot ends, +#for example by the melt zone size, or whether the nozzle is hardened. +[printer_model:M1] +name = Foo Bar Model 1 +variants = 0.4; 0.25; 0.6 + +[printer_model:M2] +name = Foo Bar Model 2 +variants = 0.4; 0.25; 0.6 + +[printer_model:M3] +# Printer model name will be shown by the installation wizard. +name = Foo Bar Model 3 +variants = 0.4; 0.6 + +# All presets starting with asterisk, for example *common*, are intermediate and they will +# not make it into the user interface. + +# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle. +# All other print presets will derive from the *common* print preset. +[print:*common*] +avoid_crossing_perimeters = 0 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeters_first = 0 +external_perimeter_extrusion_width = 0.45 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +interface_shells = 0 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +overhangs = 0 +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +perimeters = 2 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirts = 1 +skirt_distance = 2 +skirt_height = 3 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_extruder = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_enforce_layers = 0 +support_material_contact_distance = 0.15 +support_material_interface_contact_loops = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 40 +travel_speed = 180 +wipe_tower = 0 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +# Print parameters common to a 0.25mm diameter nozzle. +[print:*0.25nozzle*] +external_perimeter_extrusion_width = 0.25 +extrusion_width = 0.25 +first_layer_extrusion_width = 0.25 +infill_extrusion_width = 0.25 +perimeter_extrusion_width = 0.25 +solid_infill_extrusion_width = 0.25 +top_infill_extrusion_width = 0.25 +support_material_extrusion_width = 0.18 +support_material_interface_layers = 0 +support_material_interface_spacing = 0.15 +support_material_spacing = 1 +support_material_xy_spacing = 150% + +# Print parameters common to a 0.6mm diameter nozzle. +[print:*0.6nozzle*] +external_perimeter_extrusion_width = 0.61 +extrusion_width = 0.67 +first_layer_extrusion_width = 0.65 +infill_extrusion_width = 0.7 +perimeter_extrusion_width = 0.65 +solid_infill_extrusion_width = 0.65 +top_infill_extrusion_width = 0.6 + +[print:*soluble_support*] +overhangs = 1 +skirts = 0 +support_material = 1 +support_material_contact_distance = 0 +support_material_extruder = 4 +support_material_extrusion_width = 0.45 +support_material_interface_extruder = 4 +support_material_interface_spacing = 0.1 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 1 +wipe_tower = 1 + +[print:*0.05mm*] +inherits = *common* +bottom_solid_layers = 10 +bridge_acceleration = 300 +bridge_flow_ratio = 0.7 +default_acceleration = 500 +external_perimeter_speed = 20 +fill_density = 20% +first_layer_acceleration = 500 +gap_fill_speed = 20 +infill_acceleration = 800 +infill_speed = 30 +max_print_speed = 80 +small_perimeter_speed = 15 +solid_infill_speed = 30 +support_material_extrusion_width = 0.3 +support_material_spacing = 1.5 +layer_height = 0.05 +perimeter_acceleration = 300 +perimeter_speed = 30 +perimeters = 3 +support_material_speed = 30 +top_solid_infill_speed = 20 +top_solid_layers = 15 + +[print:0.05mm ULTRADETAIL] +inherits = *0.05mm* +infill_extrusion_width = 0.5 + +[print:0.05mm ULTRADETAIL MK3] +inherits = *0.05mm* +fill_pattern = grid +top_infill_extrusion_width = 0.4 + +[print:0.05mm ULTRADETAIL 0.25 nozzle] +inherits = *0.05mm* +external_perimeter_extrusion_width = 0 +extrusion_width = 0.28 +fill_density = 20% +first_layer_extrusion_width = 0.3 +infill_extrusion_width = 0 +infill_speed = 20 +max_print_speed = 100 +perimeter_extrusion_width = 0 +perimeter_speed = 20 +small_perimeter_speed = 10 +solid_infill_extrusion_width = 0 +solid_infill_speed = 20 +support_material_speed = 20 +top_infill_extrusion_width = 0 + +[print:0.05mm ULTRADETAIL 0.25 nozzle MK3] +inherits = *0.05mm*; *0.25nozzle* +fill_pattern = grid +top_infill_extrusion_width = 0.4 + +[print:*0.10mm*] +inherits = *common* +bottom_solid_layers = 7 +bridge_flow_ratio = 0.7 +layer_height = 0.1 +perimeter_acceleration = 800 +top_solid_layers = 9 + +[print:0.10mm DETAIL] +inherits = *0.10mm* +external_perimeter_speed = 40 +infill_acceleration = 2000 +infill_speed = 60 +perimeter_speed = 50 +solid_infill_speed = 50 + +[print:0.10mm DETAIL MK3] +inherits = *0.10mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 170 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 + +[print:0.10mm DETAIL 0.25 nozzle] +inherits = *0.10mm* +bridge_acceleration = 600 +external_perimeter_speed = 20 +infill_acceleration = 1600 +infill_speed = 40 +perimeter_acceleration = 600 +perimeter_speed = 25 +small_perimeter_speed = 10 +solid_infill_speed = 40 +top_solid_infill_speed = 30 + +[print:0.10mm DETAIL 0.25 nozzle MK3] +inherits = *0.10mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 170 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 + +[print:0.10mm DETAIL 0.6 nozzle MK3] +inherits = *0.10mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 200 +perimeter_speed = 45 +solid_infill_speed = 170 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 + +[print:*0.15mm*] +inherits = *common* +bottom_solid_layers = 5 +external_perimeter_speed = 40 +infill_acceleration = 2000 +infill_speed = 60 +layer_height = 0.15 +perimeter_acceleration = 800 +perimeter_speed = 50 +solid_infill_speed = 50 +top_infill_extrusion_width = 0.4 +top_solid_layers = 7 + +[print:0.15mm 100mms Linear Advance] +inherits = *0.15mm* +bridge_flow_ratio = 0.95 +external_perimeter_speed = 50 +infill_speed = 100 +max_print_speed = 150 +perimeter_speed = 60 +small_perimeter_speed = 30 +solid_infill_speed = 100 +support_material_speed = 60 +top_solid_infill_speed = 70 + +[print:0.15mm OPTIMAL] +inherits = *0.15mm* +top_infill_extrusion_width = 0.45 + +[print:0.15mm OPTIMAL 0.25 nozzle] +inherits = *0.15mm*; *0.25nozzle* +bridge_acceleration = 600 +bridge_flow_ratio = 0.7 +external_perimeter_speed = 20 +infill_acceleration = 1600 +infill_speed = 40 +perimeter_acceleration = 600 +perimeter_speed = 25 +small_perimeter_speed = 10 +solid_infill_speed = 40 +support_material_extrusion_width = 0.2 +top_solid_infill_speed = 30 + +[print:0.15mm OPTIMAL 0.6 nozzle] +inherits = *0.15mm*; *0.6nozzle* + +[print:0.15mm OPTIMAL MK3] +inherits = *0.15mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:0.15mm OPTIMAL SOLUBLE FULL] +inherits = *0.15mm*; *soluble_support* +external_perimeter_speed = 25 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +perimeter_speed = 40 +solid_infill_speed = 40 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 30 +wipe_tower = 1 + +[print:0.15mm OPTIMAL SOLUBLE INTERFACE] +inherits = 0.15mm OPTIMAL SOLUBLE FULL +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +support_material_extruder = 0 +support_material_interface_layers = 3 +support_material_with_sheath = 0 +support_material_xy_spacing = 80% + +[print:0.15mm OPTIMAL 0.25 nozzle MK3] +inherits = *0.15mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 +[print:*0.20mm*] +inherits = *common* +bottom_solid_layers = 4 +bridge_flow_ratio = 0.95 +external_perimeter_speed = 40 +infill_acceleration = 2000 +infill_speed = 60 +layer_height = 0.2 +perimeter_acceleration = 800 +perimeter_speed = 50 +solid_infill_speed = 50 +top_infill_extrusion_width = 0.4 +top_solid_layers = 5 + +[print:0.15mm OPTIMAL 0.6 nozzle MK3] +inherits = *0.15mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:0.20mm 100mms Linear Advance] +inherits = *0.20mm* +external_perimeter_speed = 50 +infill_speed = 100 +max_print_speed = 150 +perimeter_speed = 60 +small_perimeter_speed = 30 +solid_infill_speed = 100 +support_material_speed = 60 +top_solid_infill_speed = 70 + +[print:0.20mm FAST MK3] +inherits = *0.20mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:0.20mm NORMAL] +inherits = *0.20mm* + +[print:0.20mm NORMAL 0.6 nozzle] +inherits = *0.20mm*; *0.6nozzle* + +[print:0.20mm NORMAL SOLUBLE FULL] +inherits = *0.20mm*; *soluble_support* +external_perimeter_speed = 30 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +perimeter_speed = 40 +solid_infill_speed = 40 +top_solid_infill_speed = 30 + +[print:0.20mm NORMAL SOLUBLE INTERFACE] +inherits = 0.20mm NORMAL SOLUBLE FULL +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +support_material_extruder = 0 +support_material_interface_layers = 3 +support_material_with_sheath = 0 +support_material_xy_spacing = 80% + +[print:0.20mm FAST 0.6 nozzle MK3] +inherits = *0.20mm* +bridge_speed = 30 +external_perimeter_speed = 35 +fill_pattern = grid +infill_acceleration = 1500 +infill_speed = 170 +max_print_speed = 170 +perimeter_speed = 45 +solid_infill_speed = 170 +top_solid_infill_speed = 50 + +[print:*0.35mm*] +inherits = *common* +bottom_solid_layers = 3 +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 40 +first_layer_extrusion_width = 0.75 +infill_acceleration = 2000 +infill_speed = 60 +layer_height = 0.35 +perimeter_acceleration = 800 +perimeter_extrusion_width = 0.65 +perimeter_speed = 50 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 60 +top_solid_infill_speed = 50 +top_solid_layers = 4 + +[print:0.35mm FAST] +inherits = *0.35mm* +bridge_flow_ratio = 0.95 +first_layer_extrusion_width = 0.42 +perimeter_extrusion_width = 0.43 +solid_infill_extrusion_width = 0.7 +top_infill_extrusion_width = 0.43 + +[print:0.35mm FAST 0.6 nozzle] +inherits = *0.35mm*; *0.6nozzle* + +[print:0.35mm FAST sol full 0.6 nozzle] +inherits = *0.35mm*; *0.6nozzle*; *soluble_support* +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 30 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +perimeter_speed = 40 +support_material_extrusion_width = 0.55 +support_material_interface_layers = 3 +support_material_xy_spacing = 120% +top_infill_extrusion_width = 0.57 + +[print:0.35mm FAST sol int 0.6 nozzle] +inherits = 0.35mm FAST sol full 0.6 nozzle +support_material_extruder = 0 +support_material_interface_layers = 2 +support_material_with_sheath = 0 +support_material_xy_spacing = 150% + +[filament:*common*] +cooling = 1 +compatible_printers = +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +min_print_speed = 5 +slowdown_below_layer_time = 20 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" + +[filament:*PLA*] +inherits = *common* +bed_temperature = 60 +bridge_fan_speed = 100 +disable_fan_first_layers = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #FF3232 +filament_max_volumetric_speed = 15 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 100 +temperature = 210 + +[filament:*PET*] +inherits = *common* +bed_temperature = 90 +bridge_fan_speed = 50 +disable_fan_first_layers = 3 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_max_volumetric_speed = 8 +filament_type = PET +first_layer_bed_temperature = 85 +first_layer_temperature = 230 +max_fan_speed = 50 +min_fan_speed = 30 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:*ABS*] +inherits = *common* +bed_temperature = 110 +bridge_fan_speed = 30 +cooling = 0 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_max_volumetric_speed = 11 +filament_type = ABS +first_layer_bed_temperature = 100 +first_layer_temperature = 255 +max_fan_speed = 30 +min_fan_speed = 20 +temperature = 255 + +[filament:*FLEX*] +inherits = *common* +bridge_fan_speed = 100 +cooling = 0 +disable_fan_first_layers = 1 +extrusion_multiplier = 1.2 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #00CA0A +filament_max_volumetric_speed = 1.5 +filament_type = FLEX +first_layer_bed_temperature = 50 +first_layer_temperature = 240 +max_fan_speed = 90 +min_fan_speed = 70 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 240 + +[filament:ColorFabb Brass Bronze] +inherits = *PLA* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 10 + +[filament:ColorFabb HT] +inherits = *PET* +bed_temperature = 110 +bridge_fan_speed = 30 +cooling = 1 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 10 +first_layer_bed_temperature = 105 +first_layer_temperature = 270 +max_fan_speed = 20 +min_fan_speed = 10 +min_print_speed = 5 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 270 + +[filament:ColorFabb PLA-PHA] +inherits = *PLA* + +[filament:ColorFabb Woodfil] +inherits = *PLA* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 10 +first_layer_temperature = 200 +min_print_speed = 5 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 200 + +[filament:ColorFabb XT] +inherits = *PET* +filament_type = PLA +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +temperature = 270 + +[filament:ColorFabb XT-CF20] +inherits = *PET* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 1 +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 260 + +[filament:ColorFabb nGen] +inherits = *PET* +bridge_fan_speed = 40 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_type = NGEN +first_layer_temperature = 240 +max_fan_speed = 35 +min_fan_speed = 20 + +[filament:ColorFabb nGen flex] +inherits = *FLEX* +bed_temperature = 85 +bridge_fan_speed = 40 +cooling = 1 +disable_fan_first_layers = 3 +extrusion_multiplier = 1 +fan_below_layer_time = 10 +filament_max_volumetric_speed = 5 +first_layer_bed_temperature = 85 +first_layer_temperature = 260 +max_fan_speed = 35 +min_fan_speed = 20 +temperature = 260 + +[filament:E3D Edge] +inherits = *PET* +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" + +[filament:E3D PC-ABS] +inherits = *ABS* +first_layer_temperature = 270 +temperature = 270 + +[filament:Fillamentum ABS] +inherits = *ABS* +first_layer_temperature = 240 +temperature = 240 + +[filament:Fillamentum ASA] +inherits = *ABS* +fan_always_on = 1 +first_layer_temperature = 265 +temperature = 265 + +[filament:Fillamentum CPE HG100 HM100] +inherits = *PET* +filament_notes = "CPE HG100 , CPE HM100" +first_layer_bed_temperature = 90 +first_layer_temperature = 275 +max_fan_speed = 50 +min_fan_speed = 50 +temperature = 275 + +[filament:Fillamentum Timberfil] +inherits = *PLA* +extrusion_multiplier = 1.2 +filament_colour = #804040 +filament_max_volumetric_speed = 10 +first_layer_temperature = 190 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 190 + +[filament:Generic ABS] +inherits = *ABS* +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" + +[filament:Generic PET] +inherits = *PET* +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" + +[filament:Generic PLA] +inherits = *PLA* +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" + +[filament:Polymaker PC-Max] +inherits = *ABS* +bed_temperature = 115 +filament_colour = #3A80CA +first_layer_bed_temperature = 100 +first_layer_temperature = 270 +temperature = 270 + +[filament:Primavalue PVA] +inherits = *PLA* +cooling = 0 +fan_always_on = 0 +filament_colour = #FFFFD7 +filament_max_volumetric_speed = 10 +filament_notes = "List of materials tested with standart PVA print settings for MK2:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH" +filament_soluble = 1 +filament_type = PVA +first_layer_temperature = 195 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 195 + +[filament:Prusa ABS] +inherits = *ABS* +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" + +[filament:Prusa HIPS] +inherits = *ABS* +bridge_fan_speed = 50 +cooling = 1 +extrusion_multiplier = 0.9 +fan_always_on = 1 +fan_below_layer_time = 10 +filament_colour = #FFFFD7 +filament_soluble = 1 +filament_type = HIPS +first_layer_temperature = 220 +max_fan_speed = 20 +min_fan_speed = 20 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 220 + +[filament:Prusa PET] +inherits = *PET* +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" + +[filament:Prusa PLA] +inherits = *PLA* +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" + +[filament:SemiFlex or Flexfill 98A] +inherits = *FLEX* + +[filament:Taulman Bridge] +inherits = *common* +bed_temperature = 90 +bridge_fan_speed = 40 +cooling = 0 +disable_fan_first_layers = 3 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #DEE0E6 +filament_max_volumetric_speed = 10 +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 60 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +min_print_speed = 5 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 250 + +[filament:Taulman T-Glase] +inherits = *PET* +bridge_fan_speed = 40 +cooling = 0 +fan_always_on = 0 +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" + +[filament:Verbatim BVOH] +inherits = *common* +bed_temperature = 60 +bridge_fan_speed = 100 +cooling = 0 +disable_fan_first_layers = 1 +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #FFFFD7 +filament_max_volumetric_speed = 10 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_soluble = 1 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 100 +min_print_speed = 15 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 210 + +[filament:Verbatim PP] +inherits = *common* +bed_temperature = 100 +bridge_fan_speed = 100 +cooling = 1 +disable_fan_first_layers = 2 +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #DEE0E6 +filament_max_volumetric_speed = 5 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA" +filament_type = PLA +first_layer_bed_temperature = 100 +first_layer_temperature = 220 +max_fan_speed = 100 +min_fan_speed = 100 +min_print_speed = 15 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 220 + +[printer:*common*] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 0 +end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +extruder_colour = #FFFF00 +extruder_offset = 0x0 +gcode_flavor = marlin +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25 +min_layer_height = 0.07 +nozzle_diameter = 0.4 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\n +printer_settings_id = +retract_before_travel = 1 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 0.8 +retract_length_toolchange = 4 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 35 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 +printer_model = M2 +printer_variant = 0.4 +default_print_profile = 0.15mm OPTIMAL +default_filament_profile = Prusa PLA + +[printer:*multimaterial*] +inherits = *common* +deretract_speed = 50 +retract_before_travel = 3 +retract_before_wipe = 60% +retract_layer_change = 0 +retract_length = 4 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 80 +single_extruder_multi_material = 1 +printer_model = M3 + +[printer:*mm-single*] +inherits = *multimaterial* +end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0 + +[printer:*mm-multi*] +inherits = *multimaterial* +end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes.\nG1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\n{endif}\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors +extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259 +nozzle_diameter = 0.4,0.4,0.4,0.4 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM201 X9000 Y9000 Z500 E10000 ; sets maximum accelerations, mm/sec^2\nM203 X500 Y500 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1500 T1500 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.2 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0 +variable_layer_height = 0 + +[printer:Original Prusa i3 MK2] +inherits = *common* + +[printer:Original Prusa i3 MK2 0.25 nozzle] +inherits = *common* +max_layer_height = 0.1 +min_layer_height = 0.05 +nozzle_diameter = 0.25 +retract_length = 1 +retract_speed = 50 +variable_layer_height = 0 +printer_variant = 0.25 +default_print_profile = 0.10mm DETAIL 0.25 nozzle + +[printer:Original Prusa i3 MK2 0.6 nozzle] +inherits = *common* +max_layer_height = 0.35 +min_layer_height = 0.1 +nozzle_diameter = 0.6 +printer_variant = 0.6 + +[printer:Original Prusa i3 MK2 MM Single Mode] +inherits = *mm-single* + +[printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle] +inherits = *mm-single* +nozzle_diameter = 0.6 +printer_variant = 0.6 + +[printer:Original Prusa i3 MK2 MultiMaterial] +inherits = *mm-multi* +nozzle_diameter = 0.4,0.4,0.4,0.4 + +[printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle] +inherits = *mm-multi* +nozzle_diameter = 0.6,0.6,0.6,0.6 +printer_variant = 0.6 + +[printer:Original Prusa i3 MK3] +inherits = *common* +end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_lift_below = 209 +start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +printer_model = M1 +default_print_profile = 0.15mm OPTIMAL MK3 + +[printer:Original Prusa i3 MK3 0.25 nozzle] +inherits = *common* +nozzle_diameter = 0.25 +printer_variant = 0.25 +end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_lift_below = 209 +start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +printer_model = M1 +default_print_profile = 0.10mm DETAIL MK3 + +[printer:Original Prusa i3 MK3 0.6 nozzle] +inherits = *common* +nozzle_diameter = 0.6 +printer_variant = 0.6 +end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_lift_below = 209 +start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +printer_model = M1 +default_print_profile = 0.15mm OPTIMAL MK3 diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index 10a586e27..9e5ce5f1b 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -135,8 +135,6 @@ void AppConfig::save() bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const { - // std::cerr << "AppConfig::get_variant(" << vendor << ", " << model << ", " << variant << ") " << std::endl; - const auto it_v = m_vendors.find(vendor); if (it_v == m_vendors.end()) { return false; } const auto it_m = it_v->second.find(model); diff --git a/xs/src/slic3r/GUI/AppConfig.hpp b/xs/src/slic3r/GUI/AppConfig.hpp index e43ff51bf..7aac95fd6 100644 --- a/xs/src/slic3r/GUI/AppConfig.hpp +++ b/xs/src/slic3r/GUI/AppConfig.hpp @@ -68,9 +68,9 @@ public: void clear_section(const std::string §ion) { m_storage[section].clear(); } - bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const; - void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); - void set_vendors(const AppConfig &from); + bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const; + void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable); + void set_vendors(const AppConfig &from); // return recent/skein_directory or recent/config_directory or empty string. std::string get_last_dir() const; @@ -86,8 +86,8 @@ public: void reset_selections(); // Whether the Slic3r version available online differs from this one - bool version_check_enabled() const; - bool slic3r_update_avail() const; + bool version_check_enabled() const; + bool slic3r_update_avail() const; // Get the default config path from Slic3r::data_dir(). static std::string config_path(); diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index 914ebb9a1..ce51d7641 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -1,6 +1,5 @@ #include "ConfigWizard_private.hpp" -#include // XXX #include #include #include @@ -23,9 +22,6 @@ namespace Slic3r { namespace GUI { -// FIXME: scrolling - - // Printer model picker GUI control struct PrinterPickerEvent : public wxEvent @@ -296,7 +292,7 @@ void PageVendors::on_vendor_pick(size_t i) for (PrinterPicker *picker : pickers) { picker->Hide(); } if (i < pickers.size()) { pickers[i]->Show(); - Layout(); + wizard_p()->layout_fit(); } } @@ -352,7 +348,7 @@ PageBedShape::PageBedShape(ConfigWizard *parent) : { append_text(_(L("Set the shape of your printer's bed."))); - shape_panel->build_panel(wizard_p()->custom_config.option("bed_shape")); + shape_panel->build_panel(wizard_p()->custom_config->option("bed_shape")); append(shape_panel); } @@ -583,7 +579,13 @@ void ConfigWizard::priv::set_page(ConfigWizardPage *page) btn_next->Show(page->page_next() != nullptr); btn_finish->Show(page->page_next() == nullptr); + layout_fit(); +} + +void ConfigWizard::priv::layout_fit() +{ q->Layout(); + q->Fit(); } void ConfigWizard::priv::enable_next(bool enable) @@ -619,9 +621,9 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese preset_bundle->load_presets(*app_config); } else { for (ConfigWizardPage *page = page_firmware; page != nullptr; page = page->page_next()) { - page->apply_custom_config(custom_config); + page->apply_custom_config(*custom_config); } - preset_bundle->load_config("My Settings", custom_config); + preset_bundle->load_config("My Settings", *custom_config); } } @@ -632,10 +634,9 @@ ConfigWizard::ConfigWizard(wxWindow *parent) : p(new priv(this)) { p->load_vendors(); - std::unique_ptr custom_config_defaults(DynamicPrintConfig::new_from_defaults_keys({ + p->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({ "gcode_flavor", "bed_shape", "nozzle_diameter", "filament_diameter", "temperature", "bed_temperature", })); - p->custom_config.apply(*custom_config_defaults); p->index = new ConfigWizardIndex(this); diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index 9f9395975..d32a609be 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -22,6 +22,8 @@ namespace GUI { enum { + CONTENT_WIDTH = 500, + DIALOG_MARGIN = 15, INDEX_MARGIN = 40, BTN_SPACING = 10, @@ -38,10 +40,6 @@ struct PrinterPicker: wxPanel struct ConfigWizardPage: wxPanel { - enum { - CONTENT_WIDTH = 500, - }; - ConfigWizard *parent; const wxString shortname; wxBoxSizer *content; @@ -171,7 +169,7 @@ struct ConfigWizard::priv ConfigWizard *q; AppConfig appconfig_vendors; PresetBundle bundle_vendors; - DynamicPrintConfig custom_config; + std::unique_ptr custom_config; wxBoxSizer *topsizer = nullptr; wxBoxSizer *btnsizer = nullptr; @@ -196,6 +194,7 @@ struct ConfigWizard::priv void add_page(ConfigWizardPage *page); void index_refresh(); void set_page(ConfigWizardPage *page); + void layout_fit(); void go_prev() { if (page_current != nullptr) { set_page(page_current->page_prev()); } } void go_next() { if (page_current != nullptr) { set_page(page_current->page_next()); } } void enable_next(bool enable); diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 9c0f60c1d..c1ca58827 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -235,9 +235,6 @@ PresetHints* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T TabIface* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T -# TODO: remove: -# ConfigWizard* O_OBJECT_SLIC3R -# Ref O_OBJECT_SLIC3R_T PresetUpdater* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T From 90a8ef8e9f208dce144cea4252173079fd0f830c Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 6 Apr 2018 13:18:12 +0200 Subject: [PATCH 07/10] Cleanup --- lib/Slic3r/GUI/MainFrame.pm | 44 +--------------------- resources/profiles/PrusaResearch.ini | 5 --- xs/src/slic3r/GUI/ConfigWizard.cpp | 15 +++++--- xs/src/slic3r/GUI/ConfigWizard.hpp | 3 +- xs/src/slic3r/GUI/ConfigWizard_private.hpp | 4 +- xs/src/slic3r/GUI/GUI.cpp | 4 +- xs/src/slic3r/GUI/GUI.hpp | 5 +-- xs/src/slic3r/GUI/Preset.cpp | 1 - xs/src/slic3r/GUI/Preset.hpp | 5 +-- xs/src/slic3r/GUI/PresetBundle.cpp | 6 +-- xs/xsp/GUI.xsp | 4 +- 11 files changed, 23 insertions(+), 73 deletions(-) diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 4307375c8..402cb8051 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -644,48 +644,8 @@ sub config_wizard { # Exit wizard if there are unsaved changes and the user cancels the action. return unless $self->check_unsaved_changes; - - # TODO: Offer "reset user profile" - Slic3r::GUI::open_config_wizard(wxTheApp->{preset_bundle}); - # Load the currently selected preset into the GUI, update the preset selection box. - foreach my $tab (values %{$self->{options_tabs}}) { # XXX: only if not cancelled? - $tab->load_current_preset; - } - return; - - # Enumerate the profiles bundled with the Slic3r installation under resources/profiles. - my $directory = Slic3r::resources_dir() . "/profiles"; - my @profiles = (); - if (opendir(DIR, Slic3r::encode_path($directory))) { - while (my $file = readdir(DIR)) { - if ($file =~ /\.ini$/) { - $file =~ s/\.ini$//; - push @profiles, Slic3r::decode_path($file); - } - } - closedir(DIR); - } - # Open the wizard. - if (my $result = Slic3r::GUI::ConfigWizard->new($self, \@profiles, $fresh_start)->run) { - eval { - if ($result->{reset_user_profile}) { - wxTheApp->{preset_bundle}->reset(1); - } - if (defined $result->{config}) { - # Load and save the settings into print, filament and printer presets. - wxTheApp->{preset_bundle}->load_config('My Settings', $result->{config}); - } else { - # Wizard returned a name of a preset bundle bundled with the installation. Unpack it. - wxTheApp->{preset_bundle}->install_vendor_configbundle($directory . '/' . $result->{preset_name} . '.ini'); - # Reset the print / filament / printer selections, so that following line will select some sensible defaults. - if ($fresh_start) { - wxTheApp->{app_config}->reset_selections; - } - # Reload all presets after the vendor config bundle has been installed. - wxTheApp->{preset_bundle}->load_presets(wxTheApp->{app_config}); - } - }; - Slic3r::GUI::catch_error($self) and return; + # TODO: Offer "reset user profile" ??? + if (Slic3r::GUI::open_config_wizard(wxTheApp->{preset_bundle})) { # Load the currently selected preset into the GUI, update the preset selection box. foreach my $tab (values %{$self->{options_tabs}}) { $tab->load_current_preset; diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 6dc29a96e..b654b4039 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -1017,8 +1017,3 @@ retract_lift_below = 209 start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} printer_model = MK3 default_print_profile = 0.15mm OPTIMAL MK3 - -[presets] -print = 0.15mm OPTIMAL MK3 -printer = Original Prusa i3 MK3 -filament = Prusa PLA diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index ce51d7641..032b5e903 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -412,16 +412,16 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) PageTemperatures::PageTemperatures(ConfigWizard *parent) : ConfigWizardPage(parent, _(L("Extruder and Bed Temperatures")), _(L("Temperatures"))), - spin_extr(new wxSpinCtrl(this, wxID_ANY)), - spin_bed(new wxSpinCtrl(this, wxID_ANY)) + spin_extr(new wxSpinCtrlDouble(this, wxID_ANY)), + spin_bed(new wxSpinCtrlDouble(this, wxID_ANY)) { - spin_extr->SetIncrement(5); + spin_extr->SetIncrement(5.0); const auto &def_extr = print_config_def.options["temperature"]; spin_extr->SetRange(def_extr.min, def_extr.max); auto *default_extr = dynamic_cast(def_extr.default_value); spin_extr->SetValue(default_extr != nullptr && default_extr->size() > 0 ? default_extr->get_at(0) : 200); - spin_bed->SetIncrement(5); + spin_bed->SetIncrement(5.0); const auto &def_bed = print_config_def.options["bed_temperature"]; spin_bed->SetRange(def_bed.min, def_bed.max); auto *default_bed = dynamic_cast(def_bed.default_value); @@ -541,7 +541,7 @@ void ConfigWizard::priv::load_vendors() const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor"; for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) { if (it->path().extension() == ".ini") { - bundle_vendors.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); + bundle_vendors.load_configbundle(it->path().string(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); } } @@ -688,7 +688,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent) : ConfigWizard::~ConfigWizard() {} -void ConfigWizard::run(wxWindow *parent, PresetBundle *preset_bundle) +bool ConfigWizard::run(wxWindow *parent, PresetBundle *preset_bundle) { const auto profiles_dir = fs::path(resources_dir()) / "profiles"; for (fs::directory_iterator it(profiles_dir); it != fs::directory_iterator(); ++it) { @@ -700,6 +700,9 @@ void ConfigWizard::run(wxWindow *parent, PresetBundle *preset_bundle) ConfigWizard wizard(parent); if (wizard.ShowModal() == wxID_OK) { wizard.p->apply_config(GUI::get_app_config(), preset_bundle); + return true; + } else { + return false; } } diff --git a/xs/src/slic3r/GUI/ConfigWizard.hpp b/xs/src/slic3r/GUI/ConfigWizard.hpp index a06388396..40ecf09a1 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard.hpp @@ -15,7 +15,6 @@ namespace GUI { class ConfigWizard: public wxDialog { public: - // ConfigWizard(wxWindow *parent, const PresetBundle &bundle); ConfigWizard(wxWindow *parent); ConfigWizard(ConfigWizard &&) = delete; ConfigWizard(const ConfigWizard &) = delete; @@ -23,7 +22,7 @@ public: ConfigWizard &operator=(const ConfigWizard &) = delete; ~ConfigWizard(); - static void run(wxWindow *parent, PresetBundle *preset_bundle); + static bool run(wxWindow *parent, PresetBundle *preset_bundle); private: struct priv; std::unique_ptr p; diff --git a/xs/src/slic3r/GUI/ConfigWizard_private.hpp b/xs/src/slic3r/GUI/ConfigWizard_private.hpp index d32a609be..652328aaa 100644 --- a/xs/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/xs/src/slic3r/GUI/ConfigWizard_private.hpp @@ -136,8 +136,8 @@ struct PageDiameters: ConfigWizardPage struct PageTemperatures: ConfigWizardPage { - wxSpinCtrl *spin_extr; - wxSpinCtrl *spin_bed; + wxSpinCtrlDouble *spin_extr; + wxSpinCtrlDouble *spin_bed; PageTemperatures(ConfigWizard *parent); virtual void apply_custom_config(DynamicPrintConfig &config); diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 80e232287..310860e53 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -353,13 +353,13 @@ void add_debug_menu(wxMenuBar *menu, int event_language_change) //#endif } -void open_config_wizard(PresetBundle *preset_bundle) +bool open_config_wizard(PresetBundle *preset_bundle) { if (g_wxMainFrame == nullptr) { throw std::runtime_error("Main frame not set"); } - ConfigWizard::run(g_wxMainFrame, preset_bundle); + return ConfigWizard::run(g_wxMainFrame, preset_bundle); } void open_preferences_dialog(int event_preferences) diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 98a124091..321c97d36 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -73,7 +73,6 @@ void break_to_debugger(); // Passing the wxWidgets GUI classes instantiated by the Perl part to C++. void set_wxapp(wxApp *app); void set_main_frame(wxFrame *main_frame); -// wxFrame* get_main_frame(); void set_tab_panel(wxNotebook *tab_panel); void set_app_config(AppConfig *app_config); void set_preset_bundle(PresetBundle *preset_bundle); @@ -85,8 +84,8 @@ wxColour* get_sys_label_clr(); void add_debug_menu(wxMenuBar *menu, int event_language_change); -// Opens the first-time configuration wizard -void open_config_wizard(PresetBundle *preset_bundle); +// Opens the first-time configuration wizard, returns true if wizard is finished & accepted. +bool open_config_wizard(PresetBundle *preset_bundle); // Create "Preferences" dialog after selecting menu "Preferences" in Perl part void open_preferences_dialog(int event_preferences); diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 40afca144..66836074e 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -183,7 +183,6 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config) const std::string &variant = config.opt_string("printer_variant"); if (model.empty() || variant.empty()) { return; } is_visible = app_config.get_variant(vendor->id, model, variant); - std::cerr << vendor->id << " / " << model << " / " << variant << ": visible: " << is_visible << std::endl; } const std::vector& Preset::print_options() diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index 075eed9af..4f734b85e 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -37,14 +37,12 @@ public: PrinterVariant() {} PrinterVariant(const std::string &name) : name(name) {} std::string name; - // bool enabled = true; // TODO: remove these? }; struct PrinterModel { PrinterModel() {} std::string id; std::string name; - // bool enabled = true; std::vector variants; PrinterVariant* variant(const std::string &name) { for (auto &v : this->variants) @@ -87,7 +85,8 @@ public: bool is_external = false; // System preset is read-only. bool is_system = false; - // Preset is visible, if it is compatible with the active Printer. TODO: fix + // Preset is visible, if it is associated with a printer model / variant that is enabled in the AppConfig + // or if it has no printer model / variant association. // Also the "default" preset is only visible, if it is the only preset in the list. bool is_visible = true; // Has this preset been modified? diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 8645a4f2d..bd9e35ca8 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -4,7 +4,6 @@ #include "PresetBundle.hpp" #include "BitmapCache.hpp" -#include // XXX #include #include #include @@ -201,10 +200,7 @@ static inline std::string remove_ini_suffix(const std::string &name) // If the "vendor" section is missing, enable all models and variants of the particular vendor. void PresetBundle::load_installed_printers(const AppConfig &config) { - std::cerr << "load_installed_printers()" << std::endl; - for (auto &preset : printers) { - std::cerr << "preset: printer: " << preset.name << std::endl; preset.set_visible_from_appconfig(config); } } @@ -742,7 +738,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla const VendorProfile *vendor_profile = nullptr; if (flags & (LOAD_CFGBNDLE_SYSTEM | LOAD_CFGBUNDLE_VENDOR_ONLY)) { boost::filesystem::path fspath(path); - VendorProfile vp(fspath.stem().native()); + VendorProfile vp(fspath.stem().string()); load_vendor_profile(tree, vp); if (vp.name.empty()) throw std::runtime_error(std::string("Vendor Config Bundle is not valid: Missing vendor name key.")); diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index ad7f69a2d..fcf465a29 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -54,8 +54,8 @@ int combochecklist_get_flags(SV *ui) void set_app_config(AppConfig *app_config) %code%{ Slic3r::GUI::set_app_config(app_config); %}; -void open_config_wizard(PresetBundle *preset_bundle) - %code%{ Slic3r::GUI::open_config_wizard(preset_bundle); %}; +bool open_config_wizard(PresetBundle *preset_bundle) + %code%{ RETVAL=Slic3r::GUI::open_config_wizard(preset_bundle); %}; void open_preferences_dialog(int preferences_event) %code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %}; From 57f6601c9d6b506ebc3aacdb580c59d3c90633d2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 9 Apr 2018 10:41:34 +0200 Subject: [PATCH 08/10] ConfigWizard: Fix logo rendering --- xs/src/slic3r/GUI/ConfigWizard.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index 032b5e903..f13448c37 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -477,10 +477,22 @@ ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) : bullet_white(GUI::from_u8(Slic3r::var("bullet_white.png")), wxBITMAP_TYPE_PNG) { SetMinSize(bg.GetSize()); - Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this); wxClientDC dc(this); text_height = dc.GetCharHeight(); + + // Add logo bitmap. + // This could be done in on_paint() along with the index labels, but I've found it tricky + // to get the bitmap rendered well on all platforms with transparent background. + // In some cases it didn't work at all. And so wxStaticBitmap is used here instead, + // because it has all the platform quirks figured out. + auto *sizer = new wxBoxSizer(wxVERTICAL); + auto *logo = new wxStaticBitmap(this, wxID_ANY, bg); + sizer->AddStretchSpacer(); + sizer->Add(logo); + SetSizer(sizer); + + Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this); } void ConfigWizardIndex::load_items(ConfigWizardPage *firstpage) @@ -509,12 +521,9 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt) }; const auto size = GetClientSize(); - const auto h = size.GetHeight(); - const auto w = size.GetWidth(); - if (h == 0 || w == 0) { return; } + if (size.GetHeight() == 0 || size.GetWidth() == 0) { return; } wxPaintDC dc(this); - dc.DrawBitmap(bg, 0, h - bg.GetHeight(), false); const auto bullet_w = bullet_black.GetSize().GetWidth(); const auto bullet_h = bullet_black.GetSize().GetHeight(); From b8a06d728ad523b5fa1542840c02e9dc67e0403e Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 9 Apr 2018 16:24:34 +0200 Subject: [PATCH 09/10] Fixes in 2DBed --- xs/src/slic3r/GUI/2DBed.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/xs/src/slic3r/GUI/2DBed.cpp b/xs/src/slic3r/GUI/2DBed.cpp index c5d68400d..6d788cf34 100644 --- a/xs/src/slic3r/GUI/2DBed.cpp +++ b/xs/src/slic3r/GUI/2DBed.cpp @@ -1,4 +1,4 @@ -#include "2DBed.hpp"; +#include "2DBed.hpp" #include #include "BoundingBox.hpp" @@ -66,7 +66,7 @@ void Bed_2D::repaint() shift.y - (cbb.max.y - GetSize().GetHeight())); // draw bed fill - dc.SetBrush(*new wxBrush(*new wxColour(255, 255, 255), wxSOLID)); + dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxSOLID)); wxPointList pt_list; for (auto pt: m_bed_shape) { @@ -87,7 +87,7 @@ void Bed_2D::repaint() } polylines = intersection_pl(polylines, bed_polygon); - dc.SetPen(*new wxPen(*new wxColour(230, 230, 230), 1, wxSOLID)); + dc.SetPen(wxPen(wxColour(230, 230, 230), 1, wxSOLID)); for (auto pl : polylines) { for (size_t i = 0; i < pl.points.size()-1; i++){ @@ -98,8 +98,8 @@ void Bed_2D::repaint() } // draw bed contour - dc.SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID)); - dc.SetBrush(*new wxBrush(*new wxColour(0, 0, 0), wxTRANSPARENT)); + dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxSOLID)); + dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxTRANSPARENT)); dc.DrawPolygon(&pt_list, 0, 0); auto origin_px = to_pixels(Pointf(0, 0)); @@ -108,7 +108,7 @@ void Bed_2D::repaint() auto axes_len = 50; auto arrow_len = 6; auto arrow_angle = Geometry::deg2rad(45.0); - dc.SetPen(*new wxPen(*new wxColour(255, 0, 0), 2, wxSOLID)); // red + dc.SetPen(wxPen(wxColour(255, 0, 0), 2, wxSOLID)); // red auto x_end = Pointf(origin_px.x + axes_len, origin_px.y); dc.DrawLine(wxPoint(origin_px.x, origin_px.y), wxPoint(x_end.x, x_end.y)); for (auto angle : { -arrow_angle, arrow_angle }){ @@ -118,7 +118,7 @@ void Bed_2D::repaint() dc.DrawLine(wxPoint(x_end.x, x_end.y), wxPoint(end.x, end.y)); } - dc.SetPen(*new wxPen(*new wxColour(0, 255, 0), 2, wxSOLID)); // green + dc.SetPen(wxPen(wxColour(0, 255, 0), 2, wxSOLID)); // green auto y_end = Pointf(origin_px.x, origin_px.y - axes_len); dc.DrawLine(wxPoint(origin_px.x, origin_px.y), wxPoint(y_end.x, y_end.y)); for (auto angle : { -arrow_angle, arrow_angle }) { @@ -129,19 +129,23 @@ void Bed_2D::repaint() } // draw origin - dc.SetPen(*new wxPen(*new wxColour(0, 0, 0), 1, wxSOLID)); - dc.SetBrush(*new wxBrush(*new wxColour(0, 0, 0), wxSOLID)); + dc.SetPen(wxPen(wxColour(0, 0, 0), 1, wxSOLID)); + dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxSOLID)); dc.DrawCircle(origin_px.x, origin_px.y, 3); - dc.SetTextForeground(*new wxColour(0, 0, 0)); - dc.SetFont(*new wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL)); - dc.DrawText("(0,0)", origin_px.x + 1, origin_px.y + 2); + static const auto origin_label = wxString("(0,0)"); + dc.SetTextForeground(wxColour(0, 0, 0)); + dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL)); + auto extent = dc.GetTextExtent(origin_label); + const auto origin_label_x = origin_px.x <= cw / 2 ? origin_px.x + 1 : origin_px.x - 1 - extent.GetWidth(); + const auto origin_label_y = origin_px.y <= ch / 2 ? origin_px.y + 1 : origin_px.y - 1 - extent.GetHeight(); + dc.DrawText(origin_label, origin_label_x, origin_label_y); // draw current position if (m_pos!= Pointf(0, 0)) { auto pos_px = to_pixels(m_pos); - dc.SetPen(*new wxPen(*new wxColour(200, 0, 0), 2, wxSOLID)); - dc.SetBrush(*new wxBrush(*new wxColour(200, 0, 0), wxTRANSPARENT)); + dc.SetPen(wxPen(wxColour(200, 0, 0), 2, wxSOLID)); + dc.SetBrush(wxBrush(wxColour(200, 0, 0), wxTRANSPARENT)); dc.DrawCircle(pos_px.x, pos_px.y, 5); dc.DrawLine(pos_px.x - 15, pos_px.y, pos_px.x + 15, pos_px.y); From 26511deec0f4b86ee1f7597281f4553fbe91bca2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 9 Apr 2018 16:39:50 +0200 Subject: [PATCH 10/10] Add '-alpha' suffix to data directory for now --- xs/src/libslic3r/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 34b9eaa9f..14736468a 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -119,7 +119,7 @@ static std::string g_data_dir; void set_data_dir(const std::string &dir) { - g_data_dir = dir; + g_data_dir = dir + "-alpha"; // FIXME: Resolve backcompat problems } const std::string& data_dir()