Polymorphic AppController for cli and gui modes.

This commit is contained in:
tamasmeszaros 2018-09-19 18:02:04 +02:00
parent c9acd1252a
commit 2306c1589a
8 changed files with 338 additions and 183 deletions

View File

@ -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::no_plater = $opt{no_plater};
$Slic3r::GUI::autosave = $opt{autosave}; $Slic3r::GUI::autosave = $opt{autosave};
} }
Slic3r::GUI::set_gui_appctl();
$gui = Slic3r::GUI->new; $gui = Slic3r::GUI->new;
#setlocale(LC_NUMERIC, 'C'); #setlocale(LC_NUMERIC, 'C');
$gui->{mainframe}->load_config_file($_) for @{$opt{load}}; $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}; die $@ if $@ && $opt{gui};
if (@ARGV) { # slicing from command line if (@ARGV) { # slicing from command line
Slic3r::GUI::set_cli_appctl();
my $appctl = Slic3r::AppController->new();
$config->validate; $config->validate;
if ($opt{repair}) { if ($opt{repair}) {
@ -210,7 +214,10 @@ if (@ARGV) { # slicing from command line
$sprint->apply_config($config); $sprint->apply_config($config);
if ($opt{export_png}) { 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 { } else {
my $t0 = [gettimeofday]; my $t0 = [gettimeofday];
# The following call may die if the output_filename_format template substitution fails, # The following call may die if the output_filename_format template substitution fails,

View File

@ -292,59 +292,59 @@ protected:
using Distance = TCoord<PointImpl>; using Distance = TCoord<PointImpl>;
using Pile = sl::Shapes<PolygonImpl>; using Pile = sl::Shapes<PolygonImpl>;
Packer pck_; Packer m_pck;
PConfig pconf_; // Placement configuration PConfig m_pconf; // Placement configuration
double bin_area_; double m_bin_area;
SpatIndex rtree_; SpatIndex m_rtree;
SpatIndex smallsrtree_; SpatIndex m_smallsrtree;
double norm_; double m_norm;
Pile merged_pile_; Pile m_merged_pile;
Box pilebb_; Box m_pilebb;
ItemGroup remaining_; ItemGroup m_remaining;
ItemGroup items_; ItemGroup m_items;
public: public:
_ArrBase(const TBin& bin, Distance dist, _ArrBase(const TBin& bin, Distance dist,
std::function<void(unsigned)> progressind, std::function<void(unsigned)> progressind,
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
pck_(bin, dist), bin_area_(sl::area(bin)), m_pck(bin, dist), m_bin_area(sl::area(bin)),
norm_(std::sqrt(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 [this](const Pile& merged_pile, // merged pile
const ItemGroup& items, // packed items const ItemGroup& items, // packed items
const ItemGroup& remaining) // future items to be packed const ItemGroup& remaining) // future items to be packed
{ {
items_ = items; m_items = items;
merged_pile_ = merged_pile; m_merged_pile = merged_pile;
remaining_ = remaining; m_remaining = remaining;
pilebb_ = sl::boundingBox(merged_pile); m_pilebb = sl::boundingBox(merged_pile);
rtree_.clear(); m_rtree.clear();
smallsrtree_.clear(); m_smallsrtree.clear();
// We will treat big items (compared to the print bed) differently // We will treat big items (compared to the print bed) differently
auto isBig = [this](double a) { 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) { for(unsigned idx = 0; idx < items.size(); ++idx) {
Item& itm = items[idx]; Item& itm = items[idx];
if(isBig(itm.area())) rtree_.insert({itm.boundingBox(), idx}); if(isBig(itm.area())) m_rtree.insert({itm.boundingBox(), idx});
smallsrtree_.insert({itm.boundingBox(), idx}); m_smallsrtree.insert({itm.boundingBox(), idx});
} }
}; };
pck_.progressIndicator(progressind); m_pck.progressIndicator(progressind);
pck_.stopCondition(stopcond); m_pck.stopCondition(stopcond);
} }
template<class...Args> inline IndexedPackGroup operator()(Args&&...args) { template<class...Args> inline IndexedPackGroup operator()(Args&&...args) {
rtree_.clear(); m_rtree.clear();
return pck_.executeIndexed(std::forward<Args>(args)...); return m_pck.executeIndexed(std::forward<Args>(args)...);
} }
}; };
@ -358,18 +358,18 @@ public:
_ArrBase<Box>(bin, dist, progressind, stopcond) _ArrBase<Box>(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(), auto result = objfunc(bin.center(),
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
bin_area_, m_bin_area,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
double score = std::get<0>(result); double score = std::get<0>(result);
auto& fullbb = std::get<1>(result); auto& fullbb = std::get<1>(result);
@ -381,7 +381,7 @@ public:
return score; return score;
}; };
pck_.configure(pconf_); m_pck.configure(m_pconf);
} }
}; };
@ -396,27 +396,27 @@ public:
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
_ArrBase<lnCircle>(bin, dist, progressind, stopcond) { _ArrBase<lnCircle>(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(), auto result = objfunc(bin.center(),
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
bin_area_, m_bin_area,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
double score = std::get<0>(result); double score = std::get<0>(result);
auto isBig = [this](const Item& itm) { 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)) { if(isBig(item)) {
auto mp = merged_pile_; auto mp = m_merged_pile;
mp.push_back(item.transformedShape()); mp.push_back(item.transformedShape());
auto chull = sl::convexHull(mp); auto chull = sl::convexHull(mp);
double miss = Placer::overfit(chull, bin); double miss = Placer::overfit(chull, bin);
@ -427,7 +427,7 @@ public:
return score; return score;
}; };
pck_.configure(pconf_); m_pck.configure(m_pconf);
} }
}; };
@ -439,25 +439,25 @@ public:
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
_ArrBase<PolygonImpl>(bin, dist, progressind, stopcond) _ArrBase<PolygonImpl>(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 binbb = sl::boundingBox(bin);
auto result = objfunc(binbb.center(), auto result = objfunc(binbb.center(),
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
bin_area_, m_bin_area,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
double score = std::get<0>(result); double score = std::get<0>(result);
return score; return score;
}; };
pck_.configure(pconf_); m_pck.configure(m_pconf);
} }
}; };
@ -469,22 +469,22 @@ public:
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
_ArrBase<Box>(Box(0, 0), dist, progressind, stopcond) _ArrBase<Box>(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}, auto result = objfunc({0, 0},
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
0, 0,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
return std::get<0>(result); 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.rotation(objinst->rotation);
item.translation( { item.translation( {
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
ClipperLib::cInt(objinst->get_offset(X) / SCALING_FACTOR), ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR),
ClipperLib::cInt(objinst->get_offset(Y) / SCALING_FACTOR) ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR)
#else #else
ClipperLib::cInt(objinst->offset(0)/SCALING_FACTOR), ClipperLib::cInt(objinst->offset(0)/SCALING_FACTOR),
ClipperLib::cInt(objinst->offset(1)/SCALING_FACTOR) ClipperLib::cInt(objinst->offset(1)/SCALING_FACTOR)
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
}); });
ret.emplace_back(objinst, item); ret.emplace_back(objinst, item);
@ -668,17 +668,19 @@ void applyResult(
// Get the model instance from the shapemap using the index // Get the model instance from the shapemap using the index
ModelInstance *inst_ptr = shapemap[idx].first; 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 // appropriately
auto off = item.translation(); auto off = item.translation();
Radians rot = item.rotation(); Radians rot = item.rotation();
#if ENABLE_MODELINSTANCE_3D_OFFSET #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 #else
Vec2d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR); Vec2d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #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; inst_ptr->rotation = rot;
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
inst_ptr->set_offset(foff); inst_ptr->set_offset(foff);
@ -695,7 +697,7 @@ void applyResult(
* The arrangement considers multiple bins (aka. print beds) for placing all * 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 * 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. * 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 * 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 * 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 * 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; IndexedPackGroup result;
// If there is no hint about the shape, we will try to guess
if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed); if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed);
BoundingBox bbb(bed); BoundingBox bbb(bed);

View File

@ -21,7 +21,7 @@
namespace Slic3r { namespace Slic3r {
class AppControllerBoilerplate::PriData { class AppControllerGui::PriData {
public: public:
std::mutex m; std::mutex m;
std::thread::id ui_thread; std::thread::id ui_thread;
@ -29,14 +29,14 @@ public:
inline explicit PriData(std::thread::id uit): ui_thread(uit) {} inline explicit PriData(std::thread::id uit): ui_thread(uit) {}
}; };
AppControllerBoilerplate::AppControllerBoilerplate() AppControllerGui::AppControllerGui()
:m_pri_data(new PriData(std::this_thread::get_id())) {} :m_pri_data(new PriData(std::this_thread::get_id())) {}
AppControllerBoilerplate::~AppControllerBoilerplate() { AppControllerGui::~AppControllerGui() {
m_pri_data.reset(); 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(); 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_BRIM = psBrim;
static const PrintStep STEP_WIPE_TOWER = psWipeTower; static const PrintStep STEP_WIPE_TOWER = psWipeTower;
AppControllerBoilerplate::ProgresIndicatorPtr ProgresIndicatorPtr AppControllerGui::global_progress_indicator() {
AppControllerBoilerplate::global_progress_indicator() {
ProgresIndicatorPtr ret; ProgresIndicatorPtr ret;
m_pri_data->m.lock(); m_pri_data->m.lock();
@ -65,8 +64,7 @@ AppControllerBoilerplate::global_progress_indicator() {
return ret; return ret;
} }
void AppControllerBoilerplate::global_progress_indicator( void AppControllerGui::global_progress_indicator(ProgresIndicatorPtr gpri)
AppControllerBoilerplate::ProgresIndicatorPtr gpri)
{ {
m_pri_data->m.lock(); m_pri_data->m.lock();
m_global_progressind = gpri; m_global_progressind = gpri;
@ -78,7 +76,10 @@ PrintController::query_png_export_data(const DynamicPrintConfig& conf)
{ {
PngExportData ret; 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; ret.zippath = zippath;
@ -102,7 +103,7 @@ PrintController::query_png_export_data(const DynamicPrintConfig& conf)
return ret; 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){ m_print->set_status_callback([pri](int st, const std::string& msg){
pri->update(unsigned(st), msg); pri->update(unsigned(st), msg);
@ -113,8 +114,9 @@ void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri)
void PrintController::slice() void PrintController::slice()
{ {
auto pri = global_progress_indicator(); auto ctl = GUI::get_appctl();
if(!pri) pri = create_progress_indicator(100, L("Slicing")); auto pri = ctl->global_progress_indicator();
if(!pri) pri = ctl->create_progress_indicator(100, L("Slicing"));
slice(pri); slice(pri);
} }
@ -139,13 +141,15 @@ void PrintController::slice_to_png()
{ {
using Pointf3 = Vec3d; using Pointf3 = Vec3d;
auto ctl = GUI::get_appctl();
auto presetbundle = GUI::get_preset_bundle(); auto presetbundle = GUI::get_preset_bundle();
assert(presetbundle); assert(presetbundle);
// FIXME: this crashes in command line mode
auto pt = presetbundle->printers.get_selected_preset().printer_technology(); auto pt = presetbundle->printers.get_selected_preset().printer_technology();
if(pt != ptSLA) { 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")); L("Error"));
return; return;
} }
@ -162,7 +166,7 @@ void PrintController::slice_to_png()
print->apply_config(conf); print->apply_config(conf);
print->validate(); print->validate();
} catch(std::exception& e) { } catch(std::exception& e) {
report_issue(IssueType::ERR, e.what(), "Error"); ctl->report_issue(IssueType::ERR, e.what(), "Error");
return; return;
} }
@ -208,13 +212,13 @@ void PrintController::slice_to_png()
<< L("Width needed: ") << px(punsc) << " mm\n" << L("Width needed: ") << px(punsc) << " mm\n"
<< L("Height needed: ") << py(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(); scale_back();
return; return;
} }
} }
auto pri = create_progress_indicator( auto pri = ctl->create_progress_indicator(
200, L("Slicing to zipped png files...")); 200, L("Slicing to zipped png files..."));
pri->on_cancel([&print](){ print->cancel(); }); pri->on_cancel([&print](){ print->cancel(); });
@ -223,7 +227,7 @@ void PrintController::slice_to_png()
pri->update(0, L("Slicing...")); pri->update(0, L("Slicing..."));
slice(pri); slice(pri);
} catch (std::exception& e) { } 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(); scale_back();
if(print->canceled()) print->restart(); if(print->canceled()) print->restart();
return; return;
@ -242,7 +246,7 @@ void PrintController::slice_to_png()
exd.exp_time_s, exd.exp_time_first_s); exd.exp_time_s, exd.exp_time_first_s);
} catch (std::exception& e) { } 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(); scale_back();
@ -286,6 +290,8 @@ void AppController::arrange_model()
{ {
using Coord = libnest2d::TCoord<libnest2d::PointImpl>; using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
auto ctl = GUI::get_appctl();
if(m_arranging.load()) return; if(m_arranging.load()) return;
// to prevent UI reentrancies // to prevent UI reentrancies
@ -294,7 +300,7 @@ void AppController::arrange_model()
unsigned count = 0; unsigned count = 0;
for(auto obj : m_model->objects) count += obj->instances.size(); 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; float pmax = 1.0;
@ -331,15 +337,15 @@ void AppController::arrange_model()
bed, bed,
hint, hint,
false, // create many piles not just one pile false, // create many piles not just one pile
[this, pind, count](unsigned rem) { [this, pind, &ctl, count](unsigned rem) {
if(pind) if(pind)
pind->update(count - rem, L("Arranging objects...")); pind->update(count - rem, L("Arranging objects..."));
process_events(); ctl->process_events();
}, [this] () { return !m_arranging.load(); }); }, [this] () { return !m_arranging.load(); });
} catch(std::exception& e) { } catch(std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
report_issue(IssueType::ERR, ctl->report_issue(IssueType::ERR,
L("Could not arrange model objects! " L("Could not arrange model objects! "
"Some geometries may be invalid."), "Some geometries may be invalid."),
L("Exception occurred")); L("Exception occurred"));

View File

@ -20,6 +20,21 @@ class PrintConfig;
class ProgressStatusBar; class ProgressStatusBar;
class DynamicPrintConfig; class DynamicPrintConfig;
/// A Progress indicator object smart pointer
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
using FilePath = std::string;
using FilePathList = std::vector<FilePath>;
/// 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 * @brief A boilerplate class for creating application logic. It should provide
* features as issue reporting and progress indication, etc... * 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 * UI toolkit dependencies. We can implement it with any UI framework or make it
* a cli client. * a cli client.
*/ */
class AppControllerBoilerplate { class AppControllerBase {
public: public:
/// A Progress indicator object smart pointer using Ptr = std::shared_ptr<AppControllerBase>;
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
private: inline virtual ~AppControllerBase() {}
class PriData; // Some structure to store progress indication data
// Pimpl data for thread safe progress indication features
std::unique_ptr<PriData> m_pri_data;
public:
AppControllerBoilerplate();
~AppControllerBoilerplate();
using Path = std::string;
using PathList = std::vector<Path>;
/// Common runtime issue types
enum class IssueType {
INFO,
WARN,
WARN_Q, // Warning with a question to continue
ERR,
FATAL
};
/** /**
* @brief Query some paths from the user. * @brief Query some paths from the user.
@ -69,23 +62,28 @@ public:
* @param extensions Recognized file extensions. * @param extensions Recognized file extensions.
* @return Returns a list of paths chosen by the user. * @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& 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. * @brief Same as query_destination_paths but works for directories only.
*/ */
PathList query_destination_dirs( virtual FilePathList query_destination_dirs(
const std::string& title) const; 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. * @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& title,
const std::string& extensions, 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. * @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 * @param brief A very brief description. Can be used for message dialog
* title. * title.
*/ */
bool report_issue(IssueType issuetype, virtual bool report_issue(IssueType issuetype,
const std::string& description, const std::string& description,
const std::string& brief); const std::string& brief) = 0;
bool report_issue(IssueType issuetype,
const std::string& description);
/** /**
* @brief Return the global progress indicator for the current controller. * @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. * 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 * @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 * @return Return true for the same caller thread that created this
* object and false for every other. * object and false for every other.
*/ */
bool is_main_thread() const; virtual bool is_main_thread() const = 0;
/** /**
* @brief The frontend supports asynch execution. * @brief The frontend supports asynch execution.
@ -138,11 +133,9 @@ public:
* @return true if a job or method can be executed asynchronously, false * @return true if a job or method can be executed asynchronously, false
* otherwise. * otherwise.
*/ */
bool supports_asynch() const; virtual bool supports_asynch() const = 0;
void process_events(); virtual void process_events() = 0;
protected:
/** /**
* @brief Create a new progress indicator and return a smart pointer to it. * @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. * @param firstmsg The message for the first subtask to be displayed.
* @return Smart pointer to the created object. * @return Smart pointer to the created object.
*/ */
ProgresIndicatorPtr create_progress_indicator( virtual ProgresIndicatorPtr create_progress_indicator(
unsigned statenum, unsigned statenum,
const std::string& title, 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<PriData> 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, 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<CliProgress>();
}
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<CliProgress>();
}
protected:
// This is a global progress indicator placeholder. In the Slic3r UI it can // This is a global progress indicator placeholder. In the Slic3r UI it can
// contain the progress indicator on the statusbar. // contain the progress indicator on the statusbar.
@ -185,7 +302,7 @@ public:
/** /**
* @brief Implementation of the printing logic. * @brief Implementation of the printing logic.
*/ */
class PrintController: public AppControllerBoilerplate { class PrintController {
Print *m_print = nullptr; Print *m_print = nullptr;
std::function<void()> m_rempools; std::function<void()> m_rempools;
protected: protected:
@ -241,7 +358,7 @@ public:
/** /**
* @brief Top level controller. * @brief Top level controller.
*/ */
class AppController: public AppControllerBoilerplate { class AppController {
Model *m_model = nullptr; Model *m_model = nullptr;
PrintController::Ptr printctl; PrintController::Ptr printctl;
std::atomic<bool> m_arranging; std::atomic<bool> m_arranging;

View File

@ -25,40 +25,43 @@
namespace Slic3r { namespace Slic3r {
bool AppControllerBoilerplate::supports_asynch() const bool AppControllerGui::supports_asynch() const
{ {
return true; return true;
} }
void AppControllerBoilerplate::process_events() void AppControllerGui::process_events()
{ {
wxYieldIfNeeded(); wxYieldIfNeeded();
} }
AppControllerBoilerplate::PathList FilePathList AppControllerGui::query_destination_paths(
AppControllerBoilerplate::query_destination_paths(
const std::string &title, 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) ); wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
dlg.SetWildcard(extensions); dlg.SetWildcard(extensions);
dlg.ShowModal(); dlg.SetFilename(hint);
wxArrayString paths; FilePathList ret;
dlg.GetPaths(paths);
PathList ret(paths.size(), ""); if(dlg.ShowModal() == wxID_OK) {
for(auto& p : paths) ret.push_back(p.ToStdString()); wxArrayString paths;
dlg.GetPaths(paths);
for(auto& p : paths) ret.push_back(p.ToStdString());
}
return ret; return ret;
} }
AppControllerBoilerplate::Path FilePath AppControllerGui::query_destination_path(
AppControllerBoilerplate::query_destination_path(
const std::string &title, const std::string &title,
const std::string &extensions, const std::string &extensions,
const std::string &/*functionid*/,
const std::string& hint) const const std::string& hint) const
{ {
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) ); wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
@ -66,16 +69,16 @@ AppControllerBoilerplate::query_destination_path(
dlg.SetFilename(hint); dlg.SetFilename(hint);
Path ret; FilePath ret;
if(dlg.ShowModal() == wxID_OK) { if(dlg.ShowModal() == wxID_OK) {
ret = Path(dlg.GetPath()); ret = FilePath(dlg.GetPath());
} }
return ret; return ret;
} }
bool AppControllerBoilerplate::report_issue(IssueType issuetype, bool AppControllerGui::report_issue(IssueType issuetype,
const std::string &description, const std::string &description,
const std::string &brief) const std::string &brief)
{ {
@ -93,13 +96,6 @@ bool AppControllerBoilerplate::report_issue(IssueType issuetype,
return ret != wxCANCEL; 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); wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent);
struct Zipper::Impl { struct Zipper::Impl {
@ -235,8 +231,7 @@ public:
}; };
} }
AppControllerBoilerplate::ProgresIndicatorPtr ProgresIndicatorPtr AppControllerGui::create_progress_indicator(
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, unsigned statenum,
const std::string& title, const std::string& title,
const std::string& firstmsg) const const std::string& firstmsg) const
@ -251,20 +246,13 @@ AppControllerBoilerplate::create_progress_indicator(
return pri; return pri;
} }
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, const std::string &title) const
{
return create_progress_indicator(statenum, title, std::string());
}
namespace { namespace {
class Wrapper: public ProgressIndicator, public wxEvtHandler { class Wrapper: public ProgressIndicator, public wxEvtHandler {
ProgressStatusBar *m_sbar; ProgressStatusBar *m_sbar;
using Base = ProgressIndicator; using Base = ProgressIndicator;
wxString m_message; wxString m_message;
AppControllerBoilerplate& m_ctl; AppControllerBase& m_ctl;
void showProgress(bool show = true) { void showProgress(bool show = true) {
m_sbar->show_progress(show); m_sbar->show_progress(show);
@ -288,7 +276,7 @@ class Wrapper: public ProgressIndicator, public wxEvtHandler {
public: public:
inline Wrapper(ProgressStatusBar *sbar, inline Wrapper(ProgressStatusBar *sbar,
AppControllerBoilerplate& ctl): AppControllerBase& ctl):
m_sbar(sbar), m_ctl(ctl) m_sbar(sbar), m_ctl(ctl)
{ {
Base::max(static_cast<float>(m_sbar->get_range())); Base::max(static_cast<float>(m_sbar->get_range()));
@ -344,7 +332,8 @@ public:
void AppController::set_global_progress_indicator(ProgressStatusBar *prsb) void AppController::set_global_progress_indicator(ProgressStatusBar *prsb)
{ {
if(prsb) { if(prsb) {
global_progress_indicator(std::make_shared<Wrapper>(prsb, *this)); auto ctl = GUI::get_appctl();
ctl->global_progress_indicator(std::make_shared<Wrapper>(prsb, *ctl));
} }
} }

View File

@ -1,4 +1,5 @@
#include "GUI.hpp" #include "GUI.hpp"
#include "../AppController.hpp"
#include "WipeTowerDialog.hpp" #include "WipeTowerDialog.hpp"
#include <assert.h> #include <assert.h>
@ -1405,4 +1406,23 @@ void desktop_open_datadir_folder()
#endif #endif
} }
namespace {
AppControllerPtr g_appctl;
}
AppControllerPtr get_appctl()
{
return g_appctl;
}
void set_cli_appctl()
{
g_appctl = std::make_shared<AppControllerCli>();
}
void set_gui_appctl()
{
g_appctl = std::make_shared<AppControllerGui>();
}
} } } }

View File

@ -42,6 +42,9 @@ class TabIface;
class PreviewIface; class PreviewIface;
class Print; class Print;
class GCodePreviewData; class GCodePreviewData;
class AppControllerBase;
using AppControllerPtr = std::shared_ptr<AppControllerBase>;
#define _(s) Slic3r::GUI::I18N::translate((s)) #define _(s) Slic3r::GUI::I18N::translate((s))
@ -129,6 +132,10 @@ ProgressStatusBar* get_progress_status_bar();
wxNotebook * get_tab_panel(); wxNotebook * get_tab_panel();
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_modified();
const wxColour& get_label_clr_sys(); const wxColour& get_label_clr_sys();
const wxColour& get_label_clr_default(); const wxColour& get_label_clr_default();

View File

@ -35,6 +35,12 @@ bool is_windows10()
void set_wxapp(SV *ui) void set_wxapp(SV *ui)
%code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %}; %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) void set_progress_status_bar(ProgressStatusBar *prs)
%code%{ Slic3r::GUI::set_progress_status_bar(prs); %}; %code%{ Slic3r::GUI::set_progress_status_bar(prs); %};