mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	WIP OctoPrint integration
This commit is contained in:
		
							parent
							
								
									0bba116455
								
							
						
					
					
						commit
						2350fb62b9
					
				
					 18 changed files with 314 additions and 172 deletions
				
			
		|  | @ -1297,10 +1297,11 @@ void PrintConfigDef::init_fff_params() | |||
|     def->default_value = new ConfigOptionString(""); | ||||
|      | ||||
|     def = this->add("printhost_cafile", coString); | ||||
|     def->label = "HTTPS CA file"; | ||||
|     def->label = "HTTPS CA File"; | ||||
|     def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. " | ||||
|                    "If left blank, the default OS CA certificate repository is used."; | ||||
|     def->cli = "printhost-cafile=s"; | ||||
|     def->mode = comAdvanced; | ||||
|     def->default_value = new ConfigOptionString(""); | ||||
| 
 | ||||
|     def = this->add("print_host", coString); | ||||
|  |  | |||
|  | @ -103,12 +103,12 @@ add_library(libslic3r_gui STATIC | |||
|     GUI/ProgressIndicator.hpp | ||||
|     GUI/ProgressStatusBar.hpp | ||||
|     GUI/ProgressStatusBar.cpp | ||||
|     GUI/PrintHostDialogs.cpp | ||||
|     GUI/PrintHostDialogs.hpp | ||||
|     Utils/Http.cpp | ||||
|     Utils/Http.hpp | ||||
|     Utils/FixModelByWin10.cpp | ||||
|     Utils/FixModelByWin10.hpp | ||||
|     Utils/PrintHostSendDialog.cpp | ||||
|     Utils/PrintHostSendDialog.hpp | ||||
|     Utils/OctoPrint.cpp | ||||
|     Utils/OctoPrint.hpp | ||||
|     Utils/Duet.cpp | ||||
|  |  | |||
|  | @ -19,9 +19,12 @@ | |||
| //#undef NDEBUG
 | ||||
| #include <cassert> | ||||
| #include <stdexcept> | ||||
| #include <cctype> | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| #include <boost/nowide/cstdio.hpp> | ||||
| 
 | ||||
|  | @ -62,6 +65,11 @@ PrinterTechnology BackgroundSlicingProcess::current_printer_technology() const | |||
| 	return m_print->technology(); | ||||
| } | ||||
| 
 | ||||
| static bool isspace(int ch) | ||||
| { | ||||
| 	return std::isspace(ch) != 0; | ||||
| } | ||||
| 
 | ||||
| // This function may one day be merged into the Print, but historically the print was separated
 | ||||
| // from the G-code generator.
 | ||||
| void BackgroundSlicingProcess::process_fff() | ||||
|  | @ -80,8 +88,8 @@ void BackgroundSlicingProcess::process_fff() | |||
| 		    	PlaceholderParser pp; | ||||
| 		    	std::string normal_print_time = stats.estimated_normal_print_time; | ||||
| 		    	std::string silent_print_time = stats.estimated_silent_print_time; | ||||
| 				normal_print_time.erase(std::remove_if(normal_print_time.begin(), normal_print_time.end(), std::isspace), normal_print_time.end()); | ||||
| 				silent_print_time.erase(std::remove_if(silent_print_time.begin(), silent_print_time.end(), std::isspace), silent_print_time.end()); | ||||
| 				normal_print_time.erase(std::remove_if(normal_print_time.begin(), normal_print_time.end(), isspace), normal_print_time.end()); | ||||
| 				silent_print_time.erase(std::remove_if(silent_print_time.begin(), silent_print_time.end(), isspace), silent_print_time.end()); | ||||
| 		    	pp.set("print_time",        		new ConfigOptionString(normal_print_time)); | ||||
| 		    	pp.set("normal_print_time", 		new ConfigOptionString(normal_print_time)); | ||||
| 		    	pp.set("silent_print_time", 		new ConfigOptionString(silent_print_time)); | ||||
|  | @ -373,6 +381,22 @@ void BackgroundSlicingProcess::schedule_export(const std::string &path) | |||
| 	m_export_path = path; | ||||
| } | ||||
| 
 | ||||
| void BackgroundSlicingProcess::schedule_upload(Slic3r::PrintHostJob upload_job) | ||||
| { | ||||
| 	assert(m_export_path.empty()); | ||||
| 	if (! m_export_path.empty()) | ||||
| 		return; | ||||
| 
 | ||||
| 	const auto path = boost::filesystem::temp_directory_path() | ||||
| 		/ boost::filesystem::unique_path(".upload.%%%%-%%%%-%%%%-%%%%.gcode"); | ||||
| 
 | ||||
| 	// Guard against entering the export step before changing the export path.
 | ||||
| 	tbb::mutex::scoped_lock lock(m_print->state_mutex()); | ||||
| 	this->invalidate_step(bspsGCodeFinalize); | ||||
| 	m_export_path = path.native(); | ||||
| 	m_upload_job = std::move(upload_job); | ||||
| } | ||||
| 
 | ||||
| void BackgroundSlicingProcess::reset_export() | ||||
| { | ||||
| 	assert(! this->running()); | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <wx/event.h> | ||||
| 
 | ||||
| #include "libslic3r/Print.hpp" | ||||
| #include "slic3r/Utils/PrintHost.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -86,6 +87,9 @@ public: | |||
| 	// Set the export path of the G-code.
 | ||||
| 	// Once the path is set, the G-code 
 | ||||
| 	void schedule_export(const std::string &path); | ||||
| 	// Set print host upload job data to be enqueued to the PrintHostJobQueue
 | ||||
| 	// after current print slicing is complete
 | ||||
| 	void schedule_upload(Slic3r::PrintHostJob upload_job); | ||||
| 	// Clear m_export_path.
 | ||||
| 	void reset_export(); | ||||
| 	// Once the G-code export is scheduled, the apply() methods will do nothing.
 | ||||
|  | @ -143,6 +147,9 @@ private: | |||
| 	// Output path provided by the user. The output path may be set even if the slicing is running,
 | ||||
| 	// but once set, it cannot be re-set.
 | ||||
| 	std::string 				m_export_path; | ||||
| 	// Print host upload job to schedule after slicing is complete, used by schedule_upload(),
 | ||||
| 	// empty by default (ie. no upload to schedule)
 | ||||
| 	PrintHostJob                m_upload_job; | ||||
| 	// Thread, on which the background processing is executed. The thread will always be present
 | ||||
| 	// and ready to execute the slicing process.
 | ||||
| 	std::thread		 			m_thread; | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| #include "3DScene.hpp" | ||||
| 
 | ||||
| #include "../Utils/PresetUpdater.hpp" | ||||
| #include "../Utils/PrintHost.hpp" | ||||
| #include "ConfigWizard_private.hpp" | ||||
| #include "slic3r/Config/Snapshot.hpp" | ||||
| #include "ConfigSnapshotDialog.hpp" | ||||
|  | @ -72,6 +73,7 @@ GUI_App::GUI_App() | |||
|     : wxApp() | ||||
| #if ENABLE_IMGUI | ||||
|     , m_imgui(new ImGuiWrapper()) | ||||
|     , m_printhost_queue(new PrintHostJobQueue()) | ||||
| #endif // ENABLE_IMGUI
 | ||||
| {} | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ class AppConfig; | |||
| class PresetBundle; | ||||
| class PresetUpdater; | ||||
| class ModelObject; | ||||
| class PrintHostJobQueue; | ||||
| 
 | ||||
| namespace GUI | ||||
| { | ||||
|  | @ -91,6 +92,8 @@ class GUI_App : public wxApp | |||
|     std::unique_ptr<ImGuiWrapper> m_imgui; | ||||
| #endif // ENABLE_IMGUI
 | ||||
| 
 | ||||
|     std::unique_ptr<PrintHostJobQueue> m_printhost_queue; | ||||
| 
 | ||||
| public: | ||||
|     bool            OnInit() override; | ||||
| 
 | ||||
|  | @ -161,6 +164,8 @@ public: | |||
|     ImGuiWrapper* imgui() { return m_imgui.get(); } | ||||
| #endif // ENABLE_IMGUI
 | ||||
| 
 | ||||
|     PrintHostJobQueue& printhost_queue() { return *m_printhost_queue.get(); } | ||||
| 
 | ||||
| }; | ||||
| DECLARE_APP(GUI_App) | ||||
| 
 | ||||
|  |  | |||
|  | @ -794,7 +794,7 @@ void MainFrame::update_ui_from_settings() | |||
| { | ||||
|     bool bp_on = wxGetApp().app_config->get("background_processing") == "1"; | ||||
|     m_menu_item_reslice_now->Enable(bp_on); | ||||
|     m_plater->sidebar().show_button(baReslice, !bp_on); | ||||
|     m_plater->sidebar().show_reslice(!bp_on); | ||||
|     m_plater->sidebar().Layout(); | ||||
|     if (m_plater) | ||||
|         m_plater->update_ui_from_settings(); | ||||
|  |  | |||
|  | @ -54,7 +54,9 @@ | |||
| #include "PresetBundle.hpp" | ||||
| #include "BackgroundSlicingProcess.hpp" | ||||
| #include "ProgressStatusBar.hpp" | ||||
| #include "PrintHostDialogs.hpp" | ||||
| #include "../Utils/ASCIIFolding.hpp" | ||||
| #include "../Utils/PrintHost.hpp" | ||||
| #include "../Utils/FixModelByWin10.hpp" | ||||
| 
 | ||||
| #include <wx/glcanvas.h>    // Needs to be last because reasons :-/
 | ||||
|  | @ -64,6 +66,7 @@ using boost::optional; | |||
| namespace fs = boost::filesystem; | ||||
| using Slic3r::_3DScene; | ||||
| using Slic3r::Preset; | ||||
| using Slic3r::PrintHostJob; | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -447,7 +450,6 @@ struct Sidebar::priv | |||
| 
 | ||||
|     wxButton *btn_export_gcode; | ||||
|     wxButton *btn_reslice; | ||||
|     // wxButton *btn_print;  // XXX: remove
 | ||||
|     wxButton *btn_send_gcode; | ||||
| 
 | ||||
|     priv(Plater *plater) : plater(plater) {} | ||||
|  | @ -543,13 +545,12 @@ Sidebar::Sidebar(Plater *parent) | |||
|     p->object_settings->Hide(); | ||||
|     p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxLEFT | wxTOP, 20); | ||||
| 
 | ||||
|     // Buttons in the scrolled area
 | ||||
|     wxBitmap arrow_up(GUI::from_u8(Slic3r::var("brick_go.png")), wxBITMAP_TYPE_PNG); | ||||
|     p->btn_send_gcode = new wxButton(p->scrolled, wxID_ANY, _(L("Send to printer"))); | ||||
|     p->btn_send_gcode = new wxButton(this, wxID_ANY, _(L("Send to printer"))); | ||||
|     p->btn_send_gcode->SetBitmap(arrow_up); | ||||
|     p->btn_send_gcode->SetFont(wxGetApp().bold_font()); | ||||
|     p->btn_send_gcode->Hide(); | ||||
|     auto *btns_sizer_scrolled = new wxBoxSizer(wxHORIZONTAL); | ||||
|     btns_sizer_scrolled->Add(p->btn_send_gcode); | ||||
| 
 | ||||
|     // Info boxes
 | ||||
|     p->object_info = new ObjectInfo(p->scrolled); | ||||
|  | @ -559,7 +560,6 @@ Sidebar::Sidebar(Plater *parent) | |||
|     scrolled_sizer->Add(p->sizer_presets, 0, wxEXPAND | wxLEFT, 2); | ||||
|     scrolled_sizer->Add(p->sizer_params, 1, wxEXPAND); | ||||
|     scrolled_sizer->Add(p->object_info, 0, wxEXPAND | wxTOP | wxLEFT, 20); | ||||
|     scrolled_sizer->Add(btns_sizer_scrolled, 0, wxEXPAND, 0); | ||||
|     scrolled_sizer->Add(p->sliced_info, 0, wxEXPAND | wxTOP | wxLEFT, 20); | ||||
| 
 | ||||
|     // Buttons underneath the scrolled area
 | ||||
|  | @ -571,6 +571,7 @@ Sidebar::Sidebar(Plater *parent) | |||
| 
 | ||||
|     auto *btns_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|     btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, 5); | ||||
|     btns_sizer->Add(p->btn_send_gcode, 0, wxEXPAND | wxTOP, 5); | ||||
|     btns_sizer->Add(p->btn_export_gcode, 0, wxEXPAND | wxTOP, 5); | ||||
| 
 | ||||
|     auto *sizer = new wxBoxSizer(wxVERTICAL); | ||||
|  | @ -820,14 +821,6 @@ void Sidebar::show_sliced_info_sizer(const bool show) | |||
|     p->scrolled->Refresh(); | ||||
| } | ||||
| 
 | ||||
| void Sidebar::show_buttons(const bool show) | ||||
| { | ||||
|     p->btn_reslice->Show(show); | ||||
|     TabPrinter *tab = dynamic_cast<TabPrinter*>(wxGetApp().get_tab(Preset::TYPE_PRINTER)); | ||||
| 	if (tab && p->plater->printer_technology() == ptFFF) | ||||
|         p->btn_send_gcode->Show(show && !tab->m_config->opt_string("print_host").empty()); | ||||
| } | ||||
| 
 | ||||
| void Sidebar::enable_buttons(bool enable) | ||||
| { | ||||
|     p->btn_reslice->Enable(enable); | ||||
|  | @ -835,23 +828,8 @@ void Sidebar::enable_buttons(bool enable) | |||
|     p->btn_send_gcode->Enable(enable); | ||||
| } | ||||
| 
 | ||||
| void Sidebar::show_button(ButtonAction but_action, bool show) | ||||
| { | ||||
|     switch (but_action) | ||||
|     { | ||||
|     case baReslice: | ||||
|         p->btn_reslice->Show(show); | ||||
|         break; | ||||
|     case baExportGcode: | ||||
|         p->btn_export_gcode->Show(show); | ||||
|         break; | ||||
|     case baSendGcode: | ||||
|         p->btn_send_gcode->Show(show); | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| void Sidebar::show_reslice(bool show) { p->btn_reslice->Show(show); } | ||||
| void Sidebar::show_send(bool show) { p->btn_send_gcode->Show(show); } | ||||
| 
 | ||||
| bool Sidebar::is_multifilament() | ||||
| { | ||||
|  | @ -1008,6 +986,7 @@ struct Plater::priv | |||
|     }; | ||||
|     // returns bit mask of UpdateBackgroundProcessReturnState
 | ||||
|     unsigned int update_background_process(); | ||||
|     void export_gcode(fs::path output_path, PrintHostJob upload_job); | ||||
|     void async_apply_config(); | ||||
|     void reload_from_disk(); | ||||
|     void fix_through_netfabb(const int obj_idx); | ||||
|  | @ -2059,6 +2038,45 @@ unsigned int Plater::priv::update_background_process() | |||
|     return return_state; | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::export_gcode(fs::path output_path, PrintHostJob upload_job) | ||||
| { | ||||
|     wxCHECK_RET(!(output_path.empty() && upload_job.empty()), "export_gcode: output_path and upload_job empty"); | ||||
| 
 | ||||
|     if (model.objects.empty()) | ||||
|         return; | ||||
| 
 | ||||
|     if (background_process.is_export_scheduled()) { | ||||
|         GUI::show_error(q, _(L("Another export job is currently running."))); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // bitmask of UpdateBackgroundProcessReturnState
 | ||||
|     unsigned int state = update_background_process(); | ||||
|     if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) | ||||
| #if ENABLE_REMOVE_TABS_FROM_PLATER | ||||
|         view3D->reload_scene(false); | ||||
| #else | ||||
|         canvas3D->reload_scene(false); | ||||
| #endif // ENABLE_REMOVE_TABS_FROM_PLATER
 | ||||
|     if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0) | ||||
|         return; | ||||
| 
 | ||||
|     if (! output_path.empty()) { | ||||
|         background_process.schedule_export(output_path.string()); | ||||
|     } else { | ||||
|         background_process.schedule_upload(std::move(upload_job)); | ||||
|     } | ||||
| 
 | ||||
|     if (! background_process.running()) { | ||||
|         // The print is valid and it should be started.
 | ||||
|         if (background_process.start()) | ||||
|             statusbar()->set_cancel_callback([this]() { | ||||
|                 statusbar()->set_status_text(L("Cancelling")); | ||||
|                 background_process.stop(); | ||||
|             }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::async_apply_config() | ||||
| { | ||||
|     // bitmask of UpdateBackgroundProcessReturnState
 | ||||
|  | @ -2912,42 +2930,26 @@ void Plater::export_gcode(fs::path output_path) | |||
|     if (p->model.objects.empty()) | ||||
|         return; | ||||
| 
 | ||||
|     if (this->p->background_process.is_export_scheduled()) { | ||||
|         GUI::show_error(this, _(L("Another export job is currently running."))); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // bitmask of UpdateBackgroundProcessReturnState
 | ||||
|     unsigned int state = this->p->update_background_process(); | ||||
|     if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) | ||||
| #if ENABLE_REMOVE_TABS_FROM_PLATER | ||||
|         this->p->view3D->reload_scene(false); | ||||
| #else | ||||
|         this->p->canvas3D->reload_scene(false); | ||||
| #endif // ENABLE_REMOVE_TABS_FROM_PLATER
 | ||||
|     if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0) | ||||
|         return; | ||||
| 
 | ||||
|     // select output file
 | ||||
|     if (output_path.empty()) { | ||||
|         // XXX: take output path from CLI opts? Ancient Slic3r versions used to do that...
 | ||||
| 
 | ||||
|         // If possible, remove accents from accented latin characters.
 | ||||
|         // This function is useful for generating file names to be processed by legacy firmwares.
 | ||||
| 		fs::path default_output_file; | ||||
|         fs::path default_output_file; | ||||
|         try { | ||||
| 			default_output_file = this->p->background_process.current_print()->output_filepath(output_path.string()); | ||||
|             default_output_file = this->p->background_process.current_print()->output_filepath(output_path.string()); | ||||
|         } catch (const std::exception &ex) { | ||||
|             show_error(this, ex.what()); | ||||
|             return; | ||||
|         } | ||||
| 		default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); | ||||
|         default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); | ||||
|         auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); | ||||
| 
 | ||||
| 		wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")), | ||||
|         wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")), | ||||
|             start_dir, | ||||
|             default_output_file.filename().string(), | ||||
| 			GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), | ||||
|             GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), | ||||
|             wxFD_SAVE | wxFD_OVERWRITE_PROMPT | ||||
|         ); | ||||
| 
 | ||||
|  | @ -2958,23 +2960,15 @@ void Plater::export_gcode(fs::path output_path) | |||
|         } | ||||
|     } else { | ||||
|         try { | ||||
| 			output_path = this->p->background_process.current_print()->output_filepath(output_path.string()); | ||||
|             output_path = this->p->background_process.current_print()->output_filepath(output_path.string()); | ||||
|         } catch (const std::exception &ex) { | ||||
|             show_error(this, ex.what()); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (! output_path.empty()) | ||||
|         this->p->background_process.schedule_export(output_path.string()); | ||||
| 
 | ||||
|     if ((! output_path.empty() || this->p->background_processing_enabled()) && ! this->p->background_process.running()) { | ||||
|         // The print is valid and it should be started.
 | ||||
|         if (this->p->background_process.start()) | ||||
|             this->p->statusbar()->set_cancel_callback([this]() { | ||||
|                 this->p->statusbar()->set_status_text(L("Cancelling")); | ||||
|                 this->p->background_process.stop(); | ||||
|             }); | ||||
|     if (! output_path.empty()) { | ||||
|         p->export_gcode(std::move(output_path), PrintHostJob()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -3077,7 +3071,28 @@ void Plater::reslice() | |||
| 
 | ||||
| void Plater::send_gcode() | ||||
| { | ||||
| //    p->send_gcode_file = export_gcode();
 | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| 
 | ||||
|     PrintHostJob upload_job(p->config); | ||||
|     if (upload_job.empty()) { return; } | ||||
| 
 | ||||
|     // Obtain default output path
 | ||||
|     fs::path default_output_file; | ||||
|     try { | ||||
|         default_output_file = this->p->background_process.current_print()->output_filepath(""); | ||||
|     } catch (const std::exception &ex) { | ||||
|         show_error(this, ex.what()); | ||||
|         return; | ||||
|     } | ||||
|     default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); | ||||
| 
 | ||||
|     Slic3r::PrintHostSendDialog dlg(default_output_file); | ||||
|     if (dlg.ShowModal() == wxID_OK) { | ||||
|         upload_job.upload_data.upload_path = dlg.filename(); | ||||
|         upload_job.upload_data.start_print = dlg.start_print(); | ||||
| 
 | ||||
|         p->export_gcode(fs::path(), std::move(upload_job)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Plater::on_extruders_change(int num_extruders) | ||||
|  | @ -3127,14 +3142,6 @@ void Plater::on_config_change(const DynamicPrintConfig &config) | |||
|             opt_key == "single_extruder_multi_material") { | ||||
|             update_scheduled = true; | ||||
|         }  | ||||
| //         else if(opt_key == "serial_port") {
 | ||||
| //             sidebar()->p->btn_print->Show(config.get("serial_port"));  // ???: btn_print is removed
 | ||||
| //             Layout();
 | ||||
| //         } 
 | ||||
|         else if (opt_key == "print_host") { | ||||
|             sidebar().show_button(baReslice, !p->config->option<ConfigOptionString>(opt_key)->value.empty()); | ||||
|             Layout(); | ||||
|         } | ||||
|         else if(opt_key == "variable_layer_height") { | ||||
|             if (p->config->opt_bool("variable_layer_height") != true) { | ||||
| #if ENABLE_REMOVE_TABS_FROM_PLATER | ||||
|  | @ -3174,6 +3181,11 @@ void Plater::on_config_change(const DynamicPrintConfig &config) | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         const auto prin_host_opt = p->config->option<ConfigOptionString>("print_host"); | ||||
|         p->sidebar->show_send(prin_host_opt != nullptr && !prin_host_opt->value.empty()); | ||||
|     } | ||||
| 
 | ||||
|     if (update_scheduled)  | ||||
|         update(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -55,14 +55,6 @@ private: | |||
|     int extruder_idx = -1; | ||||
| }; | ||||
| 
 | ||||
| enum ButtonAction | ||||
| { | ||||
|     baUndef, | ||||
|     baReslice, | ||||
|     baExportGcode, | ||||
|     baSendGcode | ||||
| }; | ||||
| 
 | ||||
| class Sidebar : public wxPanel | ||||
| { | ||||
|     /*ConfigMenuIDs*/int    m_mode; | ||||
|  | @ -88,9 +80,9 @@ public: | |||
|     void                    update_objects_list_extruder_column(int extruders_count); | ||||
|     void                    show_info_sizer(); | ||||
|     void                    show_sliced_info_sizer(const bool show); | ||||
|     void                    show_buttons(const bool show); | ||||
|     void                    show_button(ButtonAction but_action, bool show); | ||||
|     void                    enable_buttons(bool enable); | ||||
|     void                    show_reslice(bool show); | ||||
|     void                    show_send(bool show); | ||||
|     bool                    is_multifilament(); | ||||
|     void                    set_mode_value(const /*ConfigMenuIDs*/int mode) { m_mode = mode; } | ||||
| 
 | ||||
|  | @ -103,6 +95,8 @@ private: | |||
| class Plater: public wxPanel | ||||
| { | ||||
| public: | ||||
|     using fs_path = boost::filesystem::path; | ||||
| 
 | ||||
|     Plater(wxWindow *parent, MainFrame *main_frame); | ||||
|     Plater(Plater &&) = delete; | ||||
|     Plater(const Plater &) = delete; | ||||
|  |  | |||
							
								
								
									
										49
									
								
								src/slic3r/GUI/PrintHostDialogs.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/slic3r/GUI/PrintHostDialogs.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| #include "PrintHostDialogs.hpp" | ||||
| 
 | ||||
| #include <wx/frame.h> | ||||
| #include <wx/event.h> | ||||
| #include <wx/progdlg.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/stattext.h> | ||||
| #include <wx/textctrl.h> | ||||
| #include <wx/checkbox.h> | ||||
| 
 | ||||
| #include "slic3r/GUI/GUI.hpp" | ||||
| #include "slic3r/GUI/MsgDialog.hpp" | ||||
| #include "slic3r/GUI/I18N.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| PrintHostSendDialog::PrintHostSendDialog(const fs::path &path) | ||||
|     : MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE) | ||||
|     , txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())) | ||||
|     , box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload")))) | ||||
| { | ||||
|     auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed."))); | ||||
|     label_dir_hint->Wrap(CONTENT_WIDTH); | ||||
| 
 | ||||
|     content_sizer->Add(txt_filename, 0, wxEXPAND); | ||||
|     content_sizer->Add(label_dir_hint); | ||||
|     content_sizer->AddSpacer(VERT_SPACING); | ||||
|     content_sizer->Add(box_print, 0, wxBOTTOM, 2*VERT_SPACING); | ||||
| 
 | ||||
|     btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL)); | ||||
| 
 | ||||
|     txt_filename->SetFocus(); | ||||
|     wxString stem(path.stem().wstring()); | ||||
|     txt_filename->SetSelection(0, stem.Length()); | ||||
| 
 | ||||
|     Fit(); | ||||
| } | ||||
| 
 | ||||
| fs::path PrintHostSendDialog::filename() const | ||||
| { | ||||
|     return fs::path(txt_filename->GetValue().wx_str()); | ||||
| } | ||||
| 
 | ||||
| bool PrintHostSendDialog::start_print() const | ||||
| { | ||||
|     return box_print->GetValue(); } | ||||
| } | ||||
|  | @ -20,19 +20,30 @@ | |||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| 
 | ||||
| class PrintHostSendDialog : public GUI::MsgDialog | ||||
| { | ||||
| private: | ||||
| 	wxTextCtrl *txt_filename; | ||||
| 	wxCheckBox *box_print; | ||||
| 	bool can_start_print; | ||||
| 
 | ||||
| public: | ||||
| 	PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print); | ||||
| 	boost::filesystem::path filename() const; | ||||
| 	bool print() const; | ||||
|     PrintHostSendDialog(const boost::filesystem::path &path); | ||||
|     boost::filesystem::path filename() const; | ||||
|     bool start_print() const; | ||||
| 
 | ||||
| private: | ||||
|     wxTextCtrl *txt_filename; | ||||
|     wxCheckBox *box_print; | ||||
|     bool can_start_print; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class PrintHostQueueDialog : public wxDialog | ||||
| { | ||||
| public: | ||||
|     PrintHostQueueDialog(); | ||||
| 
 | ||||
| private: | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,5 +1,4 @@ | |||
| #include "Duet.hpp" | ||||
| #include "PrintHostSendDialog.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <ctime> | ||||
|  | @ -21,6 +20,7 @@ | |||
| #include "slic3r/GUI/GUI.hpp" | ||||
| #include "slic3r/GUI/I18N.hpp" | ||||
| #include "slic3r/GUI/MsgDialog.hpp" | ||||
| #include "slic3r/GUI/PrintHostDialogs.hpp"   // XXX
 | ||||
| #include "Http.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
|  | @ -62,10 +62,10 @@ bool Duet::send_gcode(const std::string &filename) const | |||
| 	const auto errortitle = _(L("Error while uploading to the Duet")); | ||||
| 	fs::path filepath(filename); | ||||
| 
 | ||||
| 	PrintHostSendDialog send_dialog(filepath.filename(), true); | ||||
| 	PrintHostSendDialog send_dialog(filepath.filename()); | ||||
| 	if (send_dialog.ShowModal() != wxID_OK) { return false; } | ||||
| 
 | ||||
| 	const bool print = send_dialog.print();  | ||||
| 	const bool print = send_dialog.start_print(); | ||||
| 	const auto upload_filepath = send_dialog.filename(); | ||||
| 	const auto upload_filename = upload_filepath.filename(); | ||||
| 	const auto upload_parent_path = upload_filepath.parent_path(); | ||||
|  | @ -136,6 +136,11 @@ bool Duet::send_gcode(const std::string &filename) const | |||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| bool Duet::upload(PrintHostUpload upload_data) const | ||||
| { | ||||
| 	throw "unimplemented"; | ||||
| } | ||||
| 
 | ||||
| bool Duet::has_auto_discovery() const | ||||
| { | ||||
| 	return false; | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ public: | |||
| 	wxString get_test_failed_msg (wxString &msg) const; | ||||
| 	// Send gcode file to duet, filename is expected to be in UTF-8
 | ||||
| 	bool send_gcode(const std::string &filename) const; | ||||
| 	bool upload(PrintHostUpload upload_data) const; | ||||
| 	bool has_auto_discovery() const; | ||||
| 	bool can_test() const; | ||||
| private: | ||||
|  |  | |||
|  | @ -1,14 +1,14 @@ | |||
| #include "OctoPrint.hpp" | ||||
| #include "PrintHostSendDialog.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include "libslic3r/PrintConfig.hpp" | ||||
| #include "slic3r/GUI/I18N.hpp" | ||||
| #include "slic3r/GUI/PrintHostDialogs.hpp"   // XXX
 | ||||
| #include "Http.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/I18N.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
| 
 | ||||
|  | @ -66,10 +66,10 @@ bool OctoPrint::send_gcode(const std::string &filename) const | |||
| 	const auto errortitle = _(L("Error while uploading to the OctoPrint server")); | ||||
| 	fs::path filepath(filename); | ||||
| 
 | ||||
| 	PrintHostSendDialog send_dialog(filepath.filename(), true); | ||||
| 	PrintHostSendDialog send_dialog(filepath.filename()); | ||||
| 	if (send_dialog.ShowModal() != wxID_OK) { return false; } | ||||
| 
 | ||||
| 	const bool print = send_dialog.print(); | ||||
| 	const bool print = send_dialog.start_print(); | ||||
| 	const auto upload_filepath = send_dialog.filename(); | ||||
| 	const auto upload_filename = upload_filepath.filename(); | ||||
| 	const auto upload_parent_path = upload_filepath.parent_path(); | ||||
|  | @ -101,7 +101,7 @@ bool OctoPrint::send_gcode(const std::string &filename) const | |||
| 	auto http = Http::post(std::move(url)); | ||||
| 	set_auth(http); | ||||
| 	http.form_add("print", print ? "true" : "false") | ||||
| 		.form_add("path", upload_parent_path.string()) | ||||
| 		.form_add("path", upload_parent_path.string())      // XXX: slashes on windows ???
 | ||||
| 		.form_add_file("file", filename, upload_filename.string()) | ||||
| 		.on_complete([&](std::string body, unsigned status) { | ||||
| 			BOOST_LOG_TRIVIAL(debug) << boost::format("Octoprint: File uploaded: HTTP %1%: %2%") % status % body; | ||||
|  | @ -129,6 +129,11 @@ bool OctoPrint::send_gcode(const std::string &filename) const | |||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| bool OctoPrint::upload(PrintHostUpload upload_data) const | ||||
| { | ||||
| 	throw "unimplemented"; | ||||
| } | ||||
| 
 | ||||
| bool OctoPrint::has_auto_discovery() const | ||||
| { | ||||
| 	return true; | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ public: | |||
| 	wxString get_test_failed_msg (wxString &msg) const; | ||||
| 	// Send gcode file to octoprint, filename is expected to be in UTF-8
 | ||||
| 	bool send_gcode(const std::string &filename) const; | ||||
| 	bool upload(PrintHostUpload upload_data) const; | ||||
| 	bool has_auto_discovery() const; | ||||
| 	bool can_test() const; | ||||
| private: | ||||
|  |  | |||
|  | @ -1,7 +1,15 @@ | |||
| #include "OctoPrint.hpp" | ||||
| #include "Duet.hpp" | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <thread> | ||||
| #include <boost/optional.hpp> | ||||
| 
 | ||||
| #include "libslic3r/PrintConfig.hpp" | ||||
| #include "libslic3r/Channel.hpp" | ||||
| 
 | ||||
| using boost::optional; | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -10,13 +18,42 @@ PrintHost::~PrintHost() {} | |||
| 
 | ||||
| PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) | ||||
| { | ||||
| 	PrintHostType kind = config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value; | ||||
| 	if (kind == htOctoPrint) { | ||||
| 		return new OctoPrint(config); | ||||
| 	} else if (kind == htDuet) { | ||||
| 		return new Duet(config); | ||||
| 	} | ||||
| 	return nullptr; | ||||
|     PrintHostType kind = config->option<ConfigOptionEnum<PrintHostType>>("host_type")->value; | ||||
|     if (kind == htOctoPrint) { | ||||
|         return new OctoPrint(config); | ||||
|     } else if (kind == htDuet) { | ||||
|         return new Duet(config); | ||||
|     } | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct PrintHostJobQueue::priv | ||||
| { | ||||
|     std::vector<PrintHostJob> jobs; | ||||
|     Channel<unsigned> channel; | ||||
| 
 | ||||
|     std::thread bg_thread; | ||||
|     optional<PrintHostJob> bg_job; | ||||
| }; | ||||
| 
 | ||||
| PrintHostJobQueue::PrintHostJobQueue() | ||||
|     : p(new priv()) | ||||
| { | ||||
|     std::shared_ptr<priv> p2 = p; | ||||
|     p->bg_thread = std::thread([p2]() { | ||||
|         // Wait for commands on the channel:
 | ||||
|         auto cmd = p2->channel.pop(); | ||||
|         // TODO
 | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| PrintHostJobQueue::~PrintHostJobQueue() | ||||
| { | ||||
|     // TODO: stop the thread
 | ||||
|     // if (p && p->bg_thread.joinable()) {
 | ||||
|     //     p->bg_thread.detach();
 | ||||
|     // }
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,26 +8,66 @@ | |||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| 
 | ||||
| class DynamicPrintConfig; | ||||
| 
 | ||||
| 
 | ||||
| struct PrintHostUpload | ||||
| { | ||||
|     boost::filesystem::path source_path; | ||||
|     boost::filesystem::path upload_path; | ||||
|     bool start_print = false; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class PrintHost | ||||
| { | ||||
| public: | ||||
| 	virtual ~PrintHost(); | ||||
|     virtual ~PrintHost(); | ||||
| 
 | ||||
| 	virtual bool test(wxString &curl_msg) const = 0; | ||||
| 	virtual wxString get_test_ok_msg () const = 0; | ||||
| 	virtual wxString get_test_failed_msg (wxString &msg) const = 0; | ||||
| 	// Send gcode file to print host, filename is expected to be in UTF-8
 | ||||
| 	virtual bool send_gcode(const std::string &filename) const = 0; | ||||
| 	virtual bool has_auto_discovery() const = 0; | ||||
| 	virtual bool can_test() const = 0; | ||||
|     virtual bool test(wxString &curl_msg) const = 0; | ||||
|     virtual wxString get_test_ok_msg () const = 0; | ||||
|     virtual wxString get_test_failed_msg (wxString &msg) const = 0; | ||||
|     // Send gcode file to print host, filename is expected to be in UTF-8
 | ||||
|     virtual bool send_gcode(const std::string &filename) const = 0;         // XXX: remove in favor of upload()
 | ||||
|     virtual bool upload(PrintHostUpload upload_data) const = 0; | ||||
|     virtual bool has_auto_discovery() const = 0; | ||||
|     virtual bool can_test() const = 0; | ||||
| 
 | ||||
| 	static PrintHost* get_print_host(DynamicPrintConfig *config); | ||||
|     static PrintHost* get_print_host(DynamicPrintConfig *config); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct PrintHostJob | ||||
| { | ||||
|     PrintHostUpload upload_data; | ||||
|     std::unique_ptr<PrintHost> printhost; | ||||
| 
 | ||||
|     PrintHostJob() {} | ||||
|     PrintHostJob(DynamicPrintConfig *config) | ||||
|         : printhost(PrintHost::get_print_host(config)) | ||||
|     {} | ||||
| 
 | ||||
|     bool empty() const { return !printhost; } | ||||
|     operator bool() const { return !!printhost; } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class PrintHostJobQueue | ||||
| { | ||||
| public: | ||||
|     PrintHostJobQueue(); | ||||
|     PrintHostJobQueue(const PrintHostJobQueue &) = delete; | ||||
|     PrintHostJobQueue(PrintHostJobQueue &&other) = delete; | ||||
|     ~PrintHostJobQueue(); | ||||
| 
 | ||||
|     PrintHostJobQueue& operator=(const PrintHostJobQueue &) = delete; | ||||
|     PrintHostJobQueue& operator=(PrintHostJobQueue &&other) = delete; | ||||
| 
 | ||||
| private: | ||||
|     struct priv; | ||||
|     std::shared_ptr<priv> p; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -1,52 +0,0 @@ | |||
| #include "PrintHostSendDialog.hpp" | ||||
| 
 | ||||
| #include <wx/frame.h> | ||||
| #include <wx/event.h> | ||||
| #include <wx/progdlg.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/stattext.h> | ||||
| #include <wx/textctrl.h> | ||||
| #include <wx/checkbox.h> | ||||
| 
 | ||||
| #include "slic3r/GUI/GUI.hpp" | ||||
| #include "slic3r/GUI/MsgDialog.hpp" | ||||
| #include "slic3r/GUI/I18N.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print) : | ||||
| 	MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE), | ||||
| 	txt_filename(new wxTextCtrl(this, wxID_ANY, path.filename().wstring())), | ||||
| 	box_print(new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload")))), | ||||
| 	can_start_print(can_start_print) | ||||
| { | ||||
| 	auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _(L("Use forward slashes ( / ) as a directory separator if needed."))); | ||||
| 	label_dir_hint->Wrap(CONTENT_WIDTH); | ||||
| 
 | ||||
| 	content_sizer->Add(txt_filename, 0, wxEXPAND); | ||||
| 	content_sizer->Add(label_dir_hint); | ||||
| 	content_sizer->AddSpacer(VERT_SPACING); | ||||
| 	content_sizer->Add(box_print, 0, wxBOTTOM, 2*VERT_SPACING); | ||||
| 
 | ||||
| 	btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL)); | ||||
| 
 | ||||
| 	txt_filename->SetFocus(); | ||||
| 	wxString stem(path.stem().wstring()); | ||||
| 	txt_filename->SetSelection(0, stem.Length()); | ||||
| 
 | ||||
| 	box_print->Enable(can_start_print); | ||||
| 
 | ||||
| 	Fit(); | ||||
| } | ||||
| 
 | ||||
| fs::path PrintHostSendDialog::filename() const  | ||||
| { | ||||
| 	return fs::path(txt_filename->GetValue().wx_str()); | ||||
| } | ||||
| 
 | ||||
| bool PrintHostSendDialog::print() const  | ||||
| {  | ||||
| 	return box_print->GetValue(); } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vojtech Kral
						Vojtech Kral