From 120be3a76d6a85d3598a366226667106085e5202 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 18 Aug 2021 13:04:45 +0200 Subject: [PATCH 01/40] Fixed compile warning --- src/slic3r/GUI/3DScene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 8ef333d69..9c0341ff4 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -306,7 +306,7 @@ void GLVolume::SinkingContours::update() int object_idx = m_parent.object_idx(); Model& model = GUI::wxGetApp().plater()->model(); - if (0 <= object_idx && object_idx < model.objects.size() && m_parent.is_sinking() && !m_parent.is_below_printbed()) { + if (0 <= object_idx && object_idx < (int)model.objects.size() && m_parent.is_sinking() && !m_parent.is_below_printbed()) { const BoundingBoxf3& box = m_parent.transformed_convex_hull_bounding_box(); if (!m_old_box.size().isApprox(box.size()) || m_old_box.min.z() != box.min.z()) { m_old_box = box; From a3f995ac45e92f0987a5c7714316f1dbc1034bbb Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 18 Aug 2021 15:02:36 +0200 Subject: [PATCH 02/40] Add "Revert" buttons for text colors Settings --- src/slic3r/GUI/ButtonsDescription.cpp | 81 ++++++++++++++++----------- src/slic3r/GUI/ButtonsDescription.hpp | 4 ++ src/slic3r/GUI/GUI_App.cpp | 21 ++++--- src/slic3r/GUI/GUI_App.hpp | 2 + src/slic3r/GUI/Preferences.cpp | 31 ++-------- 5 files changed, 70 insertions(+), 69 deletions(-) diff --git a/src/slic3r/GUI/ButtonsDescription.cpp b/src/slic3r/GUI/ButtonsDescription.cpp index cadb7ac24..2f8c2b681 100644 --- a/src/slic3r/GUI/ButtonsDescription.cpp +++ b/src/slic3r/GUI/ButtonsDescription.cpp @@ -12,6 +12,46 @@ namespace Slic3r { namespace GUI { +void ButtonsDescription::FillSizerWithTextColorDescriptions(wxSizer* sizer, wxWindow* parent, wxColourPickerCtrl** sys_colour, wxColourPickerCtrl** mod_colour) +{ + wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(3, 5, 5); + sizer->Add(grid_sizer, 0, wxEXPAND); + + ScalableBitmap bmp_delete = ScalableBitmap(parent, "cross"); + ScalableBitmap bmp_delete_focus = ScalableBitmap(parent, "cross_focus"); + + auto add_color = [grid_sizer, parent](wxColourPickerCtrl** color_picker, const wxColour& color, const wxColour& def_color, wxString label_text) { + // + auto sys_label = new wxStaticText(parent, wxID_ANY, label_text); + sys_label->SetForegroundColour(color); + + *color_picker = new wxColourPickerCtrl(parent, wxID_ANY, color); + wxGetApp().UpdateDarkUI((*color_picker)->GetPickerCtrl(), true); + (*color_picker)->Bind(wxEVT_COLOURPICKER_CHANGED, [color_picker, sys_label](wxCommandEvent&) { + sys_label->SetForegroundColour((*color_picker)->GetColour()); + sys_label->Refresh(); + }); + + auto btn = new ScalableButton(parent, wxID_ANY, "undo"); + btn->SetToolTip(_L("Revert color to default")); + btn->Bind(wxEVT_BUTTON, [sys_label, color_picker, def_color](wxEvent& event) { + (*color_picker)->SetColour(def_color); + sys_label->SetForegroundColour(def_color); + sys_label->Refresh(); + }); + parent->Bind(wxEVT_UPDATE_UI, [color_picker, def_color](wxUpdateUIEvent& evt) { + evt.Enable((*color_picker)->GetColour() != def_color); + }, btn->GetId()); + + grid_sizer->Add(*color_picker, 0, wxALIGN_CENTRE_VERTICAL); + grid_sizer->Add(btn, 0, wxALIGN_CENTRE_VERTICAL); + grid_sizer->Add(sys_label, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + }; + + add_color(sys_colour, wxGetApp().get_label_clr_sys(), wxGetApp().get_label_default_clr_system(), _L("Value is the same as the system value")); + add_color(mod_colour, wxGetApp().get_label_clr_modified(),wxGetApp().get_label_default_clr_modified(), _L("Value was changed and is not equal to the system value or the last saved preset")); +} + ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vector &entries) : wxDialog(parent, wxID_ANY, _(L("Buttons And Text Colors Description")), wxDefaultPosition, wxDefaultSize), m_entries(entries) @@ -35,50 +75,23 @@ ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vectorSetForegroundColour(wxGetApp().get_label_clr_sys()); - auto sys_colour = new wxColourPickerCtrl(this, wxID_ANY, wxGetApp().get_label_clr_sys()); - wxGetApp().UpdateDarkUI(sys_colour->GetPickerCtrl(), true); - sys_colour->Bind(wxEVT_COLOURPICKER_CHANGED, ([sys_colour, sys_label](wxCommandEvent e) - { - sys_label->SetForegroundColour(sys_colour->GetColour()); - sys_label->Refresh(); - })); - size_t t= 0; - while (t < 3) { - grid_sizer->Add(new wxStaticText(this, wxID_ANY, ""), -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND); - ++t; - } - grid_sizer->Add(0, -1, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(sys_colour, -1, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(sys_label, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND); - - auto mod_label = new wxStaticText(this, wxID_ANY, _(L("Value was changed and is not equal to the system value or the last saved preset"))); - mod_label->SetForegroundColour(wxGetApp().get_label_clr_modified()); - auto mod_colour = new wxColourPickerCtrl(this, wxID_ANY, wxGetApp().get_label_clr_modified()); - wxGetApp().UpdateDarkUI(mod_colour->GetPickerCtrl(), true); - mod_colour->Bind(wxEVT_COLOURPICKER_CHANGED, ([mod_colour, mod_label](wxCommandEvent e) - { - mod_label->SetForegroundColour(mod_colour->GetColour()); - mod_label->Refresh(); - })); - grid_sizer->Add(0, -1, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(mod_colour, -1, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(mod_label, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND); - + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + FillSizerWithTextColorDescriptions(sizer, this, &sys_colour, &mod_colour); + main_sizer->Add(sizer, 0, wxEXPAND | wxALL, 20); auto buttons = CreateStdDialogButtonSizer(wxOK|wxCANCEL); main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); - wxGetApp().UpdateDlgDarkUI(this, true); - wxButton* btn = static_cast(FindWindowById(wxID_OK, this)); - btn->Bind(wxEVT_BUTTON, [sys_colour, mod_colour, this](wxCommandEvent&) { + btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { wxGetApp().set_label_clr_sys(sys_colour->GetColour()); wxGetApp().set_label_clr_modified(mod_colour->GetColour()); EndModal(wxID_OK); }); + wxGetApp().UpdateDarkUI(btn); + wxGetApp().UpdateDarkUI(static_cast(FindWindowById(wxID_CANCEL, this))); + SetSizer(main_sizer); main_sizer->SetSizeHints(this); } diff --git a/src/slic3r/GUI/ButtonsDescription.hpp b/src/slic3r/GUI/ButtonsDescription.hpp index 5ca74290a..921ce796e 100644 --- a/src/slic3r/GUI/ButtonsDescription.hpp +++ b/src/slic3r/GUI/ButtonsDescription.hpp @@ -11,6 +11,8 @@ namespace GUI { class ButtonsDescription : public wxDialog { + wxColourPickerCtrl* sys_colour{ nullptr }; + wxColourPickerCtrl* mod_colour{ nullptr }; public: struct Entry { Entry(ScalableBitmap *bitmap, const std::string &symbol, const std::string &explanation) : bitmap(bitmap), symbol(symbol), explanation(explanation) {} @@ -23,6 +25,8 @@ public: ButtonsDescription(wxWindow* parent, const std::vector &entries); ~ButtonsDescription() {} + static void FillSizerWithTextColorDescriptions(wxSizer* sizer, wxWindow* parent, wxColourPickerCtrl** sys_colour, wxColourPickerCtrl** mod_colour); + private: std::vector m_entries; }; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index ec1dce508..91d16c602 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1030,17 +1030,22 @@ bool GUI_App::dark_mode() #endif } +const wxColour GUI_App::get_label_default_clr_system() +{ + return dark_mode() ? wxColour(115, 220, 103) : wxColour(26, 132, 57); +} + +const wxColour GUI_App::get_label_default_clr_modified() +{ + return dark_mode() ? wxColour(253, 111, 40) : wxColour(252, 77, 1); +} + void GUI_App::init_label_colours() { + m_color_label_modified = get_label_default_clr_modified(); + m_color_label_sys = get_label_default_clr_system(); + bool is_dark_mode = dark_mode(); - if (is_dark_mode) { - m_color_label_modified = wxColour(253, 111, 40); - m_color_label_sys = wxColour(115, 220, 103); - } - else { - m_color_label_modified = wxColour(252, 77, 1); - m_color_label_sys = wxColour(26, 132, 57); - } #ifdef _WIN32 m_color_label_default = is_dark_mode ? wxColour(250, 250, 250): wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); m_color_highlight_label_default = is_dark_mode ? wxColour(230, 230, 230): wxSystemSettings::GetColour(/*wxSYS_COLOUR_HIGHLIGHTTEXT*/wxSYS_COLOUR_WINDOWTEXT); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index f6699e82b..a140247e0 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -179,6 +179,8 @@ public: static unsigned get_colour_approx_luma(const wxColour &colour); static bool dark_mode(); + const wxColour get_label_default_clr_system(); + const wxColour get_label_default_clr_modified(); void init_label_colours(); void update_label_colours_from_appconfig(); void update_label_colours(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 50a5993a9..53c93b6b0 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -7,6 +7,7 @@ #include "libslic3r/AppConfig.hpp" #include #include "Notebook.hpp" +#include "ButtonsDescription.hpp" namespace Slic3r { namespace GUI { @@ -395,7 +396,8 @@ void PreferencesDialog::build(size_t selected_tab) auto buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL); this->Bind(wxEVT_BUTTON, &PreferencesDialog::accept, this, wxID_OK); - wxGetApp().UpdateDlgDarkUI(this, true); + for (int id : {wxID_OK, wxID_CANCEL}) + wxGetApp().UpdateDarkUI(static_cast(FindWindowById(id, this))); sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM | wxTOP, 10); @@ -638,32 +640,7 @@ void PreferencesDialog::create_settings_text_color_widget() if (!wxOSX) stb->SetBackgroundStyle(wxBG_STYLE_PAINT); wxSizer* sizer = new wxStaticBoxSizer(stb, wxVERTICAL); - wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(2, 5, 5); - sizer->Add(grid_sizer, 0, wxEXPAND); - - auto sys_label = new wxStaticText(parent, wxID_ANY, _L("Value is the same as the system value")); - sys_label->SetForegroundColour(wxGetApp().get_label_clr_sys()); - m_sys_colour = new wxColourPickerCtrl(parent, wxID_ANY, wxGetApp().get_label_clr_sys()); - wxGetApp().UpdateDarkUI(m_sys_colour->GetPickerCtrl(), true); - m_sys_colour->Bind(wxEVT_COLOURPICKER_CHANGED, [this, sys_label](wxCommandEvent&) { - sys_label->SetForegroundColour(m_sys_colour->GetColour()); - sys_label->Refresh(); - }); - - grid_sizer->Add(m_sys_colour, 0, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(sys_label, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); - - auto mod_label = new wxStaticText(parent, wxID_ANY, _L("Value was changed and is not equal to the system value or the last saved preset")); - mod_label->SetForegroundColour(wxGetApp().get_label_clr_modified()); - m_mod_colour = new wxColourPickerCtrl(parent, wxID_ANY, wxGetApp().get_label_clr_modified()); - wxGetApp().UpdateDarkUI(m_mod_colour->GetPickerCtrl(), true); - m_mod_colour->Bind(wxEVT_COLOURPICKER_CHANGED, [this, mod_label](wxCommandEvent&) { - mod_label->SetForegroundColour(m_mod_colour->GetColour()); - mod_label->Refresh(); - }); - - grid_sizer->Add(m_mod_colour, 0, wxALIGN_CENTRE_VERTICAL); - grid_sizer->Add(mod_label, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + ButtonsDescription::FillSizerWithTextColorDescriptions(sizer, parent, &m_sys_colour, &m_mod_colour); m_optgroup_gui->sizer->Add(sizer, 0, wxEXPAND | wxTOP, em_unit()); } From 5be61fb31c4985a9aafddc3b6f4202375d2d5b19 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 18 Aug 2021 15:29:51 +0200 Subject: [PATCH 03/40] Fix build on Linux (gcc 8.4) --- src/slic3r/GUI/ButtonsDescription.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/ButtonsDescription.hpp b/src/slic3r/GUI/ButtonsDescription.hpp index 921ce796e..fbed36c2a 100644 --- a/src/slic3r/GUI/ButtonsDescription.hpp +++ b/src/slic3r/GUI/ButtonsDescription.hpp @@ -5,6 +5,7 @@ #include class ScalableBitmap; +class wxColourPickerCtrl; namespace Slic3r { namespace GUI { From caf8ef4aab73edace0a2d3a3f71a3f277d769f67 Mon Sep 17 00:00:00 2001 From: Oleksandra Yushchenko Date: Wed, 18 Aug 2021 16:10:35 +0200 Subject: [PATCH 04/40] Auto selection of presets (#6817) PresetComboBoxes: Auto selection of printer/material preset from the new added presets in ConfigWizard + Check unsaved changes if ConfigWizard is running from the PesetComboBoxes --- src/libslic3r/Preset.cpp | 8 +- src/libslic3r/Preset.hpp | 2 +- src/libslic3r/PresetBundle.cpp | 20 +++-- src/libslic3r/PresetBundle.hpp | 13 ++- src/slic3r/GUI/ConfigWizard.cpp | 128 ++++++++++++++++++---------- src/slic3r/GUI/PresetComboBoxes.cpp | 14 ++- 6 files changed, 127 insertions(+), 58 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 1283d0ac1..61ae78b5e 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1385,12 +1385,16 @@ const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConf return this->default_preset((opt_printer_technology == nullptr || opt_printer_technology->value == ptFFF) ? 0 : 1); } -const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model_id) const +const Preset* PrinterPresetCollection::find_system_preset_by_model_and_variant(const std::string &model_id, const std::string& variant) const { if (model_id.empty()) { return nullptr; } const auto it = std::find_if(cbegin(), cend(), [&](const Preset &preset) { - return preset.config.opt_string("printer_model") == model_id; + if (!preset.is_system || preset.config.opt_string("printer_model") != model_id) + return false; + if (variant.empty()) + return true; + return preset.config.opt_string("printer_variant") == variant; }); return it != cend() ? &*it : nullptr; diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 9d5597cac..4897f504c 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -592,7 +592,7 @@ public: const Preset& default_preset_for(const DynamicPrintConfig &config) const override; - const Preset* find_by_model_id(const std::string &model_id) const; + const Preset* find_system_preset_by_model_and_variant(const std::string &model_id, const std::string &variant) const; private: PrinterPresetCollection() = default; diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index adb84df67..95d93b1c2 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -188,7 +188,8 @@ void PresetBundle::setup_directories() } } -PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule, const std::string &preferred_model_id) +PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule, + const PresetPreferences& preferred_selection/* = PresetPreferences()*/) { // First load the vendor specific system presets. PresetsConfigSubstitutions substitutions; @@ -239,7 +240,8 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward if (! errors_cummulative.empty()) throw Slic3r::RuntimeError(errors_cummulative); - this->load_selections(config, preferred_model_id); + // ysToDo : set prefered filament or sla_material (relates to print technology) and force o use of preffered printer model if it was added + this->load_selections(config, preferred_selection); return substitutions; } @@ -441,7 +443,7 @@ void PresetBundle::load_installed_sla_materials(AppConfig &config) // Load selections (current print, current filaments, current printer) from config.ini // This is done on application start up or after updates are applied. -void PresetBundle::load_selections(AppConfig &config, const std::string &preferred_model_id) +void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& preferred_selection/* = PresetPreferences()*/) { // Update visibility of presets based on application vendor / model / variant configuration. this->load_installed_printers(config); @@ -464,13 +466,21 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr // will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always). const Preset *initial_printer = printers.find_preset(initial_printer_profile_name); - const Preset *preferred_printer = printers.find_by_model_id(preferred_model_id); + const Preset *preferred_printer = printers.find_system_preset_by_model_and_variant(preferred_selection.printer_model_id, preferred_selection.printer_variant); printers.select_preset_by_name( - (preferred_printer != nullptr && (initial_printer == nullptr || !initial_printer->is_visible)) ? + (preferred_printer != nullptr /*&& (initial_printer == nullptr || !initial_printer->is_visible)*/) ? preferred_printer->name : initial_printer_profile_name, true); + // select preferred filament/sla_material profile if any exists and is visible + if (!preferred_selection.filament.empty()) + if (auto it = filaments.find_preset_internal(preferred_selection.filament); it != filaments.end() && it->is_visible) + initial_filament_profile_name = it->name; + if (!preferred_selection.sla_material.empty()) + if (auto it = sla_materials.find_preset_internal(preferred_selection.sla_material); it != sla_materials.end() && it->is_visible) + initial_sla_material_profile_name = it->name; + // Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found. prints.select_preset_by_name_strict(initial_print_profile_name); filaments.select_preset_by_name_strict(initial_filament_profile_name); diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 3c7349668..c22599e38 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -25,9 +25,18 @@ public: void setup_directories(); + struct PresetPreferences { + std::string printer_model_id;// name of a preferred printer model + std::string printer_variant; // name of a preferred printer variant + std::string filament; // name of a preferred filament preset + std::string sla_material; // name of a preferred sla_material preset + }; + // Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. // Load selections (current print, current filaments, current printer) from config.ini - PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule, const std::string &preferred_model_id = std::string()); + // select preferred presets, if any exist + PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule, + const PresetPreferences& preferred_selection = PresetPreferences()); // Export selections (current print, current filaments, current printer) into config.ini void export_selections(AppConfig &config); @@ -153,7 +162,7 @@ private: // Load selections (current print, current filaments, current printer) from config.ini // This is done just once on application start up. - void load_selections(AppConfig &config, const std::string &preferred_model_id = ""); + void load_selections(AppConfig &config, const PresetPreferences& preferred_selection = PresetPreferences()); // Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path. // and the external config is just referenced, not stored into user profile directory. diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index c31bc0287..f64bdecba 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -2453,6 +2453,34 @@ bool ConfigWizard::priv::check_and_install_missing_materials(Technology technolo return true; } +static std::set get_new_added_presets(const std::map& old_data, const std::map& new_data) +{ + auto get_aliases = [](const std::map& data) { + std::set old_aliases; + for (auto item : data) { + const std::string& name = item.first; + size_t pos = name.find("@"); + old_aliases.emplace(pos == std::string::npos ? name : name.substr(0, pos-1)); + } + return old_aliases; + }; + + std::set old_aliases = get_aliases(old_data); + std::set new_aliases = get_aliases(new_data); + std::set diff; + std::set_difference(new_aliases.begin(), new_aliases.end(), old_aliases.begin(), old_aliases.end(), std::inserter(diff, diff.begin())); + + return diff; +} + +static std::string get_first_added_preset(const std::map& old_data, const std::map& new_data) +{ + std::set diff = get_new_added_presets(old_data, new_data); + if (diff.empty()) + return std::string(); + return *diff.begin(); +} + bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater) { const auto enabled_vendors = appconfig_new.vendors(); @@ -2525,13 +2553,61 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese preset_bundle->reset(true); } + std::string preferred_model; + std::string preferred_variant; + const auto enabled_vendors_old = app_config->vendors(); + auto get_preferred_printer_model = [enabled_vendors, enabled_vendors_old](const std::string& bundle_name, const Bundle& bundle, std::string& variant) { + const auto config = enabled_vendors.find(bundle_name); + if (config == enabled_vendors.end()) + return std::string(); + for (const auto& model : bundle.vendor_profile->models) { + if (const auto model_it = config->second.find(model.id); + model_it != config->second.end() && model_it->second.size() > 0) { + variant = *model_it->second.begin(); + const auto config_old = enabled_vendors_old.find(bundle_name); + if (config_old == enabled_vendors_old.end()) + return model.id; + const auto model_it_old = config_old->second.find(model.id); + if (model_it_old == config_old->second.end()) + return model.id; + else if (model_it_old->second != model_it->second) { + for (const auto& var : model_it->second) + if (model_it_old->second.find(var) == model_it_old->second.end()) { + variant = var; + return model.id; + } + } + } + } + if (!variant.empty()) + variant.clear(); + return std::string(); + }; + // Prusa printers are considered first, then 3rd party. + if (preferred_model = get_preferred_printer_model("PrusaResearch", bundles.prusa_bundle(), preferred_variant); + preferred_model.empty()) { + for (const auto& bundle : bundles) { + if (bundle.second.is_prusa_bundle) { continue; } + if (preferred_model = get_preferred_printer_model(bundle.first, bundle.second, preferred_variant); + !preferred_model.empty()) + break; + } + } + + std::string first_added_filament, first_added_sla_material; + auto apply_section = [this, app_config](const std::string& section_name, std::string& first_added_preset) { + if (appconfig_new.has_section(section_name)) { + // get first of new added preset names + const std::map& old_presets = app_config->has_section(section_name) ? app_config->get_section(section_name) : std::map(); + first_added_preset = get_first_added_preset(old_presets, appconfig_new.get_section(section_name)); + app_config->set_section(section_name, appconfig_new.get_section(section_name)); + } + }; + apply_section(AppConfig::SECTION_FILAMENTS, first_added_filament); + apply_section(AppConfig::SECTION_MATERIALS, first_added_sla_material); + app_config->set_vendors(appconfig_new); - if (appconfig_new.has_section(AppConfig::SECTION_FILAMENTS)) { - app_config->set_section(AppConfig::SECTION_FILAMENTS, appconfig_new.get_section(AppConfig::SECTION_FILAMENTS)); - } - if (appconfig_new.has_section(AppConfig::SECTION_MATERIALS)) { - app_config->set_section(AppConfig::SECTION_MATERIALS, appconfig_new.get_section(AppConfig::SECTION_MATERIALS)); - } + app_config->set("version_check", page_update->version_check ? "1" : "0"); app_config->set("preset_update", page_update->preset_update ? "1" : "0"); app_config->set("export_sources_full_pathnames", page_reload_from_disk->full_pathnames ? "1" : "0"); @@ -2556,44 +2632,8 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese page_mode->serialize_mode(app_config); - std::string preferred_model; - - // Figure out the default pre-selected printer based on the selections in the pickers. - // The default is the first selected printer model (one with at least 1 variant selected). - // The default is only applied by load_presets() if the user doesn't have a (visible) printer - // selected already. - // Prusa printers are considered first, then 3rd party. - const auto config_prusa = enabled_vendors.find("PrusaResearch"); - if (config_prusa != enabled_vendors.end()) { - for (const auto &model : bundles.prusa_bundle().vendor_profile->models) { - const auto model_it = config_prusa->second.find(model.id); - if (model_it != config_prusa->second.end() && model_it->second.size() > 0) { - preferred_model = model.id; - break; - } - } - } - if (preferred_model.empty()) { - for (const auto &bundle : bundles) { - if (bundle.second.is_prusa_bundle) { continue; } - - const auto config = enabled_vendors.find(bundle.first); - if (config == enabled_vendors.end()) { continue; } - for (const auto &model : bundle.second.vendor_profile->models) { - const auto model_it = config->second.find(model.id); - if (model_it != config->second.end() && model_it->second.size() > 0) { - preferred_model = model.id; - break; - } - } - } - } - - // Reloading the configs after some modifications were done to PrusaSlicer.ini. - // Just perform the substitutions silently, as the substitutions were already presented to the user on application start-up - // and the Wizard shall not create any new values that would require substitution. - // Throw on substitutions in system profiles, as the system profiles provided over the air should be compatible with this PrusaSlicer version. - preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, preferred_model); + preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, + {preferred_model, preferred_variant, first_added_filament, first_added_sla_material}); if (page_custom->custom_wanted()) { page_firmware->apply_custom_config(*custom_config); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index aab8c2829..b8d4ead50 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -634,6 +634,12 @@ PlaterPresetComboBox::~PlaterPresetComboBox() edit_btn->Destroy(); } +static void run_wizard(ConfigWizard::StartPage sp) +{ + if (wxGetApp().check_and_save_current_preset_changes()) + wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); +} + void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt) { auto selected_item = evt.GetSelection(); @@ -653,7 +659,7 @@ void PlaterPresetComboBox::OnSelect(wxCommandEvent &evt) case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break; default: break; } - wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); }); + wxTheApp->CallAfter([sp]() { run_wizard(sp); }); } return; } @@ -685,7 +691,7 @@ void PlaterPresetComboBox::show_add_menu() append_menu_item(menu, wxID_ANY, _L("Add/Remove presets"), "", [](wxCommandEvent&) { - wxTheApp->CallAfter([]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS); }); + wxTheApp->CallAfter([]() { run_wizard(ConfigWizard::SP_PRINTERS); }); }, "edit_uni", menu, []() { return true; }, wxGetApp().plater()); append_menu_item(menu, wxID_ANY, _L("Add physical printer"), "", @@ -715,7 +721,7 @@ void PlaterPresetComboBox::show_edit_menu() else append_menu_item(menu, wxID_ANY, _L("Add/Remove presets"), "", [](wxCommandEvent&) { - wxTheApp->CallAfter([]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS); }); + wxTheApp->CallAfter([]() { run_wizard(ConfigWizard::SP_PRINTERS); }); }, "edit_uni", menu, []() { return true; }, wxGetApp().plater()); append_menu_item(menu, wxID_ANY, _L("Add physical printer"), "", @@ -918,7 +924,7 @@ void TabPresetComboBox::OnSelect(wxCommandEvent &evt) this->SetSelection(m_last_selected); if (marker == LABEL_ITEM_WIZARD_PRINTERS) wxTheApp->CallAfter([this]() { - wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS); + run_wizard(ConfigWizard::SP_PRINTERS); // update combobox if its parent is a PhysicalPrinterDialog PhysicalPrinterDialog* parent = dynamic_cast(this->GetParent()); From 74edeb147b66f46b879e820e2ac2eec3b60fd4fa Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 18 Aug 2021 15:44:48 +0200 Subject: [PATCH 05/40] Add min z height orientation search --- src/libslic3r/SLA/Rotfinder.cpp | 88 ++++++++++++++++++++++++++ src/libslic3r/SLA/Rotfinder.hpp | 3 +- src/slic3r/GUI/Jobs/RotoptimizeJob.hpp | 6 +- 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index d18d2fe6b..804908ab8 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -442,4 +442,92 @@ Vec2d find_least_supports_rotation(const ModelObject & mo, return {rot[0], rot[1]}; } +inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set& its, const Transform3f &tr) +{ + if (its.vertices.empty()) + return {}; + + Vec3f bmin = tr * its.vertices.front(), bmax = tr * its.vertices.front(); + + for (const Vec3f &p : its.vertices) { + Vec3f pp = tr * p; + bmin = pp.cwiseMin(bmin); + bmax = pp.cwiseMax(bmax); + } + + return {bmin.cast(), bmax.cast()}; +} + +Vec2d find_min_z_height_rotation(const ModelObject &mo, const RotOptimizeParams ¶ms) +{ + static const unsigned MAX_TRIES = 1000; + + // return value + XYRotation rot; + + // We will use only one instance of this converted mesh to examine different + // rotations + TriangleMesh mesh = get_mesh_to_rotate(mo); + + // To keep track of the number of iterations + unsigned status = 0; + + // The maximum number of iterations + auto max_tries = unsigned(params.accuracy() * MAX_TRIES); + + auto &statuscb = params.statuscb(); + + // call status callback with zero, because we are at the start + statuscb(status); + + auto statusfn = [&statuscb, &status, &max_tries] { + // report status + statuscb(unsigned(++status * 100.0/max_tries) ); + }; + + auto stopcond = [&statuscb] { + return ! statuscb(-1); + }; + + TriangleMesh chull = mesh.convex_hull_3d(); + chull.require_shared_vertices(); + auto inputs = reserve_vector(chull.its.indices.size()); + auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) { + double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y]; + return std::abs(xdiff) < EPSILON ? ydiff < 0. : xdiff < 0.; + }; + auto eqcmp = [](const XYRotation &r1, const XYRotation &r2) { + double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y]; + return std::abs(xdiff) < EPSILON && std::abs(ydiff) < EPSILON; + }; + + for (size_t fi = 0; fi < chull.its.indices.size(); ++fi) { + Facestats fc{get_triangle_vertices(chull, fi)}; + + auto q = Eigen::Quaternionf{}.FromTwoVectors(fc.normal, DOWN); + XYRotation rot = from_transform3f(Transform3f::Identity() * q); + + auto it = std::lower_bound(inputs.begin(), inputs.end(), rot, rotcmp); + + if (it == inputs.end() || !eqcmp(*it, rot)) + inputs.insert(it, rot); + } + + inputs.shrink_to_fit(); + max_tries = inputs.size(); + + // If the model can be placed on the bed directly, we only need to + // check the 3D convex hull face rotations. + + auto objfn = [&chull, &statusfn](const XYRotation &rot) { + statusfn(); + Transform3f tr = to_transform3f(rot); + return bounding_box_with_tr(chull.its, tr).size().z(); + }; + + rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), stopcond); + + return {rot[0], rot[1]}; +} + }} // namespace Slic3r::sla diff --git a/src/libslic3r/SLA/Rotfinder.hpp b/src/libslic3r/SLA/Rotfinder.hpp index 77a39016d..d632419fb 100644 --- a/src/libslic3r/SLA/Rotfinder.hpp +++ b/src/libslic3r/SLA/Rotfinder.hpp @@ -63,7 +63,8 @@ Vec2d find_best_misalignment_rotation(const ModelObject &modelobj, Vec2d find_least_supports_rotation(const ModelObject &modelobj, const RotOptimizeParams & = {}); -double find_Z_fit_to_bed_rotation(const ModelObject &mo, const BoundingBox &bed); +Vec2d find_min_z_height_rotation(const ModelObject &mo, + const RotOptimizeParams ¶ms = {}); } // namespace sla } // namespace Slic3r diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp index edabb7cae..d703ff0e3 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp @@ -27,9 +27,9 @@ class RotoptimizeJob : public PlaterJob "structures.\nNote that this method will try to find the best surface of the object " "for touching the print bed if no elevation is set.")}, // Just a min area bounding box that is done for all methods anyway. - {L("Smallest bounding box (Z axis only)"), - nullptr, - L("Rotate the object only in Z axis to have the smallest bounding box.")}}; + {L("Smallest Z height"), + sla::find_min_z_height_rotation, + L("Rotate the model to have least z height for faster print time.")}}; size_t m_method_id = 0; float m_accuracy = 0.75; From 1672130d456a039388516bf76544ce15b35db311 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 18 Aug 2021 16:47:59 +0200 Subject: [PATCH 06/40] Remove code duplication, clarify naming of orientation searches --- src/libslic3r/SLA/Rotfinder.cpp | 215 ++++++++++--------------- src/slic3r/GUI/Jobs/RotoptimizeJob.hpp | 4 +- 2 files changed, 84 insertions(+), 135 deletions(-) diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index 804908ab8..ac336731a 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -283,64 +283,61 @@ std::array find_min_score(Fn &&fn, It from, It to, StopCond &&stopfn) } // namespace -// Assemble the mesh with the correct transformation to be used in rotation -// optimization. -TriangleMesh get_mesh_to_rotate(const ModelObject &mo) -{ - TriangleMesh mesh = mo.raw_mesh(); - mesh.require_shared_vertices(); - ModelInstance *mi = mo.instances[0]; - auto rotation = Vec3d::Zero(); - auto offset = Vec3d::Zero(); - Transform3d trafo_instance = Geometry::assemble_transform(offset, - rotation, - mi->get_scaling_factor(), - mi->get_mirror()); - mesh.transform(trafo_instance); +template +struct RotfinderBoilerplate { + static constexpr unsigned MAX_TRIES = MAX_ITER; - return mesh; -} + int status = 0; + TriangleMesh mesh; + unsigned max_tries; + const RotOptimizeParams ¶ms; + + // Assemble the mesh with the correct transformation to be used in rotation + // optimization. + static TriangleMesh get_mesh_to_rotate(const ModelObject &mo) + { + TriangleMesh mesh = mo.raw_mesh(); + mesh.require_shared_vertices(); + + ModelInstance *mi = mo.instances[0]; + auto rotation = Vec3d::Zero(); + auto offset = Vec3d::Zero(); + Transform3d trafo_instance = + Geometry::assemble_transform(offset, rotation, + mi->get_scaling_factor(), + mi->get_mirror()); + + mesh.transform(trafo_instance); + + return mesh; + } + + RotfinderBoilerplate(const ModelObject &mo, const RotOptimizeParams &p) + : mesh{get_mesh_to_rotate(mo)} + , params{p} + , max_tries(p.accuracy() * MAX_TRIES) + { + + } + + void statusfn() { params.statuscb()(++status * 100.0 / max_tries); } + bool stopcond() { return ! params.statuscb()(-1); } +}; Vec2d find_best_misalignment_rotation(const ModelObject & mo, const RotOptimizeParams ¶ms) { - static constexpr unsigned MAX_TRIES = 1000; - - // return value - XYRotation rot; - - // We will use only one instance of this converted mesh to examine different - // rotations - TriangleMesh mesh = get_mesh_to_rotate(mo); - - // To keep track of the number of iterations - int status = 0; - - // The maximum number of iterations - auto max_tries = unsigned(params.accuracy() * MAX_TRIES); - - auto &statuscb = params.statuscb(); - - // call status callback with zero, because we are at the start - statuscb(status); - - auto statusfn = [&statuscb, &status, &max_tries] { - // report status - statuscb(++status * 100.0/max_tries); - }; - - auto stopcond = [&statuscb] { - return ! statuscb(-1); - }; + RotfinderBoilerplate<1000> bp{mo, params}; // Preparing the optimizer. - size_t gridsize = std::sqrt(max_tries); - opt::Optimizer solver(opt::StopCriteria{} - .max_iterations(max_tries) - .stop_condition(stopcond), - gridsize); + size_t gridsize = std::sqrt(bp.max_tries); + opt::Optimizer solver( + opt::StopCriteria{}.max_iterations(bp.max_tries) + .stop_condition([&bp] { return bp.stopcond(); }), + gridsize + ); // We are searching rotations around only two axes x, y. Thus the // problem becomes a 2 dimensional optimization task. @@ -348,48 +345,19 @@ Vec2d find_best_misalignment_rotation(const ModelObject & mo, auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} }); auto result = solver.to_max().optimize( - [&mesh, &statusfn] (const XYRotation &rot) + [&bp] (const XYRotation &rot) { - statusfn(); - return get_misalginment_score(mesh, to_transform3f(rot)); + bp.statusfn(); + return get_misalginment_score(bp.mesh, to_transform3f(rot)); }, opt::initvals({0., 0.}), bounds); - rot = result.optimum; - - return {rot[0], rot[1]}; + return {result.optimum[0], result.optimum[1]}; } Vec2d find_least_supports_rotation(const ModelObject & mo, const RotOptimizeParams ¶ms) { - static const unsigned MAX_TRIES = 1000; - - // return value - XYRotation rot; - - // We will use only one instance of this converted mesh to examine different - // rotations - TriangleMesh mesh = get_mesh_to_rotate(mo); - - // To keep track of the number of iterations - unsigned status = 0; - - // The maximum number of iterations - auto max_tries = unsigned(params.accuracy() * MAX_TRIES); - - auto &statuscb = params.statuscb(); - - // call status callback with zero, because we are at the start - statuscb(status); - - auto statusfn = [&statuscb, &status, &max_tries] { - // report status - statuscb(unsigned(++status * 100.0/max_tries) ); - }; - - auto stopcond = [&statuscb] { - return ! statuscb(-1); - }; + RotfinderBoilerplate<1000> bp{mo, params}; SLAPrintObjectConfig pocfg; if (params.print_config()) @@ -397,31 +365,35 @@ Vec2d find_least_supports_rotation(const ModelObject & mo, pocfg.apply(mo.config.get()); + XYRotation rot; + // Different search methods have to be used depending on the model elevation if (is_on_floor(pocfg)) { - std::vector inputs = get_chull_rotations(mesh, max_tries); - max_tries = inputs.size(); + std::vector inputs = get_chull_rotations(bp.mesh, bp.max_tries); + bp.max_tries = inputs.size(); // If the model can be placed on the bed directly, we only need to // check the 3D convex hull face rotations. - auto objfn = [&mesh, &statusfn](const XYRotation &rot) { - statusfn(); + auto objfn = [&bp](const XYRotation &rot) { + bp.statusfn(); Transform3f tr = to_transform3f(rot); - return get_supportedness_onfloor_score(mesh, tr); + return get_supportedness_onfloor_score(bp.mesh, tr); }; - rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), stopcond); + rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] { + return bp.stopcond(); + }); } else { - // Preparing the optimizer. - size_t gridsize = std::sqrt(max_tries); // 2D grid has gridsize^2 calls - opt::Optimizer solver(opt::StopCriteria{} - .max_iterations(max_tries) - .stop_condition(stopcond), - gridsize); + size_t gridsize = std::sqrt(bp.max_tries); // 2D grid has gridsize^2 calls + opt::Optimizer solver( + opt::StopCriteria{}.max_iterations(bp.max_tries) + .stop_condition([&bp] { return bp.stopcond(); }), + gridsize + ); // We are searching rotations around only two axes x, y. Thus the // problem becomes a 2 dimensional optimization task. @@ -429,10 +401,10 @@ Vec2d find_least_supports_rotation(const ModelObject & mo, auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} }); auto result = solver.to_min().optimize( - [&mesh, &statusfn] (const XYRotation &rot) + [&bp] (const XYRotation &rot) { - statusfn(); - return get_supportedness_score(mesh, to_transform3f(rot)); + bp.statusfn(); + return get_supportedness_score(bp.mesh, to_transform3f(rot)); }, opt::initvals({0., 0.}), bounds); // Save the result @@ -442,7 +414,8 @@ Vec2d find_least_supports_rotation(const ModelObject & mo, return {rot[0], rot[1]}; } -inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set& its, const Transform3f &tr) +inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set &its, + const Transform3f &tr) { if (its.vertices.empty()) return {}; @@ -458,38 +431,12 @@ inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set& its, const return {bmin.cast(), bmax.cast()}; } -Vec2d find_min_z_height_rotation(const ModelObject &mo, const RotOptimizeParams ¶ms) +Vec2d find_min_z_height_rotation(const ModelObject &mo, + const RotOptimizeParams ¶ms) { - static const unsigned MAX_TRIES = 1000; + RotfinderBoilerplate<1000> bp{mo, params}; - // return value - XYRotation rot; - - // We will use only one instance of this converted mesh to examine different - // rotations - TriangleMesh mesh = get_mesh_to_rotate(mo); - - // To keep track of the number of iterations - unsigned status = 0; - - // The maximum number of iterations - auto max_tries = unsigned(params.accuracy() * MAX_TRIES); - - auto &statuscb = params.statuscb(); - - // call status callback with zero, because we are at the start - statuscb(status); - - auto statusfn = [&statuscb, &status, &max_tries] { - // report status - statuscb(unsigned(++status * 100.0/max_tries) ); - }; - - auto stopcond = [&statuscb] { - return ! statuscb(-1); - }; - - TriangleMesh chull = mesh.convex_hull_3d(); + TriangleMesh chull = bp.mesh.convex_hull_3d(); chull.require_shared_vertices(); auto inputs = reserve_vector(chull.its.indices.size()); auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) { @@ -514,18 +461,20 @@ Vec2d find_min_z_height_rotation(const ModelObject &mo, const RotOptimizeParams } inputs.shrink_to_fit(); - max_tries = inputs.size(); + bp.max_tries = inputs.size(); // If the model can be placed on the bed directly, we only need to // check the 3D convex hull face rotations. - auto objfn = [&chull, &statusfn](const XYRotation &rot) { - statusfn(); + auto objfn = [&bp, &chull](const XYRotation &rot) { + bp.statusfn(); Transform3f tr = to_transform3f(rot); return bounding_box_with_tr(chull.its, tr).size().z(); }; - rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), stopcond); + XYRotation rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] { + return bp.stopcond(); + }); return {rot[0], rot[1]}; } diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp index d703ff0e3..811c9c97e 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp @@ -27,9 +27,9 @@ class RotoptimizeJob : public PlaterJob "structures.\nNote that this method will try to find the best surface of the object " "for touching the print bed if no elevation is set.")}, // Just a min area bounding box that is done for all methods anyway. - {L("Smallest Z height"), + {L("Lowest Z height"), sla::find_min_z_height_rotation, - L("Rotate the model to have least z height for faster print time.")}}; + L("Rotate the model to have the lowest z height for faster print time.")}}; size_t m_method_id = 0; float m_accuracy = 0.75; From a3b089eceb9896fcb68bb431358f806df76aff59 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 18 Aug 2021 16:51:14 +0200 Subject: [PATCH 07/40] Remove misleading comment --- src/libslic3r/SLA/Rotfinder.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index ac336731a..5486741f2 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -463,9 +463,6 @@ Vec2d find_min_z_height_rotation(const ModelObject &mo, inputs.shrink_to_fit(); bp.max_tries = inputs.size(); - // If the model can be placed on the bed directly, we only need to - // check the 3D convex hull face rotations. - auto objfn = [&bp, &chull](const XYRotation &rot) { bp.statusfn(); Transform3f tr = to_transform3f(rot); From 12328a74f70fdd1b11153dcb8f1787bfe5330143 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 10:15:42 +0200 Subject: [PATCH 08/40] Desktop integration changes empty catch block fix internal namespace fix wrong app config var Desktop integration for regular executables cmake option SLIC3R_DESKTOP_INTEGRATION cmake dependent option escape executable path in desktop file by adding /' Error messages instead of notifications. --- CMakeLists.txt | 7 ++ src/slic3r/GUI/DesktopIntegrationDialog.cpp | 94 ++++++++++----------- src/slic3r/GUI/GUI_App.cpp | 8 +- 3 files changed, 58 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a69d3bbf..a7d3dbf92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(PrusaSlicer) include("version.inc") include(GNUInstallDirs) +include(CMakeDependentOption) set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN) @@ -32,6 +33,8 @@ option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0) option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0) +# If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable. +CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow perfoming desktop integration during runtime" 0 "NOT SLIC3R_FHS" 0) set(OPENVDB_FIND_MODULE_PATH "" CACHE PATH "Path to OpenVDB installation's find modules.") @@ -71,6 +74,10 @@ if (SLIC3R_GUI) add_definitions(-DSLIC3R_GUI) endif () +if(SLIC3R_DESKTOP_INTEGRATION) + add_definitions(-DSLIC3R_DESKTOP_INTEGRATION) +endif () + if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) set(IS_CLANG_CL TRUE) diff --git a/src/slic3r/GUI/DesktopIntegrationDialog.cpp b/src/slic3r/GUI/DesktopIntegrationDialog.cpp index a2f7c8933..1ec008bd5 100644 --- a/src/slic3r/GUI/DesktopIntegrationDialog.cpp +++ b/src/slic3r/GUI/DesktopIntegrationDialog.cpp @@ -1,15 +1,18 @@ #ifdef __linux__ #include "DesktopIntegrationDialog.hpp" #include "GUI_App.hpp" +#include "GUI.hpp" #include "format.hpp" #include "I18N.hpp" #include "NotificationManager.hpp" #include "libslic3r/AppConfig.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Platform.hpp" +#include "libslic3r/Config.hpp" #include #include +#include #include #include @@ -17,9 +20,9 @@ namespace Slic3r { namespace GUI { -namespace integrate_desktop_internal{ +namespace { // Disects path strings stored in system variable divided by ':' and adds into vector -static void resolve_path_from_var(const std::string& var, std::vector& paths) +void resolve_path_from_var(const std::string& var, std::vector& paths) { wxString wxdirs; if (! wxGetEnv(boost::nowide::widen(var), &wxdirs) || wxdirs.empty() ) @@ -34,7 +37,7 @@ static void resolve_path_from_var(const std::string& var, std::vectorget("desktop_integration_app_path")); BOOST_LOG_TRIVIAL(debug) << "Desktop integration desktop file path: " << path; @@ -126,10 +125,6 @@ bool DesktopIntegrationDialog::is_integrated() } bool DesktopIntegrationDialog::integration_possible() { - - const char *appimage_env = std::getenv("APPIMAGE"); - if (!appimage_env) - return false; return true; } void DesktopIntegrationDialog::perform_desktop_integration() @@ -143,14 +138,26 @@ void DesktopIntegrationDialog::perform_desktop_integration() try { appimage_path = boost::filesystem::canonical(boost::filesystem::path(appimage_env)).string(); } catch (std::exception &) { + BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - boost::filesystem::canonical did not return appimage path."; + show_error(nullptr, _L("Performing desktop integration failed - boost::filesystem::canonical did not return appimage path.")); + return; } } else { - // not appimage - not performing - BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - not Appimage executable."; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); - return; + // not appimage - find executable + appimage_path = boost::dll::program_location().string(); + //appimage_path = wxStandardPaths::Get().GetExecutablePath().string(); + BOOST_LOG_TRIVIAL(debug) << "non-appimage path to executable: " << appimage_path; + if (appimage_path.empty()) + { + BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - no executable found."; + show_error(nullptr, _L("Performing desktop integration failed - Could not find executable.")); + return; + } } + // Escape ' characters in appimage, other special symbols will be esacaped in desktop file by 'appimage_path' + //appimage_path = std::regex_replace(appimage_path, std::regex("\'"), "\\\'"); + // Find directories icons and applications // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. // If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used. @@ -158,8 +165,8 @@ void DesktopIntegrationDialog::perform_desktop_integration() // The directories in $XDG_DATA_DIRS should be seperated with a colon ':'. // If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. std::vectortarget_candidates; - integrate_desktop_internal::resolve_path_from_var("XDG_DATA_HOME", target_candidates); - integrate_desktop_internal::resolve_path_from_var("XDG_DATA_DIRS", target_candidates); + resolve_path_from_var("XDG_DATA_HOME", target_candidates); + resolve_path_from_var("XDG_DATA_DIRS", target_candidates); AppConfig *app_config = wxGetApp().app_config; // suffix string to create different desktop file for alpha, beta. @@ -186,7 +193,6 @@ void DesktopIntegrationDialog::perform_desktop_integration() icon_theme_dirs = "/hicolor/96x96/apps"; } - std::string target_dir_icons; std::string target_dir_desktop; @@ -194,24 +200,24 @@ void DesktopIntegrationDialog::perform_desktop_integration() // iterate thru target_candidates to find icons folder for (size_t i = 0; i < target_candidates.size(); ++i) { // Copy icon PrusaSlicer.png from resources_dir()/icons to target_dir_icons/icons/ - if (integrate_desktop_internal::contains_path_dir(target_candidates[i], "icons")) { + if (contains_path_dir(target_candidates[i], "icons")) { target_dir_icons = target_candidates[i]; std::string icon_path = GUI::format("%1%/icons/PrusaSlicer.png",resources_dir()); std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer%3%.png", target_dir_icons, icon_theme_path, version_suffix); - if (integrate_desktop_internal::copy_icon(icon_path, dest_path)) + if (copy_icon(icon_path, dest_path)) break; // success else target_dir_icons.clear(); // copying failed // if all failed - try creating default home folder if (i == target_candidates.size() - 1) { // create $HOME/.local/share - integrate_desktop_internal::create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/icons" + icon_theme_dirs); + create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/icons" + icon_theme_dirs); // copy icon target_dir_icons = GUI::format("%1%/.local/share",wxFileName::GetHomeDir()); std::string icon_path = GUI::format("%1%/icons/PrusaSlicer.png",resources_dir()); std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer%3%.png", target_dir_icons, icon_theme_path, version_suffix); - if (!integrate_desktop_internal::contains_path_dir(target_dir_icons, "icons") - || !integrate_desktop_internal::copy_icon(icon_path, dest_path)) { + if (!contains_path_dir(target_dir_icons, "icons") + || !copy_icon(icon_path, dest_path)) { // every attempt failed - icon wont be present target_dir_icons.clear(); } @@ -228,7 +234,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() // iterate thru target_candidates to find applications folder for (size_t i = 0; i < target_candidates.size(); ++i) { - if (integrate_desktop_internal::contains_path_dir(target_candidates[i], "applications")) { + if (contains_path_dir(target_candidates[i], "applications")) { target_dir_desktop = target_candidates[i]; // Write slicer desktop file std::string desktop_file = GUI::format( @@ -236,7 +242,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() "Name=PrusaSlicer%1%\n" "GenericName=3D Printing Software\n" "Icon=PrusaSlicer%2%\n" - "Exec=%3% %%F\n" + "Exec=\'%3%\' %%F\n" "Terminal=false\n" "Type=Application\n" "MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n" @@ -246,23 +252,23 @@ void DesktopIntegrationDialog::perform_desktop_integration() "StartupWMClass=prusa-slicer", name_suffix, version_suffix, appimage_path); std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); - if (integrate_desktop_internal::create_desktop_file(path, desktop_file)){ + if (create_desktop_file(path, desktop_file)){ BOOST_LOG_TRIVIAL(debug) << "PrusaSlicer.desktop file installation success."; break; } else { // write failed - try another path - BOOST_LOG_TRIVIAL(error) << "PrusaSlicer.desktop file installation failed."; + BOOST_LOG_TRIVIAL(debug) << "Attempt to PrusaSlicer.desktop file installation failed. failed path: " << target_candidates[i]; target_dir_desktop.clear(); } // if all failed - try creating default home folder if (i == target_candidates.size() - 1) { // create $HOME/.local/share - integrate_desktop_internal::create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/applications"); + create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/applications"); // create desktop file target_dir_desktop = GUI::format("%1%/.local/share",wxFileName::GetHomeDir()); std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); - if (integrate_desktop_internal::contains_path_dir(target_dir_desktop, "applications")) { - if (!integrate_desktop_internal::create_desktop_file(path, desktop_file)) { + if (contains_path_dir(target_dir_desktop, "applications")) { + if (!create_desktop_file(path, desktop_file)) { // Desktop file not written - end desktop integration BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create desktop file"; return; @@ -278,7 +284,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() if(target_dir_desktop.empty()) { // Desktop file not written - end desktop integration BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not find applications directory"; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); + show_error(nullptr, _L("Performing desktop integration failed - could not find applications directory.")); return; } // save path to desktop file @@ -290,7 +296,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() { std::string icon_path = GUI::format("%1%/icons/PrusaSlicer-gcodeviewer_192px.png",resources_dir()); std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer-gcodeviewer%3%.png", target_dir_icons, icon_theme_path, version_suffix); - if (integrate_desktop_internal::copy_icon(icon_path, dest_path)) + if (copy_icon(icon_path, dest_path)) // save path to icon app_config->set("desktop_integration_icon_viewer_path", dest_path); else @@ -303,7 +309,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() "Name=Prusa Gcode Viewer%1%\n" "GenericName=3D Printing Software\n" "Icon=PrusaSlicer-gcodeviewer%2%\n" - "Exec=%3% --gcodeviwer %%F\n" + "Exec=\'%3%\' --gcodeviwer %%F\n" "Terminal=false\n" "Type=Application\n" "MimeType=text/x.gcode;\n" @@ -312,23 +318,17 @@ void DesktopIntegrationDialog::perform_desktop_integration() "StartupNotify=false", name_suffix, version_suffix, appimage_path); std::string desktop_path = GUI::format("%1%/applications/PrusaSlicerGcodeViewer%2%.desktop", target_dir_desktop, version_suffix); - if (integrate_desktop_internal::create_desktop_file(desktop_path, desktop_file)) + if (create_desktop_file(desktop_path, desktop_file)) // save path to desktop file app_config->set("desktop_integration_app_viewer_path", desktop_path); else { - BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could create gcode viewer desktop file"; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); + BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create Gcodeviewer desktop file"; + show_error(nullptr, _L("Performing desktop integration failed - could not create Gcodeviewer desktop file. PrusaSlicer desktop file was probably created successfully.")); } wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationSuccess); } void DesktopIntegrationDialog::undo_desktop_intgration() { - const char *appimage_env = std::getenv("APPIMAGE"); - if (!appimage_env) { - BOOST_LOG_TRIVIAL(error) << "Undo desktop integration failed - not Appimage executable."; - wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::UndoDesktopIntegrationFail); - return; - } const AppConfig *app_config = wxGetApp().app_config; // slicer .desktop std::string path = std::string(app_config->get("desktop_integration_app_path")); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 91d16c602..06d805eeb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1806,10 +1806,10 @@ void GUI_App::add_config_menu(wxMenuBar *menu) local_menu->Append(config_id_base + ConfigMenuSnapshots, _L("&Configuration Snapshots") + dots, _L("Inspect / activate configuration snapshots")); local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _L("Take Configuration &Snapshot"), _L("Capture a configuration snapshot")); local_menu->Append(config_id_base + ConfigMenuUpdate, _L("Check for updates"), _L("Check for configuration updates")); -#ifdef __linux__ - if (DesktopIntegrationDialog::integration_possible()) - local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration")); -#endif +#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) + //if (DesktopIntegrationDialog::integration_possible()) + local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration")); +#endif //(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) local_menu->AppendSeparator(); } local_menu->Append(config_id_base + ConfigMenuPreferences, _L("&Preferences") + dots + From b686b5764efbc49ab4bc6f5ccabb496bddd893d1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 19 Aug 2021 10:22:26 +0200 Subject: [PATCH 09/40] Fix opening of gizmos after clicking on info lines in object list when object has instances --- src/slic3r/GUI/GUI_ObjectList.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 318705e09..0c555454d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -3404,6 +3404,18 @@ void ObjectList::update_selections_on_canvas() std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); } + else if (type == itInfo) { + // When selecting an info item, select one instance of the + // respective object - a gizmo may want to be opened. + int inst_idx = selection.get_instance_idx(); + int scene_obj_idx = selection.get_object_idx(); + mode = Selection::Instance; + // select first instance, unless an instance of the object is already selected + if (scene_obj_idx == -1 || inst_idx == -1 || scene_obj_idx != obj_idx) + inst_idx = 0; + std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); + volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); + } else { mode = Selection::Instance; @@ -3418,7 +3430,7 @@ void ObjectList::update_selections_on_canvas() if (sel_cnt == 1) { wxDataViewItem item = GetSelection(); - if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer | itInfo)) + if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer)) add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode); else add_to_selection(item, selection, instance_idx, mode); From 97418cf9f59e1f78f554975473b02eb50980b975 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 10:27:23 +0200 Subject: [PATCH 10/40] Desktop integration in config wizard ifdef --- src/slic3r/GUI/ConfigWizard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index f64bdecba..bc56fe97e 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -494,7 +494,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent) { welcome_text->Hide(); cbox_reset->Hide(); -#ifdef __linux__ +#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) if (!DesktopIntegrationDialog::is_integrated()) cbox_integrate->Show(true); else From c08b4be0e650fd47e073daea9fb1bb3971fc9829 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 11:00:36 +0200 Subject: [PATCH 11/40] Fix of missplaced checkbox Perform desktop integration in config wizard. --- src/slic3r/GUI/ConfigWizard.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index bc56fe97e..3f388f485 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -494,15 +494,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent) { welcome_text->Hide(); cbox_reset->Hide(); -#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) - if (!DesktopIntegrationDialog::is_integrated()) - cbox_integrate->Show(true); - else - cbox_integrate->Hide(); -#else - cbox_integrate->Hide(); -#endif - + cbox_integrate->Hide(); } void PageWelcome::set_run_reason(ConfigWizard::RunReason run_reason) @@ -510,7 +502,7 @@ void PageWelcome::set_run_reason(ConfigWizard::RunReason run_reason) const bool data_empty = run_reason == ConfigWizard::RR_DATA_EMPTY; welcome_text->Show(data_empty); cbox_reset->Show(!data_empty); -#ifdef __linux__ +#if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) if (!DesktopIntegrationDialog::is_integrated()) cbox_integrate->Show(true); else From 316d38807d64e377c4b1d3a71f8c9587dcc82066 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 19 Aug 2021 11:54:41 +0200 Subject: [PATCH 12/40] Simplified shader printbed.vs --- resources/shaders/printbed.vs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index ac4763782..ee19098c1 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,12 +1,12 @@ #version 110 -attribute vec4 v_position; +attribute vec3 v_position; attribute vec2 v_tex_coords; varying vec2 tex_coords; void main() { - gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position; + gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position, 1.0); tex_coords = v_tex_coords; } From adfb5b6b4960224c23fec9531765f8d9fdf7ff45 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 19 Aug 2021 12:12:25 +0200 Subject: [PATCH 13/40] Small refactoring into GLModel::render() --- src/slic3r/GUI/GLModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 6d54ec20e..a9550bc04 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -169,6 +169,8 @@ void GLModel::reset() void GLModel::render() const { + GLShaderProgram* shader = wxGetApp().get_current_shader(); + for (const RenderData& data : m_render_data) { if (data.vbo_id == 0 || data.ibo_id == 0) continue; @@ -190,7 +192,6 @@ void GLModel::render() const glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader != nullptr) shader->set_uniform("uniform_color", data.color); else From 6d44bde96d6e11e22d34beaa85a9d480ec7c2590 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 12:36:18 +0200 Subject: [PATCH 14/40] Progress notification: fix of wrong method call. --- src/slic3r/GUI/NotificationManager.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index b347c9dfe..2bc9aaaab 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -391,7 +391,7 @@ private: { public: - ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { set_percentage(percentage); } + ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { } virtual void set_percentage(float percent) { m_percentage = percent; } protected: virtual void init() override; @@ -434,6 +434,7 @@ private: , m_file_size(filesize) { m_has_cancel_button = true; + set_percentage(percentage); } static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return /*"[" + std::to_string(id) + "] " + */filename + " -> " + host; } void set_percentage(float percent) override; From 8f58b11b085925774fd3172bca339b4f15d1412a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 19 Aug 2021 14:01:54 +0200 Subject: [PATCH 15/40] Rotated arrow asset. --- resources/icons/toolbar_arrow.png | Bin 3996 -> 3996 bytes resources/icons/toolbar_arrow.svg | 83 ++++++++++++++++++---- src/slic3r/GUI/GLToolbar.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/resources/icons/toolbar_arrow.png b/resources/icons/toolbar_arrow.png index 90ddce38f0c0dfa71dc4d6abdf07fd8a74b43a01..a370442ff0e933b85d436f3abac584b2e5ac3f37 100644 GIT binary patch literal 3996 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 LTMD)O|Nj2~#I)V2 literal 3996 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 - - -