mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-03 12:04:05 -06:00
WIP: Reconstruction of background processing.
This commit is contained in:
parent
f33713e060
commit
bded28f888
17 changed files with 273 additions and 229 deletions
|
@ -57,12 +57,20 @@ void BackgroundSlicingProcess::thread_proc()
|
|||
if (! m_print->canceled()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_sliced_id));
|
||||
m_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
||||
if (! m_print->canceled() && ! m_output_path.empty()) {
|
||||
if (copy_file(m_temp_output_path, m_output_path) != 0)
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
m_print->set_status(95, "Running post-processing scripts");
|
||||
run_post_process_scripts(m_output_path, m_print->config());
|
||||
}
|
||||
if (! m_print->canceled() && ! this->is_step_done(bspsGCodeFinalize)) {
|
||||
this->set_step_started(bspsGCodeFinalize);
|
||||
if (! m_export_path.empty()) {
|
||||
//FIXME localize the messages
|
||||
if (copy_file(m_temp_output_path, m_export_path) != 0)
|
||||
throw std::runtime_error("Copying of the temporary G-code to the output G-code failed");
|
||||
m_print->set_status(95, "Running post-processing scripts");
|
||||
run_post_process_scripts(m_export_path, m_print->config());
|
||||
m_print->set_status(100, "G-code file exported to " + m_export_path);
|
||||
} else {
|
||||
m_print->set_status(100, "Slicing complete");
|
||||
}
|
||||
this->set_step_done(bspsGCodeFinalize);
|
||||
}
|
||||
}
|
||||
} catch (CanceledException &ex) {
|
||||
// Canceled, this is all right.
|
||||
|
@ -133,7 +141,7 @@ bool BackgroundSlicingProcess::stop()
|
|||
{
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
if (m_state == STATE_INITIAL) {
|
||||
this->m_output_path.clear();
|
||||
// this->m_export_path.clear();
|
||||
return false;
|
||||
}
|
||||
// assert(this->running());
|
||||
|
@ -147,7 +155,7 @@ bool BackgroundSlicingProcess::stop()
|
|||
// In the "Finished" or "Canceled" state. Reset the state to "Idle".
|
||||
m_state = STATE_IDLE;
|
||||
}
|
||||
this->m_output_path.clear();
|
||||
// this->m_export_path.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -169,4 +177,53 @@ bool BackgroundSlicingProcess::apply(const Model &model, const DynamicPrintConfi
|
|||
return invalidated;
|
||||
}
|
||||
|
||||
// Set the output path of the G-code.
|
||||
void BackgroundSlicingProcess::schedule_export(const std::string &path)
|
||||
{
|
||||
assert(m_export_path.empty());
|
||||
if (! m_export_path.empty())
|
||||
return;
|
||||
|
||||
// Guard against entering the export step before changing the export path.
|
||||
tbb::mutex::scoped_lock lock(m_step_state_mutex);
|
||||
this->invalidate_step(bspsGCodeFinalize);
|
||||
m_export_path = path;
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::reset_export()
|
||||
{
|
||||
assert(! this->running());
|
||||
if (! this->running()) {
|
||||
m_export_path.clear();
|
||||
// invalidate_step expects the mutex to be locked.
|
||||
tbb::mutex::scoped_lock lock(m_step_state_mutex);
|
||||
this->invalidate_step(bspsGCodeFinalize);
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::set_step_started(BackgroundSlicingProcessStep step)
|
||||
{
|
||||
m_step_state.set_started(step, m_step_state_mutex);
|
||||
if (m_print->canceled())
|
||||
throw CanceledException();
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::set_step_done(BackgroundSlicingProcessStep step)
|
||||
{
|
||||
m_step_state.set_done(step, m_step_state_mutex);
|
||||
if (m_print->canceled())
|
||||
throw CanceledException();
|
||||
}
|
||||
|
||||
bool BackgroundSlicingProcess::invalidate_step(BackgroundSlicingProcessStep step)
|
||||
{
|
||||
bool invalidated = m_step_state.invalidate(step, m_step_state_mutex, [this](){ this->stop(); });
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
bool BackgroundSlicingProcess::invalidate_all_steps()
|
||||
{
|
||||
return m_step_state.invalidate_all(m_step_state_mutex, [this](){ this->stop(); });
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "Print.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
|
@ -13,6 +15,11 @@ class GCodePreviewData;
|
|||
class Model;
|
||||
class Print;
|
||||
|
||||
// Print step IDs for keeping track of the print state.
|
||||
enum BackgroundSlicingProcessStep {
|
||||
bspsGCodeFinalize, bspsCount,
|
||||
};
|
||||
|
||||
// Support for the GUI background processing (Slicing and G-code generation).
|
||||
// As of now this class is not declared in Slic3r::GUI due to the Perl bindings limits.
|
||||
class BackgroundSlicingProcess
|
||||
|
@ -32,8 +39,6 @@ public:
|
|||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||
void set_finished_event(int event_id) { m_event_finished_id = event_id; }
|
||||
|
||||
// Set the output path of the G-code.
|
||||
void set_output_path(const std::string &path) { m_output_path = path; }
|
||||
// Start the background processing. Returns false if the background processing was already running.
|
||||
bool start();
|
||||
// Cancel the background processing. Returns false if the background processing was not running.
|
||||
|
@ -46,6 +51,13 @@ public:
|
|||
// Apply config over the print. Returns false, if the new config values caused any of the already
|
||||
// processed steps to be invalidated, therefore the task will need to be restarted.
|
||||
bool apply(const Model &model, const DynamicPrintConfig &config);
|
||||
// Set the export path of the G-code.
|
||||
// Once the path is set, the G-code
|
||||
void schedule_export(const std::string &path);
|
||||
// Clear m_export_path.
|
||||
void reset_export();
|
||||
// Once the G-code export is scheduled, the apply() methods will do nothing.
|
||||
bool is_export_scheduled() const { return ! m_export_path.empty(); }
|
||||
|
||||
enum State {
|
||||
// m_thread is not running yet, or it did not reach the STATE_IDLE yet (it does not wait on the condition yet).
|
||||
|
@ -74,8 +86,11 @@ private:
|
|||
Print *m_print = nullptr;
|
||||
// Data structure, to which the G-code export writes its annotations.
|
||||
GCodePreviewData *m_gcode_preview_data = nullptr;
|
||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||
std::string m_temp_output_path;
|
||||
std::string m_output_path;
|
||||
// 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;
|
||||
// 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;
|
||||
|
@ -84,6 +99,14 @@ private:
|
|||
std::condition_variable m_condition;
|
||||
State m_state = STATE_INITIAL;
|
||||
|
||||
PrintState<BackgroundSlicingProcessStep, bspsCount> m_step_state;
|
||||
mutable tbb::mutex m_step_state_mutex;
|
||||
void set_step_started(BackgroundSlicingProcessStep step);
|
||||
void set_step_done(BackgroundSlicingProcessStep step);
|
||||
bool is_step_done(BackgroundSlicingProcessStep step) const { return m_step_state.is_done(step); }
|
||||
bool invalidate_step(BackgroundSlicingProcessStep step);
|
||||
bool invalidate_all_steps();
|
||||
|
||||
// wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue.
|
||||
int m_event_sliced_id = 0;
|
||||
// wxWidgets command ID to be sent to the platter to inform that the task finished.
|
||||
|
|
|
@ -5145,7 +5145,7 @@ void GLCanvas3D::_render_layer_editing_overlay() const
|
|||
#else
|
||||
int object_idx = int(volume->select_group_id / 1000000);
|
||||
#endif // ENABLE_EXTENDED_SELECTION
|
||||
if ((int)m_print->objects().size() < object_idx)
|
||||
if ((int)m_print->objects().size() <= object_idx)
|
||||
return;
|
||||
|
||||
const PrintObject* print_object = m_print->get_object(object_idx);
|
||||
|
|
|
@ -261,18 +261,6 @@ void warning_catcher(wxWindow* parent, const wxString& message){
|
|||
msg.ShowModal();
|
||||
}
|
||||
|
||||
// Assign a Lambda to the print object to emit a wxWidgets Command with the provided ID
|
||||
// to deliver a progress status message.
|
||||
void set_print_callback_event(Print *print, int id)
|
||||
{
|
||||
print->set_status_callback([id](int percent, const std::string &message){
|
||||
wxCommandEvent event(id);
|
||||
event.SetInt(percent);
|
||||
event.SetString(message);
|
||||
wxQueueEvent(wxGetApp().mainframe, event.Clone());
|
||||
});
|
||||
}
|
||||
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
|
||||
{
|
||||
if (comboCtrl == nullptr)
|
||||
|
|
|
@ -80,10 +80,6 @@ void show_error_id(int id, const std::string& message); // For Perl
|
|||
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
|
||||
void warning_catcher(wxWindow* parent, const wxString& message);
|
||||
|
||||
// Assign a Lambda to the print object to emit a wxWidgets Command with the provided ID
|
||||
// to deliver a progress status message.
|
||||
void set_print_callback_event(Print *print, int id);
|
||||
|
||||
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.
|
||||
// Items are all initialized to the given value.
|
||||
// Items must be separated by '|', for example "Item1|Item2|Item3", and so on.
|
||||
|
|
|
@ -63,10 +63,10 @@ namespace Slic3r {
|
|||
namespace GUI {
|
||||
|
||||
|
||||
wxDEFINE_EVENT(EVT_PROGRESS_BAR, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_SLICING_COMPLETED, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_PROCESS_COMPLETED, wxCommandEvent);
|
||||
|
||||
|
||||
// Sidebar widgets
|
||||
|
||||
// struct InfoBox : public wxStaticBox
|
||||
|
@ -741,9 +741,6 @@ struct Plater::priv
|
|||
std::vector<PlaterObject> objects;
|
||||
#endif // !ENABLE_EXTENDED_SELECTION
|
||||
|
||||
fs::path export_gcode_output_file;
|
||||
fs::path send_gcode_file;
|
||||
|
||||
// GUI elements
|
||||
wxNotebook *notebook;
|
||||
Sidebar *sidebar;
|
||||
|
@ -809,7 +806,7 @@ struct Plater::priv
|
|||
|
||||
void on_notebook_changed(wxBookCtrlEvent&);
|
||||
void on_select_preset(wxCommandEvent&);
|
||||
void on_progress_event();
|
||||
void on_progress_event(wxCommandEvent&);
|
||||
void on_update_print_preview(wxCommandEvent&);
|
||||
void on_process_completed(wxCommandEvent&);
|
||||
void on_layer_editing_toggled(bool enable);
|
||||
|
@ -880,6 +877,14 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
|||
background_process.set_gcode_preview_data(&gcode_preview_data);
|
||||
background_process.set_sliced_event(EVT_SLICING_COMPLETED);
|
||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||
// Register progress callback from the Print class to the Platter.
|
||||
print.set_status_callback([this](int percent, const std::string &message){
|
||||
wxCommandEvent event(EVT_PROGRESS_BAR);
|
||||
event.SetInt(percent);
|
||||
event.SetString(message);
|
||||
wxQueueEvent(this->q, event.Clone());
|
||||
});
|
||||
this->q->Bind(EVT_PROGRESS_BAR, &priv::on_progress_event, this);
|
||||
|
||||
_3DScene::add_canvas(canvas3D);
|
||||
_3DScene::allow_multisample(canvas3D, GLCanvas3DManager::can_multisample());
|
||||
|
@ -902,7 +907,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
|||
_3DScene::enable_shader(canvas3D, true);
|
||||
_3DScene::enable_force_zoom_to_bed(canvas3D, true);
|
||||
|
||||
background_process_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent &evt){ this->async_apply_config(); }, 0);
|
||||
this->background_process_timer.SetOwner(this->q, 0);
|
||||
this->q->Bind(wxEVT_TIMER, [this](wxTimerEvent &evt){ this->async_apply_config(); });
|
||||
|
||||
auto *bed_shape = config->opt<ConfigOptionPoints>("bed_shape");
|
||||
_3DScene::set_bed_shape(canvas3D, bed_shape->values);
|
||||
|
@ -938,7 +944,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
|
|||
canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); });
|
||||
#if !ENABLE_EXTENDED_SELECTION
|
||||
canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event<int> &evt) { /*TODO: call rotate */ });
|
||||
canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { scale(); });
|
||||
canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { this->scale(); });
|
||||
#endif // !ENABLE_EXTENDED_SELECTION
|
||||
canvas3D->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [q](Event<int> &evt) { evt.data == 1 ? q->increase_instances() : q->decrease_instances(); });
|
||||
canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); });
|
||||
|
@ -998,7 +1004,7 @@ void Plater::priv::update(bool force_autocenter)
|
|||
}
|
||||
|
||||
// stop_background_process(); // TODO
|
||||
print.reload_model_instances();
|
||||
// print.reload_model_instances();
|
||||
|
||||
#if !ENABLE_EXTENDED_SELECTION
|
||||
const auto selections = collect_selections();
|
||||
|
@ -1008,7 +1014,7 @@ void Plater::priv::update(bool force_autocenter)
|
|||
preview->reset_gcode_preview_data();
|
||||
preview->reload_print();
|
||||
|
||||
schedule_background_process();
|
||||
this->schedule_background_process();
|
||||
}
|
||||
|
||||
void Plater::priv::select_view(const std::string& direction)
|
||||
|
@ -1034,7 +1040,7 @@ void Plater::priv::update_ui_from_settings()
|
|||
// }
|
||||
}
|
||||
|
||||
ProgressStatusBar* Plater::priv::statusbar()
|
||||
ProgressStatusBar* Plater::priv::statusbar()
|
||||
{
|
||||
return main_frame->m_statusbar;
|
||||
}
|
||||
|
@ -1257,7 +1263,7 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
|
|||
case FT_GCODE:
|
||||
wildcard = file_wildcards[file_type];
|
||||
break;
|
||||
|
||||
// FT_GCODE
|
||||
default:
|
||||
wildcard = file_wildcards[FT_MODEL];
|
||||
break;
|
||||
|
@ -1290,7 +1296,6 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
|
|||
|
||||
fs::path path(dlg->GetPath());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||
export_gcode_output_file = path;
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
@ -1446,7 +1451,7 @@ void Plater::priv::object_list_changed()
|
|||
_3DScene::enable_toolbar_item(canvas3D, "arrange", have_objects);
|
||||
#endif // ENABLE_EXTENDED_SELECTION
|
||||
|
||||
const bool export_in_progress = !(export_gcode_output_file.empty() && send_gcode_file.empty());
|
||||
const bool export_in_progress = this->background_process.is_export_scheduled(); // || ! send_gcode_file.empty());
|
||||
// XXX: is this right?
|
||||
const bool model_fits = _3DScene::check_volumes_outside_state(canvas3D, config) == ModelInstance::PVS_Inside;
|
||||
|
||||
|
@ -1478,7 +1483,7 @@ void Plater::priv::remove(size_t obj_idx)
|
|||
objects.erase(objects.begin() + obj_idx);
|
||||
#endif // !ENABLE_EXTENDED_SELECTION
|
||||
model.delete_object(obj_idx);
|
||||
print.delete_object(obj_idx);
|
||||
// print.delete_object(obj_idx);
|
||||
// Delete object from Sidebar list
|
||||
sidebar->obj_list()->delete_object_from_list(obj_idx);
|
||||
|
||||
|
@ -1504,7 +1509,7 @@ void Plater::priv::reset()
|
|||
objects.clear();
|
||||
#endif // !ENABLE_EXTENDED_SELECTION
|
||||
model.clear_objects();
|
||||
print.clear_objects();
|
||||
// print.clear_objects();
|
||||
|
||||
// Delete all objects from list on c++ side
|
||||
sidebar->obj_list()->delete_all_objects_from_list();
|
||||
|
@ -1609,7 +1614,6 @@ void Plater::priv::split_object()
|
|||
if (new_objects.size() == 1)
|
||||
{
|
||||
Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part.")));
|
||||
// $self->schedule_background_process;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1635,9 +1639,16 @@ void Plater::priv::schedule_background_process()
|
|||
|
||||
void Plater::priv::async_apply_config()
|
||||
{
|
||||
DynamicPrintConfig config = wxGetApp().preset_bundle->full_config();
|
||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.opt<ConfigOptionPoints>("bed_shape")->values));
|
||||
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.opt_float("max_print_height"))));
|
||||
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
||||
print_volume.min(2) = -1e10;
|
||||
this->q->model().update_print_volume_state(print_volume);
|
||||
|
||||
// Apply new config to the possibly running background task.
|
||||
bool was_running = this->background_process.running();
|
||||
bool invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config());
|
||||
bool invalidated = this->background_process.apply(this->q->model(), std::move(config));
|
||||
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
|
||||
if (Slic3r::_3DScene::is_layers_editing_enabled(this->canvas3D))
|
||||
this->canvas3D->Refresh();
|
||||
|
@ -1669,19 +1680,19 @@ void Plater::priv::async_apply_config()
|
|||
|
||||
void Plater::priv::start_background_process()
|
||||
{
|
||||
if (this->background_process.running())
|
||||
return;
|
||||
// return if ! @{$self->{objects}} || $self->{background_slicing_process}->running;
|
||||
// Don't start process thread if config is not valid.
|
||||
std::string err = wxGetApp().preset_bundle->full_config().validate();
|
||||
if (err.empty())
|
||||
err = this->q->print().validate();
|
||||
// Don't start process thread if Print is not valid.
|
||||
std::string err = this->q->print().validate();
|
||||
if (! err.empty()) {
|
||||
// $self->statusbar->SetStatusText(err);
|
||||
return;
|
||||
}
|
||||
// Copy the names of active presets into the placeholder parser.
|
||||
wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser());
|
||||
// Start the background process.
|
||||
this->background_process.start();
|
||||
this->statusbar()->set_status_text(err);
|
||||
} else {
|
||||
// Copy the names of active presets into the placeholder parser.
|
||||
wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser());
|
||||
// Start the background process.
|
||||
this->background_process.start();
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::priv::stop_background_process()
|
||||
|
@ -1795,9 +1806,10 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
|||
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||
}
|
||||
|
||||
void Plater::priv::on_progress_event()
|
||||
void Plater::priv::on_progress_event(wxCommandEvent &evt)
|
||||
{
|
||||
// TODO
|
||||
this->statusbar()->set_progress(evt.GetInt());
|
||||
this->statusbar()->set_status_text(evt.GetString() + wxString::FromUTF8("…"));
|
||||
}
|
||||
|
||||
void Plater::priv::on_update_print_preview(wxCommandEvent &)
|
||||
|
@ -1813,62 +1825,25 @@ void Plater::priv::on_update_print_preview(wxCommandEvent &)
|
|||
#endif // !ENABLE_EXTENDED_SELECTION
|
||||
}
|
||||
|
||||
void Plater::priv::on_process_completed(wxCommandEvent &)
|
||||
void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||
{
|
||||
// Stop the background task, wait until the thread goes into the "Idle" state.
|
||||
// At this point of time the thread should be either finished or canceled,
|
||||
// so the following call just confirms, that the produced data were consumed.
|
||||
this->background_process.stop();
|
||||
//$self->statusbar->ResetCancelCallback();
|
||||
//$self->statusbar->StopBusy;
|
||||
//$self->statusbar->SetStatusText("");
|
||||
|
||||
/*
|
||||
my $message;
|
||||
my $send_gcode = 0;
|
||||
my $do_print = 0;
|
||||
# print "Process completed, message: ", $message, "\n";
|
||||
if (defined($result)) {
|
||||
$message = L("Export failed");
|
||||
} else {
|
||||
# G-code file exported successfully.
|
||||
if ($self->{print_file}) {
|
||||
$message = L("File added to print queue");
|
||||
$do_print = 1;
|
||||
} elsif ($self->{send_gcode_file}) {
|
||||
$message = L("Sending G-code file to the Printer Host ...");
|
||||
$send_gcode = 1;
|
||||
} elsif (defined $self->{export_gcode_output_file}) {
|
||||
$message = L("G-code file exported to ") . $self->{export_gcode_output_file};
|
||||
} else {
|
||||
$message = L("Slicing complete");
|
||||
}
|
||||
this->statusbar()->reset_cancel_callback();
|
||||
this->statusbar()->stop_busy();
|
||||
|
||||
bool success = evt.GetInt();
|
||||
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||
this->background_process.reset_export();
|
||||
if (! success) {
|
||||
wxString message = evt.GetString();
|
||||
if (message.IsEmpty())
|
||||
message = _(L("Export failed"));
|
||||
this->statusbar()->set_status_text(message);
|
||||
}
|
||||
$self->{export_gcode_output_file} = undef;
|
||||
wxTheApp->notify($message);
|
||||
|
||||
$self->do_print if $do_print;
|
||||
|
||||
# Send $self->{send_gcode_file} to OctoPrint.
|
||||
if ($send_gcode) {
|
||||
my $host = Slic3r::PrintHost::get_print_host($self->{config});
|
||||
if ($host->send_gcode($self->{send_gcode_file})) {
|
||||
$message = L("Upload to host finished.");
|
||||
} else {
|
||||
$message = "";
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// As of now, the BackgroundProcessing thread posts status bar update messages to a queue on the MainFrame.pm,
|
||||
// but the "Processing finished" message is posted to this window.
|
||||
// Delay the following status bar update, so it will be called later than what is received by MainFrame.pm.
|
||||
//wxTheApp->CallAfter(sub {
|
||||
// $self->statusbar->SetStatusText($message);
|
||||
// });
|
||||
|
||||
//$self->{print_file} = undef;
|
||||
//$self->{send_gcode_file} = undef;
|
||||
//$self->print_info_box_show(1);
|
||||
|
||||
// this updates buttons status
|
||||
|
@ -2209,9 +2184,9 @@ void Plater::increase_instances(size_t num)
|
|||
Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0);
|
||||
model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation());
|
||||
#if ENABLE_EXTENDED_SELECTION
|
||||
p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||
#else
|
||||
p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||
// p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||
#endif // ENABLE_EXTENDED_SELECTION
|
||||
}
|
||||
|
||||
|
@ -2254,9 +2229,9 @@ void Plater::decrease_instances(size_t num)
|
|||
for (size_t i = 0; i < num; i++) {
|
||||
model_object->delete_last_instance();
|
||||
#if ENABLE_EXTENDED_SELECTION
|
||||
p->print.get_object(obj_idx)->delete_last_copy();
|
||||
// p->print.get_object(obj_idx)->delete_last_copy();
|
||||
#else
|
||||
p->print.get_object(*obj_idx)->delete_last_copy();
|
||||
// p->print.get_object(*obj_idx)->delete_last_copy();
|
||||
#endif // ENABLE_EXTENDED_SELECTION
|
||||
}
|
||||
#if ENABLE_EXTENDED_SELECTION
|
||||
|
@ -2281,8 +2256,7 @@ void Plater::decrease_instances(size_t num)
|
|||
#endif // ENABLE_EXTENDED_SELECTION
|
||||
|
||||
p->selection_changed();
|
||||
|
||||
// $self->schedule_background_process;
|
||||
this->p->schedule_background_process();
|
||||
}
|
||||
|
||||
void Plater::set_number_of_copies(size_t num)
|
||||
|
@ -2307,38 +2281,35 @@ void Plater::set_number_of_copies(size_t num)
|
|||
decrease_instances(-diff);
|
||||
}
|
||||
|
||||
fs::path Plater::export_gcode(const fs::path &output_path)
|
||||
void Plater::export_gcode(fs::path output_path)
|
||||
{
|
||||
#if ENABLE_EXTENDED_SELECTION
|
||||
if (p->model.objects.empty()) { return ""; }
|
||||
if (p->model.objects.empty())
|
||||
return;
|
||||
#else
|
||||
if (p->objects.empty()) { return ""; }
|
||||
if (p->objects.empty())
|
||||
return;
|
||||
#endif // ENABLE_EXTENDED_SELECTION
|
||||
|
||||
if (! p->export_gcode_output_file.empty()) {
|
||||
if (this->p->background_process.is_export_scheduled()) {
|
||||
GUI::show_error(this, _(L("Another export job is currently running.")));
|
||||
return "";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string err = wxGetApp().preset_bundle->full_config().validate();
|
||||
if (err.empty()) {
|
||||
if (err.empty())
|
||||
err = p->print.validate();
|
||||
}
|
||||
if (! err.empty()) {
|
||||
// The config is not valid
|
||||
GUI::show_error(this, _(err));
|
||||
return fs::path();
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the names of active presets into the placeholder parser.
|
||||
wxGetApp().preset_bundle->export_selections(p->print.placeholder_parser());
|
||||
|
||||
// select output file
|
||||
if (! output_path.empty()) {
|
||||
p->export_gcode_output_file = fs::path(p->print.output_filepath(output_path.string()));
|
||||
// FIXME: ^ errors to handle?
|
||||
} else {
|
||||
|
||||
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.
|
||||
|
@ -2355,13 +2326,17 @@ fs::path Plater::export_gcode(const fs::path &output_path)
|
|||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||
);
|
||||
|
||||
if (dlg.ShowModal() != wxID_OK) { return ""; }
|
||||
fs::path path(dlg.GetPath());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||
p->export_gcode_output_file = path;
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fs::path path(dlg.GetPath());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||
output_path = path;
|
||||
}
|
||||
}
|
||||
|
||||
return p->export_gcode_output_file;
|
||||
if (! output_path.empty()) {
|
||||
this->p->background_process.schedule_export(p->print.output_filepath(output_path.string()));
|
||||
this->p->background_process.start();
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::export_stl()
|
||||
|
@ -2452,7 +2427,7 @@ void Plater::reslice()
|
|||
|
||||
void Plater::send_gcode()
|
||||
{
|
||||
p->send_gcode_file = export_gcode();
|
||||
// p->send_gcode_file = export_gcode();
|
||||
}
|
||||
|
||||
void Plater::on_extruders_change(int num_extruders)
|
||||
|
|
|
@ -118,7 +118,7 @@ public:
|
|||
void set_number_of_copies(size_t num);
|
||||
|
||||
// Note: empty path means "use the default"
|
||||
boost::filesystem::path export_gcode(const boost::filesystem::path &output_path = boost::filesystem::path());
|
||||
void export_gcode(boost::filesystem::path output_path = boost::filesystem::path());
|
||||
void export_stl();
|
||||
void export_amf();
|
||||
void export_3mf();
|
||||
|
|
|
@ -884,7 +884,8 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
|
|||
std::string old_label = ui->GetString(ui_id).utf8_str().data();
|
||||
std::string preset_name = Preset::remove_suffix_modified(old_label);
|
||||
const Preset *preset = this->find_preset(preset_name, false);
|
||||
assert(preset != nullptr);
|
||||
// The old_label could be the "----- system presets ------" or the "------- user presets --------" separator.
|
||||
// assert(preset != nullptr);
|
||||
if (preset != nullptr) {
|
||||
std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name;
|
||||
if (old_label != new_label)
|
||||
|
|
|
@ -53,8 +53,8 @@ ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id):
|
|||
});
|
||||
|
||||
m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
|
||||
if(m_cancel_cb) m_cancel_cb();
|
||||
m_perl_cancel_callback.call();
|
||||
if (m_cancel_cb)
|
||||
m_cancel_cb();
|
||||
m_cancelbutton->Hide();
|
||||
});
|
||||
}
|
||||
|
@ -136,7 +136,17 @@ void ProgressStatusBar::embed(wxFrame *frame)
|
|||
|
||||
void ProgressStatusBar::set_status_text(const wxString& txt)
|
||||
{
|
||||
self->SetStatusText(wxString::FromUTF8(txt.c_str()));
|
||||
self->SetStatusText(txt);
|
||||
}
|
||||
|
||||
void ProgressStatusBar::set_status_text(const std::string& txt)
|
||||
{
|
||||
this->set_status_text(txt.c_str());
|
||||
}
|
||||
|
||||
void ProgressStatusBar::set_status_text(const char *txt)
|
||||
{
|
||||
this->set_status_text(wxString::FromUTF8(txt));
|
||||
}
|
||||
|
||||
void ProgressStatusBar::show_cancel_button()
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include "callback.hpp"
|
||||
|
||||
class wxTimer;
|
||||
class wxGauge;
|
||||
class wxButton;
|
||||
|
@ -22,7 +20,8 @@ namespace Slic3r {
|
|||
* of the Slicer main window. It consists of a message area to the left and a
|
||||
* progress indication area to the right with an optional cancel button.
|
||||
*/
|
||||
class ProgressStatusBar {
|
||||
class ProgressStatusBar
|
||||
{
|
||||
wxStatusBar *self; // we cheat! It should be the base class but: perl!
|
||||
wxTimer *m_timer;
|
||||
wxGauge *m_prog;
|
||||
|
@ -35,25 +34,26 @@ public:
|
|||
ProgressStatusBar(wxWindow *parent = nullptr, int id = -1);
|
||||
~ProgressStatusBar();
|
||||
|
||||
int get_progress() const;
|
||||
void set_progress(int);
|
||||
int get_range() const;
|
||||
void set_range(int = 100);
|
||||
void show_progress(bool);
|
||||
void start_busy(int = 100);
|
||||
void stop_busy();
|
||||
int get_progress() const;
|
||||
void set_progress(int);
|
||||
int get_range() const;
|
||||
void set_range(int = 100);
|
||||
void show_progress(bool);
|
||||
void start_busy(int = 100);
|
||||
void stop_busy();
|
||||
inline bool is_busy() const { return m_busy; }
|
||||
void set_cancel_callback(CancelFn = CancelFn());
|
||||
inline void remove_cancel_callback() { set_cancel_callback(); }
|
||||
void run(int rate);
|
||||
void embed(wxFrame *frame = nullptr);
|
||||
void set_status_text(const wxString& txt);
|
||||
void set_cancel_callback(CancelFn = CancelFn());
|
||||
inline void reset_cancel_callback() { set_cancel_callback(); }
|
||||
void run(int rate);
|
||||
void embed(wxFrame *frame = nullptr);
|
||||
void set_status_text(const wxString& txt);
|
||||
void set_status_text(const std::string& txt);
|
||||
void set_status_text(const char *txt);
|
||||
|
||||
// Temporary methods to satisfy Perl side
|
||||
void show_cancel_button();
|
||||
void hide_cancel_button();
|
||||
void show_cancel_button();
|
||||
void hide_cancel_button();
|
||||
|
||||
PerlCallback m_perl_cancel_callback;
|
||||
private:
|
||||
bool m_busy = false;
|
||||
CancelFn m_cancel_cb;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue