diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 5db68cd3b..5b4856c88 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -19,6 +19,7 @@ use Wx::Locale gettext => 'L'; our $qs_last_input_file; our $qs_last_output_file; our $last_config; +our $appController; # Events to be sent from a C++ Tab implementation: # 1) To inform about a change of a configuration value. @@ -31,6 +32,8 @@ sub new { my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE); Slic3r::GUI::set_main_frame($self); + $appController = Slic3r::AppController->new(); + if ($^O eq 'MSWin32') { # Load the icon either from the exe, or from the ico file. my $iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe'; @@ -61,6 +64,12 @@ sub new { $self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new($self, -1); $self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases")); $self->SetStatusBar($self->{statusbar}); + + # Make the global status bar and its progress indicator available in C++ + $appController->set_global_progress_indicator_id( + $self->{statusbar}->{prog}->GetId(), + $self->{statusbar}->GetId(), + ); $self->{loaded} = 1; @@ -115,6 +124,8 @@ sub _init_tabpanel { if (!$self->{no_controller}) { $panel->AddPage($self->{controller} = Slic3r::GUI::Controller->new($panel), L("Controller")); } + $appController->set_model($self->{plater}->{model}); + $appController->set_print($self->{plater}->{print}); } #TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view. @@ -231,7 +242,7 @@ sub _init_menubar { $self->quick_slice(save_as => 1, export_svg => 1); }, undef, 'shape_handles.png'); $self->_append_menu_item($fileMenu, L("Slice to PNG…"), L('Slice file to a set of PNG files'), sub { - $self->quick_slice(save_as => 0, export_png => 1); + $self->slice_to_png; #$self->quick_slice(save_as => 0, export_png => 1); }, undef, 'shape_handles.png'); $self->{menu_item_reslice_now} = $self->_append_menu_item( $fileMenu, L("(&Re)Slice Now\tCtrl+S"), L('Start new slicing process'), @@ -378,6 +389,11 @@ sub on_plater_selection_changed { for $self->{object_menu}->GetMenuItems; } +sub slice_to_png { + my $self = shift; + $appController->slice_to_png; +} + # To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG". sub quick_slice { my ($self, %params) = @_; diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 14b2aed0a..6dff3a469 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -245,6 +245,8 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/Utils/PresetUpdater.hpp ${LIBDIR}/slic3r/Utils/Time.cpp ${LIBDIR}/slic3r/Utils/Time.hpp + ${LIBDIR}/slic3r/AppController.hpp + ${LIBDIR}/slic3r/AppController.cpp ) add_library(admesh STATIC @@ -437,6 +439,7 @@ set(XS_XSP_FILES ${XSP_DIR}/TriangleMesh.xsp ${XSP_DIR}/Utils_OctoPrint.xsp ${XSP_DIR}/Utils_PresetUpdater.xsp + ${XSP_DIR}/AppController.xsp ${XSP_DIR}/XS.xsp ) foreach (file ${XS_XSP_FILES}) diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 205eec218..5c87899b9 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -65,6 +65,7 @@ REGISTER_CLASS(PresetBundle, "GUI::PresetBundle"); REGISTER_CLASS(TabIface, "GUI::Tab"); REGISTER_CLASS(PresetUpdater, "PresetUpdater"); REGISTER_CLASS(OctoPrint, "OctoPrint"); +REGISTER_CLASS(AppController, "AppController"); SV* ConfigBase__as_hash(ConfigBase* THIS) { diff --git a/xs/src/slic3r/AppController.cpp b/xs/src/slic3r/AppController.cpp new file mode 100644 index 000000000..c954c0cec --- /dev/null +++ b/xs/src/slic3r/AppController.cpp @@ -0,0 +1,274 @@ +#include "AppController.hpp" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Slic3r { + +AppControllerBoilerplate::PathList +AppControllerBoilerplate::query_destination_paths( + const std::string &title, + const std::string &extensions) const +{ + + wxFileDialog dlg(wxTheApp->GetTopWindow(), wxString(title) ); + dlg.SetWildcard(extensions); + + dlg.ShowModal(); + + wxArrayString paths; + dlg.GetFilenames(paths); + + PathList ret(paths.size(), ""); + for(auto& p : paths) ret.push_back(p.ToStdString()); + + return ret; +} + +AppControllerBoilerplate::Path +AppControllerBoilerplate::query_destination_path( + const std::string &title, + const std::string &extensions) const +{ + wxFileDialog dlg(wxTheApp->GetTopWindow(), title ); + dlg.SetWildcard(extensions); + + dlg.ShowModal(); + + Path ret(dlg.GetFilename()); + + return ret; +} + +void AppControllerBoilerplate::report_issue(IssueType issuetype, + const std::string &description, + const std::string &brief) +{ + auto icon = wxICON_INFORMATION; + switch(issuetype) { + case IssueType::INFO: break; + case IssueType::WARN: icon = wxICON_WARNING; break; + case IssueType::ERR: + case IssueType::FATAL: icon = wxICON_ERROR; + } + + wxMessageBox(_(description), _(brief), icon); +} + +AppControllerBoilerplate::ProgresIndicatorPtr +AppControllerBoilerplate::createProgressIndicator(unsigned statenum, + const std::string& title, + const std::string& firstmsg) const +{ + class GuiProgressIndicator: public ProgressIndicator { + wxProgressDialog gauge_; + using Base = ProgressIndicator; + std::string message_; + public: + + inline GuiProgressIndicator(int range, const std::string& title, + const std::string& firstmsg): + gauge_(title, firstmsg, range, wxTheApp->GetTopWindow()) + { + Base::max(static_cast(range)); + Base::states(static_cast(range)); + } + + virtual void state(float val) override { + if( val <= max() && val >= 1.0) { + Base::state(val); + gauge_.Update(static_cast(val), message_); + } + } + + virtual void state(unsigned st) override { + if( st <= max() ) { + Base::state(st); + gauge_.Update(static_cast(st), message_); + if(!gauge_.IsShown()) gauge_.ShowModal(); + } + } + + virtual void message(const std::string & msg) override { + message_ = msg; + } + + virtual void title(const std::string & title) override { + gauge_.SetTitle(title); + } + }; + + auto pri = + std::make_shared(statenum, title, firstmsg); + + return pri; +} + +void AppController::sliceObject(PrintObject *pobj) +{ + assert(pobj != nullptr); + if(pobj->state.is_done(posSlice)) return; + + pobj->state.set_started(posSlice); + + pobj->_slice(); + + auto msg = pobj->_fix_slicing_errors(); + if(!msg.empty()) report_issue(IssueType::WARN, msg); + + // simplify slices if required + if (print_->config.resolution) + pobj->_simplify_slices(scale_(print_->config.resolution)); + + + if(pobj->layers.empty()) + report_issue(IssueType::ERR, + "No layers were detected. You might want to repair your " + "STL file(s) or check their size or thickness and retry" + ); + + pobj->state.set_done(posSlice); +} + +void AppController::slice() +{ + Slic3r::trace(3, "Starting the slicing process."); + + for(auto obj : print_->objects) { + sliceObject(obj); +// print_->//status_cb->(20, "Generating perimeters"); + obj->_make_perimeters(); + } + +// $self->status_cb->(70, "Infilling layers"); + +// $_->infill for @{$self->objects}; + +// $_->generate_support_material for @{$self->objects}; +// $self->make_skirt; +// $self->make_brim; # must come after make_skirt +// $self->make_wipe_tower; + +// # time to make some statistics +// if (0) { +// eval "use Devel::Size"; +// print "MEMORY USAGE:\n"; +// printf " meshes = %.1fMb\n", List::Util::sum(map Devel::Size::total_size($_->meshes), @{$self->objects})/1024/1024; +// printf " layer slices = %.1fMb\n", List::Util::sum(map Devel::Size::total_size($_->slices), map @{$_->layers}, @{$self->objects})/1024/1024; +// printf " region slices = %.1fMb\n", List::Util::sum(map Devel::Size::total_size($_->slices), map @{$_->regions}, map @{$_->layers}, @{$self->objects})/1024/1024; +// printf " perimeters = %.1fMb\n", List::Util::sum(map Devel::Size::total_size($_->perimeters), map @{$_->regions}, map @{$_->layers}, @{$self->objects})/1024/1024; +// printf " fills = %.1fMb\n", List::Util::sum(map Devel::Size::total_size($_->fills), map @{$_->regions}, map @{$_->layers}, @{$self->objects})/1024/1024; +// printf " print object = %.1fMb\n", Devel::Size::total_size($self)/1024/1024; +// } +// if (0) { +// eval "use Slic3r::Test::SectionCut"; +// Slic3r::Test::SectionCut->new(print => $self)->export_svg("section_cut.svg"); +// } +// Slic3r::trace(3, "Slicing process finished.") +} + +void AppController::slice_to_png() +{ + assert(model_ != nullptr); + + auto pri = globalProgressIndicator(); //createProgressIndicator(100, "Gauge", "operation"); + + pri->title("Operation"); + pri->message("..."); + + for(unsigned i = 1; i <= 100; i++ ) { + pri->state(i); + wxMilliSleep(100); + } + +// auto zipfilepath = query_destination_path( "Path to zip file...", +// "*.zip"); + +// auto presetbundle = GUI::get_preset_bundle(); + +// assert(presetbundle); + +// auto conf = presetbundle->full_config(); + +// conf.validate(); + +// slice(); +} + +void AppController::set_global_progress_indicator_id( + unsigned gid, + unsigned sid) +{ + + class Wrapper: public ProgressIndicator { + wxGauge *gauge_; + wxStatusBar *stbar_; + using Base = ProgressIndicator; + std::string message_; + + void showProgress(bool show = true) { + gauge_->Show(show); + gauge_->Pulse(); + } + public: + + inline Wrapper(wxGauge *gauge, wxStatusBar *stbar): + gauge_(gauge), stbar_(stbar) + { + Base::max(static_cast(gauge->GetRange())); + Base::states(static_cast(gauge->GetRange())); + } + + virtual void state(float val) override { + if( val <= max() && val >= 1.0) { + Base::state(val); + stbar_->SetStatusText(message_); + gauge_->SetValue(static_cast(val)); + } + } + + virtual void state(unsigned st) override { + if( st <= max() ) { + Base::state(st); + + if(!gauge_->IsShown()) showProgress(true); + + if(st == gauge_->GetRange()) { + gauge_->SetValue(0); + showProgress(false); + } else { + stbar_->SetStatusText(message_); + gauge_->SetValue(static_cast(st)); + } + } + } + + virtual void message(const std::string & msg) override { + message_ = msg; + } + + virtual void title(const std::string & /*title*/) override {} + + }; + + wxGauge* gauge = dynamic_cast(wxWindow::FindWindowById(gid)); + wxStatusBar* sb = dynamic_cast(wxWindow::FindWindowById(sid)); + + if(gauge && sb) + globalProgressIndicator(std::make_shared(gauge, sb)); +} + +} diff --git a/xs/src/slic3r/AppController.hpp b/xs/src/slic3r/AppController.hpp new file mode 100644 index 000000000..6e61801d8 --- /dev/null +++ b/xs/src/slic3r/AppController.hpp @@ -0,0 +1,110 @@ +#ifndef APPCONTROLLER_HPP +#define APPCONTROLLER_HPP + +#include +#include +#include + +namespace Slic3r { + +class Model; +class Print; +class PrintObject; + +class AppControllerBoilerplate { +public: + + using Path = std::string; + using PathList = std::vector; + + enum class IssueType { + INFO, + WARN, + ERR, + FATAL + }; + + PathList query_destination_paths( + const std::string& title, + const std::string& extensions) const; + + PathList query_destination_dirs( + const std::string& title) const; + + Path query_destination_path( + const std::string& title, + const std::string& extensions) const; + + void report_issue(IssueType issuetype, + const std::string& description, + const std::string& brief = ""); + + class ProgressIndicator { + float state_ = .0f, max_ = 1.f, step_; + public: + + inline virtual ~ProgressIndicator() {} + + float max() const { return max_; } + float state() const { return state_; } + + virtual void max(float maxval) { max_ = maxval; } + virtual void state(float val) { state_ = val; } + virtual void state(unsigned st) { state_ = st * step_; } + virtual void states(unsigned statenum) { + step_ = max_ / statenum; + } + + virtual void message(const std::string&) = 0; + virtual void title(const std::string&) = 0; + + template + void update(T st, const std::string& msg) { + message(msg); state(st); + } + }; + + using ProgresIndicatorPtr = std::shared_ptr; + + ProgresIndicatorPtr createProgressIndicator( + unsigned statenum, + const std::string& title, + const std::string& firstmsg = "") const; + + inline void globalProgressIndicator(ProgresIndicatorPtr progrind) { + glob_progressind_ = progrind; + } + + inline ProgresIndicatorPtr globalProgressIndicator() { + if(!glob_progressind_) + glob_progressind_ = createProgressIndicator(100, "Progress"); + + return glob_progressind_; + } + +private: + ProgresIndicatorPtr glob_progressind_; +}; + +class AppController: protected AppControllerBoilerplate { + Model *model_ = nullptr; Print *print_ = nullptr; + + void sliceObject(PrintObject *pobj); + +public: + + void slice(); + + void slice_to_png(); + + void set_model(Model *model) { model_ = model; } + + void set_print(Print *print) { print_ = print; } + + void set_global_progress_indicator_id(unsigned gauge_id, + unsigned statusbar_id); +}; + +} + +#endif // APPCONTROLLER_HPP diff --git a/xs/src/xsinit.h b/xs/src/xsinit.h index 01c1293ac..9365f1979 100644 --- a/xs/src/xsinit.h +++ b/xs/src/xsinit.h @@ -80,6 +80,7 @@ extern "C" { #include #include #include +#include namespace Slic3r { diff --git a/xs/xsp/AppController.xsp b/xs/xsp/AppController.xsp new file mode 100644 index 000000000..2ff448f1f --- /dev/null +++ b/xs/xsp/AppController.xsp @@ -0,0 +1,20 @@ +%module{Slic3r::XS}; + +%{ +#include +#include "slic3r/AppController.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Print.hpp" +%} + +%name{Slic3r::AppController} class AppController { + + AppController(); + + void slice_to_png(); + + void set_model(Model *model); + void set_print(Print *print); + void set_global_progress_indicator_id(unsigned gauge_id, unsigned statusbar_id); + +}; \ No newline at end of file diff --git a/xs/xsp/my.map b/xs/xsp/my.map index cc902acae..c5306ddfc 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -216,6 +216,7 @@ Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T AppConfig* O_OBJECT_SLIC3R +AppController* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T GLShader* O_OBJECT_SLIC3R diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 57eae1598..c19ead1ff 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -268,3 +268,4 @@ $CVar = (PrintObjectStep)SvUV($PerlVar); %}; }; +%typemap{AppController*}; \ No newline at end of file