From 2306c1589a816dbda8ede8620842f0f6b24c8e8a Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 19 Sep 2018 18:02:04 +0200 Subject: [PATCH] Polymorphic AppController for cli and gui modes. --- slic3r.pl | 9 +- xs/src/libslic3r/ModelArrange.hpp | 155 ++++++++++----------- xs/src/slic3r/AppController.cpp | 50 ++++--- xs/src/slic3r/AppController.hpp | 217 +++++++++++++++++++++++------- xs/src/slic3r/AppControllerWx.cpp | 57 ++++---- xs/src/slic3r/GUI/GUI.cpp | 20 +++ xs/src/slic3r/GUI/GUI.hpp | 7 + xs/xsp/GUI.xsp | 6 + 8 files changed, 338 insertions(+), 183 deletions(-) diff --git a/slic3r.pl b/slic3r.pl index 38c10a900..95427443b 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -109,6 +109,7 @@ if ((!@ARGV || $opt{gui}) && !$opt{no_gui} && !$opt{save} && eval "require Slic3 $Slic3r::GUI::no_plater = $opt{no_plater}; $Slic3r::GUI::autosave = $opt{autosave}; } + Slic3r::GUI::set_gui_appctl(); $gui = Slic3r::GUI->new; #setlocale(LC_NUMERIC, 'C'); $gui->{mainframe}->load_config_file($_) for @{$opt{load}}; @@ -121,6 +122,9 @@ if ((!@ARGV || $opt{gui}) && !$opt{no_gui} && !$opt{save} && eval "require Slic3 die $@ if $@ && $opt{gui}; if (@ARGV) { # slicing from command line + Slic3r::GUI::set_cli_appctl(); + my $appctl = Slic3r::AppController->new(); + $config->validate; if ($opt{repair}) { @@ -210,7 +214,10 @@ if (@ARGV) { # slicing from command line $sprint->apply_config($config); if ($opt{export_png}) { - $sprint->export_png; + # $sprint->export_png; + $appctl->set_model($model); + $appctl->set_print($sprint->_print); + $appctl->print_ctl()->slice_to_png(); } else { my $t0 = [gettimeofday]; # The following call may die if the output_filename_format template substitution fails, diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp index 372689c39..4b91131ed 100644 --- a/xs/src/libslic3r/ModelArrange.hpp +++ b/xs/src/libslic3r/ModelArrange.hpp @@ -292,59 +292,59 @@ protected: using Distance = TCoord; using Pile = sl::Shapes; - Packer pck_; - PConfig pconf_; // Placement configuration - double bin_area_; - SpatIndex rtree_; - SpatIndex smallsrtree_; - double norm_; - Pile merged_pile_; - Box pilebb_; - ItemGroup remaining_; - ItemGroup items_; + Packer m_pck; + PConfig m_pconf; // Placement configuration + double m_bin_area; + SpatIndex m_rtree; + SpatIndex m_smallsrtree; + double m_norm; + Pile m_merged_pile; + Box m_pilebb; + ItemGroup m_remaining; + ItemGroup m_items; public: _ArrBase(const TBin& bin, Distance dist, std::function progressind, std::function stopcond): - pck_(bin, dist), bin_area_(sl::area(bin)), - norm_(std::sqrt(sl::area(bin))) + m_pck(bin, dist), m_bin_area(sl::area(bin)), + m_norm(std::sqrt(sl::area(bin))) { - fillConfig(pconf_); + fillConfig(m_pconf); - pconf_.before_packing = + m_pconf.before_packing = [this](const Pile& merged_pile, // merged pile const ItemGroup& items, // packed items const ItemGroup& remaining) // future items to be packed { - items_ = items; - merged_pile_ = merged_pile; - remaining_ = remaining; + m_items = items; + m_merged_pile = merged_pile; + m_remaining = remaining; - pilebb_ = sl::boundingBox(merged_pile); + m_pilebb = sl::boundingBox(merged_pile); - rtree_.clear(); - smallsrtree_.clear(); + m_rtree.clear(); + m_smallsrtree.clear(); // We will treat big items (compared to the print bed) differently auto isBig = [this](double a) { - return a/bin_area_ > BIG_ITEM_TRESHOLD ; + return a/m_bin_area > BIG_ITEM_TRESHOLD ; }; for(unsigned idx = 0; idx < items.size(); ++idx) { Item& itm = items[idx]; - if(isBig(itm.area())) rtree_.insert({itm.boundingBox(), idx}); - smallsrtree_.insert({itm.boundingBox(), idx}); + if(isBig(itm.area())) m_rtree.insert({itm.boundingBox(), idx}); + m_smallsrtree.insert({itm.boundingBox(), idx}); } }; - pck_.progressIndicator(progressind); - pck_.stopCondition(stopcond); + m_pck.progressIndicator(progressind); + m_pck.stopCondition(stopcond); } template inline IndexedPackGroup operator()(Args&&...args) { - rtree_.clear(); - return pck_.executeIndexed(std::forward(args)...); + m_rtree.clear(); + return m_pck.executeIndexed(std::forward(args)...); } }; @@ -358,18 +358,18 @@ public: _ArrBase(bin, dist, progressind, stopcond) { - pconf_.object_function = [this, bin] (const Item &item) { + m_pconf.object_function = [this, bin] (const Item &item) { auto result = objfunc(bin.center(), - merged_pile_, - pilebb_, - items_, + m_merged_pile, + m_pilebb, + m_items, item, - bin_area_, - norm_, - rtree_, - smallsrtree_, - remaining_); + m_bin_area, + m_norm, + m_rtree, + m_smallsrtree, + m_remaining); double score = std::get<0>(result); auto& fullbb = std::get<1>(result); @@ -381,7 +381,7 @@ public: return score; }; - pck_.configure(pconf_); + m_pck.configure(m_pconf); } }; @@ -396,27 +396,27 @@ public: std::function stopcond): _ArrBase(bin, dist, progressind, stopcond) { - pconf_.object_function = [this, &bin] (const Item &item) { + m_pconf.object_function = [this, &bin] (const Item &item) { auto result = objfunc(bin.center(), - merged_pile_, - pilebb_, - items_, + m_merged_pile, + m_pilebb, + m_items, item, - bin_area_, - norm_, - rtree_, - smallsrtree_, - remaining_); + m_bin_area, + m_norm, + m_rtree, + m_smallsrtree, + m_remaining); double score = std::get<0>(result); auto isBig = [this](const Item& itm) { - return itm.area()/bin_area_ > BIG_ITEM_TRESHOLD ; + return itm.area()/m_bin_area > BIG_ITEM_TRESHOLD ; }; if(isBig(item)) { - auto mp = merged_pile_; + auto mp = m_merged_pile; mp.push_back(item.transformedShape()); auto chull = sl::convexHull(mp); double miss = Placer::overfit(chull, bin); @@ -427,7 +427,7 @@ public: return score; }; - pck_.configure(pconf_); + m_pck.configure(m_pconf); } }; @@ -439,25 +439,25 @@ public: std::function stopcond): _ArrBase(bin, dist, progressind, stopcond) { - pconf_.object_function = [this, &bin] (const Item &item) { + m_pconf.object_function = [this, &bin] (const Item &item) { auto binbb = sl::boundingBox(bin); auto result = objfunc(binbb.center(), - merged_pile_, - pilebb_, - items_, + m_merged_pile, + m_pilebb, + m_items, item, - bin_area_, - norm_, - rtree_, - smallsrtree_, - remaining_); + m_bin_area, + m_norm, + m_rtree, + m_smallsrtree, + m_remaining); double score = std::get<0>(result); return score; }; - pck_.configure(pconf_); + m_pck.configure(m_pconf); } }; @@ -469,22 +469,22 @@ public: std::function stopcond): _ArrBase(Box(0, 0), dist, progressind, stopcond) { - this->pconf_.object_function = [this] (const Item &item) { + this->m_pconf.object_function = [this] (const Item &item) { auto result = objfunc({0, 0}, - merged_pile_, - pilebb_, - items_, + m_merged_pile, + m_pilebb, + m_items, item, 0, - norm_, - rtree_, - smallsrtree_, - remaining_); + m_norm, + m_rtree, + m_smallsrtree, + m_remaining); return std::get<0>(result); }; - this->pck_.configure(pconf_); + this->m_pck.configure(m_pconf); } }; @@ -530,11 +530,11 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { item.rotation(objinst->rotation); item.translation( { #if ENABLE_MODELINSTANCE_3D_OFFSET - ClipperLib::cInt(objinst->get_offset(X) / SCALING_FACTOR), - ClipperLib::cInt(objinst->get_offset(Y) / SCALING_FACTOR) + ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), + ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR) #else - ClipperLib::cInt(objinst->offset(0)/SCALING_FACTOR), - ClipperLib::cInt(objinst->offset(1)/SCALING_FACTOR) + ClipperLib::cInt(objinst->offset(0)/SCALING_FACTOR), + ClipperLib::cInt(objinst->offset(1)/SCALING_FACTOR) #endif // ENABLE_MODELINSTANCE_3D_OFFSET }); ret.emplace_back(objinst, item); @@ -668,17 +668,19 @@ void applyResult( // Get the model instance from the shapemap using the index ModelInstance *inst_ptr = shapemap[idx].first; - // Get the tranformation data from the item object and scale it + // Get the transformation data from the item object and scale it // appropriately auto off = item.translation(); Radians rot = item.rotation(); #if ENABLE_MODELINSTANCE_3D_OFFSET - Vec3d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR, 0.0); + Vec3d foff(off.X*SCALING_FACTOR + batch_offset, + off.Y*SCALING_FACTOR, + 0.0); #else Vec2d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR); #endif // ENABLE_MODELINSTANCE_3D_OFFSET - // write the tranformation data into the model instance + // write the transformation data into the model instance inst_ptr->rotation = rot; #if ENABLE_MODELINSTANCE_3D_OFFSET inst_ptr->set_offset(foff); @@ -695,7 +697,7 @@ void applyResult( * The arrangement considers multiple bins (aka. print beds) for placing all * the items provided in the model argument. If the items don't fit on one * print bed, the remaining will be placed onto newly created print beds. - * The first_bin_only parameter, if set to true, disables this behaviour and + * The first_bin_only parameter, if set to true, disables this behavior and * makes sure that only one print bed is filled and the remaining items will be * untouched. When set to false, the items which could not fit onto the * print bed will be placed next to the print bed so the user should see a @@ -741,6 +743,7 @@ bool arrange(Model &model, coordf_t min_obj_distance, IndexedPackGroup result; + // If there is no hint about the shape, we will try to guess if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed); BoundingBox bbb(bed); diff --git a/xs/src/slic3r/AppController.cpp b/xs/src/slic3r/AppController.cpp index f9c126286..2bb79cec1 100644 --- a/xs/src/slic3r/AppController.cpp +++ b/xs/src/slic3r/AppController.cpp @@ -21,7 +21,7 @@ namespace Slic3r { -class AppControllerBoilerplate::PriData { +class AppControllerGui::PriData { public: std::mutex m; std::thread::id ui_thread; @@ -29,14 +29,14 @@ public: inline explicit PriData(std::thread::id uit): ui_thread(uit) {} }; -AppControllerBoilerplate::AppControllerBoilerplate() +AppControllerGui::AppControllerGui() :m_pri_data(new PriData(std::this_thread::get_id())) {} -AppControllerBoilerplate::~AppControllerBoilerplate() { +AppControllerGui::~AppControllerGui() { m_pri_data.reset(); } -bool AppControllerBoilerplate::is_main_thread() const +bool AppControllerGui::is_main_thread() const { return m_pri_data->ui_thread == std::this_thread::get_id(); } @@ -54,8 +54,7 @@ static const PrintStep STEP_SKIRT = psSkirt; static const PrintStep STEP_BRIM = psBrim; static const PrintStep STEP_WIPE_TOWER = psWipeTower; -AppControllerBoilerplate::ProgresIndicatorPtr -AppControllerBoilerplate::global_progress_indicator() { +ProgresIndicatorPtr AppControllerGui::global_progress_indicator() { ProgresIndicatorPtr ret; m_pri_data->m.lock(); @@ -65,8 +64,7 @@ AppControllerBoilerplate::global_progress_indicator() { return ret; } -void AppControllerBoilerplate::global_progress_indicator( - AppControllerBoilerplate::ProgresIndicatorPtr gpri) +void AppControllerGui::global_progress_indicator(ProgresIndicatorPtr gpri) { m_pri_data->m.lock(); m_global_progressind = gpri; @@ -78,7 +76,10 @@ PrintController::query_png_export_data(const DynamicPrintConfig& conf) { PngExportData ret; - auto zippath = query_destination_path("Output zip file", "*.zip", "out"); + auto c = GUI::get_appctl(); + auto zippath = c->query_destination_path("Output zip file", "*.zip", + "export-png", + "out"); ret.zippath = zippath; @@ -102,7 +103,7 @@ PrintController::query_png_export_data(const DynamicPrintConfig& conf) return ret; } -void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri) +void PrintController::slice(ProgresIndicatorPtr pri) { m_print->set_status_callback([pri](int st, const std::string& msg){ pri->update(unsigned(st), msg); @@ -113,8 +114,9 @@ void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri) void PrintController::slice() { - auto pri = global_progress_indicator(); - if(!pri) pri = create_progress_indicator(100, L("Slicing")); + auto ctl = GUI::get_appctl(); + auto pri = ctl->global_progress_indicator(); + if(!pri) pri = ctl->create_progress_indicator(100, L("Slicing")); slice(pri); } @@ -139,13 +141,15 @@ void PrintController::slice_to_png() { using Pointf3 = Vec3d; + auto ctl = GUI::get_appctl(); auto presetbundle = GUI::get_preset_bundle(); assert(presetbundle); + // FIXME: this crashes in command line mode auto pt = presetbundle->printers.get_selected_preset().printer_technology(); if(pt != ptSLA) { - report_issue(IssueType::ERR, L("Printer technology is not SLA!"), + ctl->report_issue(IssueType::ERR, L("Printer technology is not SLA!"), L("Error")); return; } @@ -162,7 +166,7 @@ void PrintController::slice_to_png() print->apply_config(conf); print->validate(); } catch(std::exception& e) { - report_issue(IssueType::ERR, e.what(), "Error"); + ctl->report_issue(IssueType::ERR, e.what(), "Error"); return; } @@ -208,13 +212,13 @@ void PrintController::slice_to_png() << L("Width needed: ") << px(punsc) << " mm\n" << L("Height needed: ") << py(punsc) << " mm\n"; - if(!report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) { + if(!ctl->report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) { scale_back(); return; } } - auto pri = create_progress_indicator( + auto pri = ctl->create_progress_indicator( 200, L("Slicing to zipped png files...")); pri->on_cancel([&print](){ print->cancel(); }); @@ -223,7 +227,7 @@ void PrintController::slice_to_png() pri->update(0, L("Slicing...")); slice(pri); } catch (std::exception& e) { - report_issue(IssueType::ERR, e.what(), L("Exception occurred")); + ctl->report_issue(IssueType::ERR, e.what(), L("Exception occurred")); scale_back(); if(print->canceled()) print->restart(); return; @@ -242,7 +246,7 @@ void PrintController::slice_to_png() exd.exp_time_s, exd.exp_time_first_s); } catch (std::exception& e) { - report_issue(IssueType::ERR, e.what(), L("Exception occurred")); + ctl->report_issue(IssueType::ERR, e.what(), L("Exception occurred")); } scale_back(); @@ -286,6 +290,8 @@ void AppController::arrange_model() { using Coord = libnest2d::TCoord; + auto ctl = GUI::get_appctl(); + if(m_arranging.load()) return; // to prevent UI reentrancies @@ -294,7 +300,7 @@ void AppController::arrange_model() unsigned count = 0; for(auto obj : m_model->objects) count += obj->instances.size(); - auto pind = global_progress_indicator(); + auto pind = ctl->global_progress_indicator(); float pmax = 1.0; @@ -331,15 +337,15 @@ void AppController::arrange_model() bed, hint, false, // create many piles not just one pile - [this, pind, count](unsigned rem) { + [this, pind, &ctl, count](unsigned rem) { if(pind) pind->update(count - rem, L("Arranging objects...")); - process_events(); + ctl->process_events(); }, [this] () { return !m_arranging.load(); }); } catch(std::exception& e) { std::cerr << e.what() << std::endl; - report_issue(IssueType::ERR, + ctl->report_issue(IssueType::ERR, L("Could not arrange model objects! " "Some geometries may be invalid."), L("Exception occurred")); diff --git a/xs/src/slic3r/AppController.hpp b/xs/src/slic3r/AppController.hpp index df506c05b..a34e5d035 100644 --- a/xs/src/slic3r/AppController.hpp +++ b/xs/src/slic3r/AppController.hpp @@ -20,6 +20,21 @@ class PrintConfig; class ProgressStatusBar; class DynamicPrintConfig; +/// A Progress indicator object smart pointer +using ProgresIndicatorPtr = std::shared_ptr; + +using FilePath = std::string; +using FilePathList = std::vector; + +/// Common runtime issue types +enum class IssueType { + INFO, + WARN, + WARN_Q, // Warning with a question to continue + ERR, + FATAL +}; + /** * @brief A boilerplate class for creating application logic. It should provide * features as issue reporting and progress indication, etc... @@ -32,34 +47,12 @@ class DynamicPrintConfig; * UI toolkit dependencies. We can implement it with any UI framework or make it * a cli client. */ -class AppControllerBoilerplate { +class AppControllerBase { public: - /// A Progress indicator object smart pointer - using ProgresIndicatorPtr = std::shared_ptr; + using Ptr = std::shared_ptr; -private: - class PriData; // Some structure to store progress indication data - - // Pimpl data for thread safe progress indication features - std::unique_ptr m_pri_data; - -public: - - AppControllerBoilerplate(); - ~AppControllerBoilerplate(); - - using Path = std::string; - using PathList = std::vector; - - /// Common runtime issue types - enum class IssueType { - INFO, - WARN, - WARN_Q, // Warning with a question to continue - ERR, - FATAL - }; + inline virtual ~AppControllerBase() {} /** * @brief Query some paths from the user. @@ -69,23 +62,28 @@ public: * @param extensions Recognized file extensions. * @return Returns a list of paths chosen by the user. */ - PathList query_destination_paths( + virtual FilePathList query_destination_paths( const std::string& title, - const std::string& extensions) const; + const std::string& extensions, + const std::string& functionid = "", + const std::string& hint = "") const = 0; /** * @brief Same as query_destination_paths but works for directories only. */ - PathList query_destination_dirs( - const std::string& title) const; + virtual FilePathList query_destination_dirs( + const std::string& title, + const std::string& functionid = "", + const std::string& hint = "") const = 0; /** * @brief Same as query_destination_paths but returns only one path. */ - Path query_destination_path( + virtual FilePath query_destination_path( const std::string& title, const std::string& extensions, - const std::string& hint = "") const; + const std::string& functionid = "", + const std::string& hint = "") const = 0; /** * @brief Report an issue to the user be it fatal or recoverable. @@ -97,12 +95,9 @@ public: * @param brief A very brief description. Can be used for message dialog * title. */ - bool report_issue(IssueType issuetype, - const std::string& description, - const std::string& brief); - - bool report_issue(IssueType issuetype, - const std::string& description); + virtual bool report_issue(IssueType issuetype, + const std::string& description, + const std::string& brief) = 0; /** * @brief Return the global progress indicator for the current controller. @@ -110,9 +105,9 @@ public: * * Only one thread should use the global indicator at a time. */ - ProgresIndicatorPtr global_progress_indicator(); + virtual ProgresIndicatorPtr global_progress_indicator() = 0; - void global_progress_indicator(ProgresIndicatorPtr gpri); + virtual void global_progress_indicator(ProgresIndicatorPtr gpri) = 0; /** * @brief A predicate telling the caller whether it is the thread that @@ -122,7 +117,7 @@ public: * @return Return true for the same caller thread that created this * object and false for every other. */ - bool is_main_thread() const; + virtual bool is_main_thread() const = 0; /** * @brief The frontend supports asynch execution. @@ -138,11 +133,9 @@ public: * @return true if a job or method can be executed asynchronously, false * otherwise. */ - bool supports_asynch() const; + virtual bool supports_asynch() const = 0; - void process_events(); - -protected: + virtual void process_events() = 0; /** * @brief Create a new progress indicator and return a smart pointer to it. @@ -151,14 +144,138 @@ protected: * @param firstmsg The message for the first subtask to be displayed. * @return Smart pointer to the created object. */ - ProgresIndicatorPtr create_progress_indicator( + virtual ProgresIndicatorPtr create_progress_indicator( unsigned statenum, const std::string& title, - const std::string& firstmsg) const; + const std::string& firstmsg = "") const = 0; +}; - ProgresIndicatorPtr create_progress_indicator( +/** + * @brief Implementation of AppControllerBase for the GUI app + */ +class AppControllerGui: public AppControllerBase { +private: + class PriData; // Some structure to store progress indication data + + // Pimpl data for thread safe progress indication features + std::unique_ptr m_pri_data; + +public: + + AppControllerGui(); + + virtual ~AppControllerGui(); + + virtual FilePathList query_destination_paths( + const std::string& title, + const std::string& extensions, + const std::string& functionid, + const std::string& hint) const override; + + virtual FilePathList query_destination_dirs( + const std::string& /*title*/, + const std::string& /*functionid*/, + const std::string& /*hint*/) const override { return {}; } + + virtual FilePath query_destination_path( + const std::string& title, + const std::string& extensions, + const std::string& functionid, + const std::string& hint) const override; + + virtual bool report_issue(IssueType issuetype, + const std::string& description, + const std::string& brief = std::string()) override; + + virtual ProgresIndicatorPtr global_progress_indicator() override; + + virtual void global_progress_indicator(ProgresIndicatorPtr gpri) override; + + virtual bool is_main_thread() const override; + + virtual bool supports_asynch() const override; + + virtual void process_events() override; + + virtual ProgresIndicatorPtr create_progress_indicator( unsigned statenum, - const std::string& title) const; + const std::string& title, + const std::string& firstmsg) const override; + +protected: + + // This is a global progress indicator placeholder. In the Slic3r UI it can + // contain the progress indicator on the statusbar. + ProgresIndicatorPtr m_global_progressind; +}; + +class AppControllerCli: public AppControllerBase { + + class CliProgress : public ProgressIndicator { + std::string m_msg, m_title; + public: + virtual void message(const std::string& msg) override { + m_msg = msg; + } + + virtual void title(const std::string& title) override { + m_title = title; + } + }; + +public: + + AppControllerCli() { + std::cout << "Cli AppController ready..." << std::endl; + m_global_progressind = std::make_shared(); + } + + virtual ~AppControllerCli() {} + + virtual FilePathList query_destination_paths( + const std::string& /*title*/, + const std::string& /*extensions*/, + const std::string& /*functionid*/, + const std::string& /*hint*/) const override { return {}; } + + virtual FilePathList query_destination_dirs( + const std::string& /*title*/, + const std::string& /*functionid*/, + const std::string& /*hint*/) const override { return {}; } + + virtual FilePath query_destination_path( + const std::string& /*title*/, + const std::string& /*extensions*/, + const std::string& /*functionid*/, + const std::string& /*hint*/) const override { return "out.zip"; } + + virtual bool report_issue(IssueType /*issuetype*/, + const std::string& description, + const std::string& brief) override { + std::cerr << brief << ": " << description << std::endl; + return true; + } + + virtual ProgresIndicatorPtr global_progress_indicator() override { + return m_global_progressind; + } + + virtual void global_progress_indicator(ProgresIndicatorPtr) override {} + + virtual bool is_main_thread() const override { return true; } + + virtual bool supports_asynch() const override { return false; } + + virtual void process_events() override {} + + virtual ProgresIndicatorPtr create_progress_indicator( + unsigned /*statenum*/, + const std::string& /*title*/, + const std::string& /*firstmsg*/) const override { + return std::make_shared(); + } + +protected: // This is a global progress indicator placeholder. In the Slic3r UI it can // contain the progress indicator on the statusbar. @@ -185,7 +302,7 @@ public: /** * @brief Implementation of the printing logic. */ -class PrintController: public AppControllerBoilerplate { +class PrintController { Print *m_print = nullptr; std::function m_rempools; protected: @@ -241,7 +358,7 @@ public: /** * @brief Top level controller. */ -class AppController: public AppControllerBoilerplate { +class AppController { Model *m_model = nullptr; PrintController::Ptr printctl; std::atomic m_arranging; diff --git a/xs/src/slic3r/AppControllerWx.cpp b/xs/src/slic3r/AppControllerWx.cpp index 9f52e52d2..25cd739f3 100644 --- a/xs/src/slic3r/AppControllerWx.cpp +++ b/xs/src/slic3r/AppControllerWx.cpp @@ -25,40 +25,43 @@ namespace Slic3r { -bool AppControllerBoilerplate::supports_asynch() const +bool AppControllerGui::supports_asynch() const { return true; } -void AppControllerBoilerplate::process_events() +void AppControllerGui::process_events() { wxYieldIfNeeded(); } -AppControllerBoilerplate::PathList -AppControllerBoilerplate::query_destination_paths( +FilePathList AppControllerGui::query_destination_paths( const std::string &title, - const std::string &extensions) const + const std::string &extensions, + const std::string &/*functionid*/, + const std::string& hint) const { wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) ); dlg.SetWildcard(extensions); - dlg.ShowModal(); + dlg.SetFilename(hint); - wxArrayString paths; - dlg.GetPaths(paths); + FilePathList ret; - PathList ret(paths.size(), ""); - for(auto& p : paths) ret.push_back(p.ToStdString()); + if(dlg.ShowModal() == wxID_OK) { + wxArrayString paths; + dlg.GetPaths(paths); + for(auto& p : paths) ret.push_back(p.ToStdString()); + } return ret; } -AppControllerBoilerplate::Path -AppControllerBoilerplate::query_destination_path( +FilePath AppControllerGui::query_destination_path( const std::string &title, const std::string &extensions, + const std::string &/*functionid*/, const std::string& hint) const { wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) ); @@ -66,16 +69,16 @@ AppControllerBoilerplate::query_destination_path( dlg.SetFilename(hint); - Path ret; + FilePath ret; if(dlg.ShowModal() == wxID_OK) { - ret = Path(dlg.GetPath()); + ret = FilePath(dlg.GetPath()); } return ret; } -bool AppControllerBoilerplate::report_issue(IssueType issuetype, +bool AppControllerGui::report_issue(IssueType issuetype, const std::string &description, const std::string &brief) { @@ -93,13 +96,6 @@ bool AppControllerBoilerplate::report_issue(IssueType issuetype, return ret != wxCANCEL; } -bool AppControllerBoilerplate::report_issue( - AppControllerBoilerplate::IssueType issuetype, - const std::string &description) -{ - return report_issue(issuetype, description, std::string()); -} - wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent); struct Zipper::Impl { @@ -235,8 +231,7 @@ public: }; } -AppControllerBoilerplate::ProgresIndicatorPtr -AppControllerBoilerplate::create_progress_indicator( +ProgresIndicatorPtr AppControllerGui::create_progress_indicator( unsigned statenum, const std::string& title, const std::string& firstmsg) const @@ -251,20 +246,13 @@ AppControllerBoilerplate::create_progress_indicator( return pri; } -AppControllerBoilerplate::ProgresIndicatorPtr -AppControllerBoilerplate::create_progress_indicator( - unsigned statenum, const std::string &title) const -{ - return create_progress_indicator(statenum, title, std::string()); -} - namespace { class Wrapper: public ProgressIndicator, public wxEvtHandler { ProgressStatusBar *m_sbar; using Base = ProgressIndicator; wxString m_message; - AppControllerBoilerplate& m_ctl; + AppControllerBase& m_ctl; void showProgress(bool show = true) { m_sbar->show_progress(show); @@ -288,7 +276,7 @@ class Wrapper: public ProgressIndicator, public wxEvtHandler { public: inline Wrapper(ProgressStatusBar *sbar, - AppControllerBoilerplate& ctl): + AppControllerBase& ctl): m_sbar(sbar), m_ctl(ctl) { Base::max(static_cast(m_sbar->get_range())); @@ -344,7 +332,8 @@ public: void AppController::set_global_progress_indicator(ProgressStatusBar *prsb) { if(prsb) { - global_progress_indicator(std::make_shared(prsb, *this)); + auto ctl = GUI::get_appctl(); + ctl->global_progress_indicator(std::make_shared(prsb, *ctl)); } } diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index e5ed917b3..2ad155b7d 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -1,4 +1,5 @@ #include "GUI.hpp" +#include "../AppController.hpp" #include "WipeTowerDialog.hpp" #include @@ -1405,4 +1406,23 @@ void desktop_open_datadir_folder() #endif } +namespace { +AppControllerPtr g_appctl; +} + +AppControllerPtr get_appctl() +{ + return g_appctl; +} + +void set_cli_appctl() +{ + g_appctl = std::make_shared(); +} + +void set_gui_appctl() +{ + g_appctl = std::make_shared(); +} + } } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index cbf83aa94..04b4a4217 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -42,6 +42,9 @@ class TabIface; class PreviewIface; class Print; class GCodePreviewData; +class AppControllerBase; + +using AppControllerPtr = std::shared_ptr; #define _(s) Slic3r::GUI::I18N::translate((s)) @@ -129,6 +132,10 @@ ProgressStatusBar* get_progress_status_bar(); wxNotebook * get_tab_panel(); wxNotebook* get_tab_panel(); +AppControllerPtr get_appctl(); +void set_cli_appctl(); +void set_gui_appctl(); + const wxColour& get_label_clr_modified(); const wxColour& get_label_clr_sys(); const wxColour& get_label_clr_default(); diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index 22e2ff1d7..a1e3e4670 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -35,6 +35,12 @@ bool is_windows10() void set_wxapp(SV *ui) %code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %}; +void set_gui_appctl() + %code%{ Slic3r::GUI::set_gui_appctl(); %}; + +void set_cli_appctl() + %code%{ Slic3r::GUI::set_cli_appctl(); %}; + void set_progress_status_bar(ProgressStatusBar *prs) %code%{ Slic3r::GUI::set_progress_status_bar(prs); %};