mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge remote-tracking branch 'origin/updating' into config_snapshots
This commit is contained in:
		
						commit
						4275b15dcd
					
				
					 40 changed files with 3378 additions and 85 deletions
				
			
		|  | @ -214,12 +214,16 @@ add_library(libslic3r_gui STATIC | |||
|     ${LIBDIR}/slic3r/Config/Version.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/PresetUpdater.cpp | ||||
|     ${LIBDIR}/slic3r/Utils/PresetUpdater.hpp | ||||
|     ${LIBDIR}/slic3r/Utils/Time.cpp | ||||
|     ${LIBDIR}/slic3r/Utils/Time.hpp | ||||
| ) | ||||
|  | @ -367,6 +371,7 @@ set(XS_XSP_FILES | |||
|     ${XSP_DIR}/SurfaceCollection.xsp | ||||
|     ${XSP_DIR}/TriangleMesh.xsp | ||||
|     ${XSP_DIR}/Utils_OctoPrint.xsp | ||||
|     ${XSP_DIR}/Utils_PresetUpdater.xsp | ||||
|     ${XSP_DIR}/XS.xsp | ||||
| ) | ||||
| foreach (file ${XS_XSP_FILES}) | ||||
|  |  | |||
|  | @ -659,6 +659,7 @@ public: | |||
|     ConfigOptionPoints() : ConfigOptionVector<Pointf>() {} | ||||
|     explicit ConfigOptionPoints(size_t n, const Pointf &value) : ConfigOptionVector<Pointf>(n, value) {} | ||||
|     explicit ConfigOptionPoints(std::initializer_list<Pointf> il) : ConfigOptionVector<Pointf>(std::move(il)) {} | ||||
|     explicit ConfigOptionPoints(const std::vector<Pointf> &values) : ConfigOptionVector<Pointf>(values) {} | ||||
| 
 | ||||
|     static ConfigOptionType static_type() { return coPoints; } | ||||
|     ConfigOptionType        type()  const override { return static_type(); } | ||||
|  |  | |||
|  | @ -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 }; | ||||
|      | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| 
 | ||||
| #include <locale> | ||||
| 
 | ||||
| #include "libslic3r.h" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| extern void set_logging_level(unsigned int level); | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| #include "2DBed.hpp"; | ||||
| #include "2DBed.hpp" | ||||
| 
 | ||||
| #include <wx/dcbuffer.h> | ||||
| #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); | ||||
|  |  | |||
|  | @ -1,5 +1,3 @@ | |||
| #include <GL/glew.h> | ||||
| 
 | ||||
| #include "../../libslic3r/libslic3r.h" | ||||
| #include "../../libslic3r/Utils.hpp" | ||||
| #include "AppConfig.hpp" | ||||
|  | @ -9,15 +7,20 @@ | |||
| #include <string.h> | ||||
| #include <utility> | ||||
| #include <assert.h> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/nowide/cenv.hpp> | ||||
| #include <boost/nowide/fstream.hpp> | ||||
| #include <boost/property_tree/ini_parser.hpp> | ||||
| #include <boost/property_tree/ptree.hpp> | ||||
| #include <boost/algorithm/string/predicate.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| static const std::string VENDOR_PREFIX = "vendor:"; | ||||
| static const std::string MODEL_PREFIX = "model:"; | ||||
| 
 | ||||
| void AppConfig::reset() | ||||
| { | ||||
|     m_storage.clear(); | ||||
|  | @ -42,9 +45,11 @@ 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"); | ||||
|     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<std::string> 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<std::string, std::string> &storage = m_storage[section.first]; | ||||
|  | @ -96,10 +114,57 @@ void AppConfig::save() | |||
|     	for (const std::pair<std::string, std::string> &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<std::string> 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 | ||||
| { | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| 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"); | ||||
|  | @ -156,6 +221,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(); | ||||
|  |  | |||
|  | @ -1,9 +1,12 @@ | |||
| #ifndef slic3r_AppConfig_hpp_ | ||||
| #define slic3r_AppConfig_hpp_ | ||||
| 
 | ||||
| #include <set> | ||||
| #include <map> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "libslic3r/Config.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class AppConfig | ||||
|  | @ -65,6 +68,10 @@ 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); | ||||
| 
 | ||||
| 	// 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 +85,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 +98,8 @@ public: | |||
| private: | ||||
| 	// Map of section, name -> value
 | ||||
| 	std::map<std::string, std::map<std::string, std::string>> 	m_storage; | ||||
| 	// Map of enabled vendors / models / variants
 | ||||
| 	std::map<std::string, std::map<std::string, std::set<std::string>>> m_vendors; | ||||
| 	// Has any value been modified since the config.ini has been last saved or loaded?
 | ||||
| 	bool														m_dirty; | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										720
									
								
								xs/src/slic3r/GUI/ConfigWizard.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										720
									
								
								xs/src/slic3r/GUI/ConfigWizard.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,720 @@ | |||
| #include "ConfigWizard_private.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <utility> | ||||
| #include <boost/filesystem.hpp> | ||||
| 
 | ||||
| #include <wx/settings.h> | ||||
| #include <wx/stattext.h> | ||||
| #include <wx/textctrl.h> | ||||
| #include <wx/dcclient.h> | ||||
| #include <wx/statbmp.h> | ||||
| #include <wx/checkbox.h> | ||||
| #include <wx/statline.h> | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "PresetBundle.hpp" | ||||
| #include "GUI.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| // 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) : | ||||
| 	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)); | ||||
| 	append(widget); | ||||
| } | ||||
| 
 | ||||
| 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) : | ||||
| 	ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))), | ||||
| 	printer_picker(nullptr), | ||||
| 	others_buttons(new wxPanel(parent)) | ||||
| { | ||||
| 	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")); | ||||
| 
 | ||||
| 	if (vendor_prusa != vendors.cend()) { | ||||
| 		const auto &models = vendor_prusa->models; | ||||
| 
 | ||||
| 		AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors; | ||||
| 
 | ||||
| 		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); | ||||
| 	} | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	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(printer_picker != nullptr ? printer_picker->variants_checked > 0 : false); | ||||
| } | ||||
| 
 | ||||
| PageUpdate::PageUpdate(ConfigWizard *parent) : | ||||
| 	ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))), | ||||
| 	version_check(true), | ||||
| 	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(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(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(); }); | ||||
| } | ||||
| 
 | ||||
| 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 *picker = new PrinterPicker(this, vendor, appconfig_vendors); | ||||
| 		picker->Hide(); | ||||
| 		pickers.push_back(picker); | ||||
| 		choices_vendors.Add(vendor.name); | ||||
| 
 | ||||
| 		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(); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	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); | ||||
| 	} | ||||
| 
 | ||||
| 	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(); | ||||
| 		wizard_p()->layout_fit(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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"))), | ||||
| 	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<GCodeFlavor> 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"))), | ||||
| 	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<ConfigOptionPoints>("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 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<const ConfigOptionFloats*>(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<const ConfigOptionFloats*>(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("Extruder and Bed Temperatures")), _(L("Temperatures"))), | ||||
| 	spin_extr(new wxSpinCtrlDouble(this, wxID_ANY)), | ||||
| 	spin_bed(new wxSpinCtrlDouble(this, wxID_ANY)) | ||||
| { | ||||
| 	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<const ConfigOptionInts*>(def_extr.default_value); | ||||
| 	spin_extr->SetValue(default_extr != nullptr && default_extr->size() > 0 ? default_extr->get_at(0) : 200); | ||||
| 
 | ||||
| 	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<const ConfigOptionInts*>(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
 | ||||
| 
 | ||||
| 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()); | ||||
| 
 | ||||
| 	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) | ||||
| { | ||||
| 	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(); | ||||
| 	if (size.GetHeight() == 0 || size.GetWidth() == 0) { return; } | ||||
| 
 | ||||
| 	wxPaintDC dc(this); | ||||
| 
 | ||||
| 	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::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().string(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	appconfig_vendors.set_vendors(*GUI::get_app_config()); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| 	layout_fit(); | ||||
| } | ||||
| 
 | ||||
| void ConfigWizard::priv::layout_fit() | ||||
| { | ||||
| 	q->Layout(); | ||||
| 	q->Fit(); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 		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 { | ||||
| 		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); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Public
 | ||||
| 
 | ||||
| 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->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({ | ||||
| 		"gcode_flavor", "bed_shape", "nozzle_diameter", "filament_diameter", "temperature", "bed_temperature", | ||||
| 	})); | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	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(); | ||||
| 	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)); | ||||
| 	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(); }); | ||||
| 	p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->EndModal(wxID_OK); }); | ||||
| } | ||||
| 
 | ||||
| ConfigWizard::~ConfigWizard() {} | ||||
| 
 | ||||
| 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) { | ||||
| 		if (it->path().extension() == ".ini") { | ||||
| 			PresetBundle::install_vendor_configbundle(it->path()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ConfigWizard wizard(parent); | ||||
| 	if (wizard.ShowModal() == wxID_OK) { | ||||
| 		wizard.p->apply_config(GUI::get_app_config(), preset_bundle); | ||||
| 		return true; | ||||
| 	} else { | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| } | ||||
							
								
								
									
										38
									
								
								xs/src/slic3r/GUI/ConfigWizard.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								xs/src/slic3r/GUI/ConfigWizard.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| #ifndef slic3r_ConfigWizard_hpp_ | ||||
| #define slic3r_ConfigWizard_hpp_ | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <wx/dialog.h> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class PresetBundle; | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| class ConfigWizard: public wxDialog | ||||
| { | ||||
| public: | ||||
| 	ConfigWizard(wxWindow *parent); | ||||
| 	ConfigWizard(ConfigWizard &&) = delete; | ||||
| 	ConfigWizard(const ConfigWizard &) = delete; | ||||
| 	ConfigWizard &operator=(ConfigWizard &&) = delete; | ||||
| 	ConfigWizard &operator=(const ConfigWizard &) = delete; | ||||
| 	~ConfigWizard(); | ||||
| 
 | ||||
| 	static bool run(wxWindow *parent, PresetBundle *preset_bundle); | ||||
| private: | ||||
| 	struct priv; | ||||
| 	std::unique_ptr<priv> p; | ||||
| 
 | ||||
| 	friend class ConfigWizardPage; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										213
									
								
								xs/src/slic3r/GUI/ConfigWizard_private.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								xs/src/slic3r/GUI/ConfigWizard_private.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,213 @@ | |||
| #ifndef slic3r_ConfigWizard_private_hpp_ | ||||
| #define slic3r_ConfigWizard_private_hpp_ | ||||
| 
 | ||||
| #include "ConfigWizard.hpp" | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/panel.h> | ||||
| #include <wx/button.h> | ||||
| #include <wx/choice.h> | ||||
| #include <wx/spinctrl.h> | ||||
| 
 | ||||
| #include "libslic3r/PrintConfig.hpp" | ||||
| #include "AppConfig.hpp" | ||||
| #include "PresetBundle.hpp" | ||||
| #include "BedShapeDialog.hpp" | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| enum { | ||||
| 	CONTENT_WIDTH = 500, | ||||
| 
 | ||||
| 	DIALOG_MARGIN = 15, | ||||
| 	INDEX_MARGIN = 40, | ||||
| 	BTN_SPACING = 10, | ||||
| 	INDENT_SPACING = 30, | ||||
| 	VERTICAL_SPACING = 10, | ||||
| }; | ||||
| 
 | ||||
| struct PrinterPicker: wxPanel | ||||
| { | ||||
| 	unsigned variants_checked; | ||||
| 
 | ||||
| 	PrinterPicker(wxWindow *parent, const VendorProfile &vendor, const AppConfig &appconfig_vendors); | ||||
| }; | ||||
| 
 | ||||
| struct ConfigWizardPage: wxPanel | ||||
| { | ||||
| 	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); | ||||
| 
 | ||||
| 	template<class T> | ||||
| 	void append(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10) | ||||
| 	{ | ||||
| 		content->Add(thing, proportion, flag, border); | ||||
| 	} | ||||
| 
 | ||||
| 	void append_text(wxString text); | ||||
| 	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() {} | ||||
| 	virtual void apply_custom_config(DynamicPrintConfig &config) {} | ||||
| 
 | ||||
| 	void enable_next(bool enable); | ||||
| private: | ||||
| 	ConfigWizardPage *p_prev; | ||||
| 	ConfigWizardPage *p_next; | ||||
| }; | ||||
| 
 | ||||
| struct PageWelcome: ConfigWizardPage | ||||
| { | ||||
| 	PrinterPicker *printer_picker; | ||||
| 	wxPanel *others_buttons; | ||||
| 
 | ||||
| 	PageWelcome(ConfigWizard *parent); | ||||
| 
 | ||||
| 	virtual wxPanel* extra_buttons() { return others_buttons; } | ||||
| 	virtual void on_page_set(); | ||||
| 
 | ||||
| 	void on_variant_checked(); | ||||
| }; | ||||
| 
 | ||||
| struct PageUpdate: ConfigWizardPage | ||||
| { | ||||
| 	bool version_check; | ||||
| 	bool preset_update; | ||||
| 
 | ||||
| 	PageUpdate(ConfigWizard *parent); | ||||
| }; | ||||
| 
 | ||||
| struct PageVendors: ConfigWizardPage | ||||
| { | ||||
| 	std::vector<PrinterPicker*> pickers; | ||||
| 
 | ||||
| 	PageVendors(ConfigWizard *parent); | ||||
| 
 | ||||
| 	virtual void on_page_set(); | ||||
| 
 | ||||
| 	void on_vendor_pick(size_t i); | ||||
| 	void on_variant_checked(); | ||||
| }; | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
| 	wxSpinCtrlDouble *spin_extr; | ||||
| 	wxSpinCtrlDouble *spin_bed; | ||||
| 
 | ||||
| 	PageTemperatures(ConfigWizard *parent); | ||||
| 	virtual void apply_custom_config(DynamicPrintConfig &config); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 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<wxString> items; | ||||
| 	std::vector<wxString>::const_iterator item_active; | ||||
| 
 | ||||
| 	void on_paint(wxPaintEvent &evt); | ||||
| }; | ||||
| 
 | ||||
| struct ConfigWizard::priv | ||||
| { | ||||
| 	ConfigWizard *q; | ||||
| 	AppConfig appconfig_vendors; | ||||
| 	PresetBundle bundle_vendors; | ||||
| 	std::unique_ptr<DynamicPrintConfig> custom_config; | ||||
| 
 | ||||
| 	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 load_vendors(); | ||||
| 	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); | ||||
| 
 | ||||
| 	void on_other_vendors(); | ||||
| 	void on_custom_setup(); | ||||
| 
 | ||||
| 	void apply_config(AppConfig *app_config, PresetBundle *preset_bundle); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -46,6 +46,7 @@ | |||
| #include "AppConfig.hpp" | ||||
| #include "ConfigSnapshotDialog.hpp" | ||||
| #include "Utils.hpp" | ||||
| #include "ConfigWizard.hpp" | ||||
| #include "Preferences.hpp" | ||||
| #include "PresetBundle.hpp" | ||||
| 
 | ||||
|  | @ -397,6 +398,21 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l | |||
| 	menu->Append(local_menu, _(L("&Configuration"))); | ||||
| } | ||||
| 
 | ||||
| bool open_config_wizard(PresetBundle *preset_bundle) | ||||
| { | ||||
| 	if (g_wxMainFrame == nullptr) { | ||||
| 		throw std::runtime_error("Main frame not set"); | ||||
| 	} | ||||
| 
 | ||||
| 	return ConfigWizard::run(g_wxMainFrame, preset_bundle); | ||||
| } | ||||
| 
 | ||||
| void open_preferences_dialog(int event_preferences) | ||||
| { | ||||
| 	auto dlg = new PreferencesDialog(g_wxMainFrame, event_preferences); | ||||
| 	dlg->ShowModal(); | ||||
| } | ||||
| 
 | ||||
| void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed) | ||||
| {	 | ||||
| 	add_created_tab(new TabPrint	(g_wxTabPanel, no_controller)); | ||||
|  |  | |||
|  | @ -84,6 +84,12 @@ wxColour*	get_sys_label_clr(); | |||
| 
 | ||||
| void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change); | ||||
| 
 | ||||
| // 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); | ||||
| 
 | ||||
| // Create a new preset tab (print, filament and printer),
 | ||||
| void create_preset_tabs(bool no_controller, int event_value_change, int event_presets_changed); | ||||
| TabIface* get_preset_tab_iface(char *name); | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ void PreferencesDialog::build() | |||
| 		m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0"; | ||||
| 	}; | ||||
| 
 | ||||
| 	// TODO
 | ||||
| //    $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
 | ||||
| //        opt_id = > 'version_check',
 | ||||
| //        type = > 'bool',
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include <cassert> | ||||
| 
 | ||||
| #include "Preset.hpp" | ||||
| #include "AppConfig.hpp" | ||||
| 
 | ||||
| #include <fstream> | ||||
| #include <boost/filesystem.hpp> | ||||
|  | @ -175,6 +176,15 @@ 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); | ||||
| } | ||||
| 
 | ||||
| const std::vector<std::string>& Preset::print_options() | ||||
| {     | ||||
|     static std::vector<std::string> s_opts { | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ class wxItemContainer; | |||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class AppConfig; | ||||
| 
 | ||||
| enum ConfigFileType | ||||
| { | ||||
|     CONFIG_FILE_TYPE_UNKNOWN, | ||||
|  | @ -35,14 +37,12 @@ public: | |||
|         PrinterVariant() {} | ||||
|         PrinterVariant(const std::string &name) : name(name) {} | ||||
|         std::string                 name; | ||||
|         bool                        enabled = true; | ||||
|     }; | ||||
| 
 | ||||
|     struct PrinterModel { | ||||
|         PrinterModel() {} | ||||
|         PrinterModel(const std::string &name) : name(name) {} | ||||
|         std::string                 id; | ||||
|         std::string                 name; | ||||
|         bool                        enabled = true; | ||||
|         std::vector<PrinterVariant> variants; | ||||
|         PrinterVariant*       variant(const std::string &name) { | ||||
|             for (auto &v : this->variants) | ||||
|  | @ -51,11 +51,10 @@ public: | |||
|             return nullptr; | ||||
|         } | ||||
|         const PrinterVariant* variant(const std::string &name) const { return const_cast<PrinterModel*>(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<PrinterModel>          models; | ||||
|     std::vector<PrinterModel>          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; } | ||||
| 
 | ||||
|  | @ -86,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.
 | ||||
|     // 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?
 | ||||
|  | @ -132,6 +132,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); } | ||||
| 
 | ||||
|  | @ -163,6 +166,13 @@ public: | |||
|     PresetCollection(Preset::Type type, const std::vector<std::string> &keys); | ||||
|     ~PresetCollection(); | ||||
| 
 | ||||
|     typedef std::deque<Preset>::iterator Iterator; | ||||
|     typedef std::deque<Preset>::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; } | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include "PresetBundle.hpp" | ||||
| #include "BitmapCache.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <fstream> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/algorithm/clamp.hpp> | ||||
|  | @ -104,6 +105,7 @@ void PresetBundle::setup_directories() | |||
|     std::initializer_list<boost::filesystem::path> paths = {  | ||||
|         data_dir, | ||||
| 		data_dir / "vendor", | ||||
|         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",  | ||||
|  | @ -198,7 +200,9 @@ 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) | ||||
| { | ||||
|     // m_storage
 | ||||
|     for (auto &preset : printers) { | ||||
|         preset.set_visible_from_appconfig(config); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Load selections (current print, current filaments, current printer) from config.ini
 | ||||
|  | @ -218,6 +222,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
 | ||||
|  | @ -667,7 +675,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 +690,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<std::string>("name", model.id); | ||||
|             section.second.get<std::string>("variants", ""); | ||||
|             std::vector<std::string> variants; | ||||
|             if (Slic3r::unescape_strings_cstyle(section.second.get<std::string>("variants", ""), variants)) { | ||||
|  | @ -693,9 +702,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
 | ||||
|  | @ -703,6 +713,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); | ||||
| } | ||||
| 
 | ||||
|  | @ -719,12 +734,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().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.")); | ||||
|  | @ -732,6 +746,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<std::string> loaded_prints; | ||||
|  | @ -803,7 +824,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."; | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include "Preset.hpp" | ||||
| 
 | ||||
| #include <set> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -81,12 +82,14 @@ 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); | ||||
| 
 | ||||
|     // 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);
 | ||||
|  |  | |||
							
								
								
									
										137
									
								
								xs/src/slic3r/Utils/PresetUpdater.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								xs/src/slic3r/Utils/PresetUpdater.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,137 @@ | |||
| #include "PresetUpdater.hpp" | ||||
| 
 | ||||
| #include <iostream>  // XXX
 | ||||
| #include <thread> | ||||
| #include <boost/algorithm/string.hpp> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| 
 | ||||
| #include <wx/app.h> | ||||
| #include <wx/event.h> | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "slic3r/GUI/GUI.hpp" | ||||
| #include "slic3r/GUI/PresetBundle.hpp" | ||||
| #include "slic3r/Utils/Http.hpp" | ||||
| #include "slic3r/Utils/Semver.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<VendorProfile> 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<VendorProfile> 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<VendorProfile> vendors = preset_bundle->vendors; | ||||
| 
 | ||||
| 	p->thread = std::move(std::thread([this, vendors]() { | ||||
| 		this->p->download(std::move(vendors)); | ||||
| 	})); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										30
									
								
								xs/src/slic3r/Utils/PresetUpdater.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								xs/src/slic3r/Utils/PresetUpdater.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| #ifndef slic3r_PresetUpdate_hpp_ | ||||
| #define slic3r_PresetUpdate_hpp_ | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| 
 | ||||
| class AppConfig; | ||||
| class PresetBundle; | ||||
| 
 | ||||
| class PresetUpdater | ||||
| { | ||||
| public: | ||||
| 	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(); | ||||
| 
 | ||||
| 	void download(PresetBundle *preset_bundle); | ||||
| private: | ||||
| 	struct priv; | ||||
| 	std::unique_ptr<priv> p; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| #endif | ||||
|  | @ -57,6 +57,12 @@ int combochecklist_get_flags(SV *ui) | |||
| void set_app_config(AppConfig *app_config) | ||||
|     %code%{ Slic3r::GUI::set_app_config(app_config); %}; | ||||
| 
 | ||||
| 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); %}; | ||||
| 
 | ||||
| void set_preset_bundle(PresetBundle *preset_bundle) | ||||
|     %code%{ Slic3r::GUI::set_preset_bundle(preset_bundle); %}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -43,4 +43,5 @@ | |||
|     void                        update_last_output_dir(char *dir); | ||||
| 
 | ||||
|     void                        reset_selections(); | ||||
|     bool                        slic3r_update_avail() const; | ||||
| }; | ||||
|  |  | |||
|  | @ -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()); | ||||
|             } | ||||
|  |  | |||
							
								
								
									
										11
									
								
								xs/xsp/Utils_PresetUpdater.xsp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								xs/xsp/Utils_PresetUpdater.xsp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| %module{Slic3r::XS}; | ||||
| 
 | ||||
| %{ | ||||
| #include <xsinit.h> | ||||
| #include "slic3r/Utils/PresetUpdater.hpp" | ||||
| %} | ||||
| 
 | ||||
| %name{Slic3r::PresetUpdater} class PresetUpdater { | ||||
|     PresetUpdater(int version_online_event, AppConfig *app_config); | ||||
|     void download(PresetBundle* preset_bundle); | ||||
| }; | ||||
|  | @ -236,6 +236,10 @@ Ref<PresetHints>    		O_OBJECT_SLIC3R_T | |||
| TabIface*	   				O_OBJECT_SLIC3R | ||||
| Ref<TabIface> 				O_OBJECT_SLIC3R_T | ||||
| 
 | ||||
| PresetUpdater*              O_OBJECT_SLIC3R | ||||
| Ref<PresetUpdater>          O_OBJECT_SLIC3R_T | ||||
| Clone<PresetUpdater>        O_OBJECT_SLIC3R_T | ||||
| 
 | ||||
| OctoPrint*                  O_OBJECT_SLIC3R | ||||
| Ref<OctoPrint>              O_OBJECT_SLIC3R_T | ||||
| Clone<OctoPrint>            O_OBJECT_SLIC3R_T | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv