mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 06:12:00 +08:00
Add export all functionality backend
- Missing BulkExportDialog
This commit is contained in:
parent
62f5fafe15
commit
ab58ccff60
@ -175,7 +175,7 @@ void BackgroundSlicingProcess::process_fff()
|
|||||||
if (this->set_step_started(bspsGCodeFinalize)) {
|
if (this->set_step_started(bspsGCodeFinalize)) {
|
||||||
if (! m_export_path.empty()) {
|
if (! m_export_path.empty()) {
|
||||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||||
finalize_gcode();
|
finalize_gcode(m_export_path, m_export_path_on_removable_media);
|
||||||
} else if (! m_upload_job.empty()) {
|
} else if (! m_upload_job.empty()) {
|
||||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||||
prepare_upload();
|
prepare_upload();
|
||||||
@ -680,12 +680,12 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
|
|||||||
// G-code is generated in m_temp_output_path.
|
// G-code is generated in m_temp_output_path.
|
||||||
// Optionally run a post-processing script on a copy of m_temp_output_path.
|
// Optionally run a post-processing script on a copy of m_temp_output_path.
|
||||||
// Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error).
|
// Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error).
|
||||||
void BackgroundSlicingProcess::finalize_gcode()
|
void BackgroundSlicingProcess::finalize_gcode(const std::string &path, const bool path_on_removable_media)
|
||||||
{
|
{
|
||||||
m_print->set_status(95, _u8L("Running post-processing scripts"));
|
m_print->set_status(95, _u8L("Running post-processing scripts"));
|
||||||
|
|
||||||
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
||||||
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
|
std::string export_path = m_fff_print->print_statistics().finalize_output_path(path);
|
||||||
std::string output_path = m_temp_output_path;
|
std::string output_path = m_temp_output_path;
|
||||||
// Both output_path and export_path ar in-out parameters.
|
// Both output_path and export_path ar in-out parameters.
|
||||||
// If post processed, output_path will differ from m_temp_output_path as run_post_process_scripts() will make a copy of the G-code to not
|
// If post processed, output_path will differ from m_temp_output_path as run_post_process_scripts() will make a copy of the G-code to not
|
||||||
@ -707,7 +707,7 @@ void BackgroundSlicingProcess::finalize_gcode()
|
|||||||
int copy_ret_val = CopyFileResult::SUCCESS;
|
int copy_ret_val = CopyFileResult::SUCCESS;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
copy_ret_val = copy_file(output_path, export_path, error_message, m_export_path_on_removable_media);
|
copy_ret_val = copy_file(output_path, export_path, error_message, path_on_removable_media);
|
||||||
remove_post_processed_temp_file();
|
remove_post_processed_temp_file();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
@ -175,7 +175,8 @@ public:
|
|||||||
// This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs),
|
// This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs),
|
||||||
// and it does not account for the OctoPrint scheduling.
|
// and it does not account for the OctoPrint scheduling.
|
||||||
bool finished() const { return m_print->finished(); }
|
bool finished() const { return m_print->finished(); }
|
||||||
|
void finalize_gcode(const std::string &path, const bool path_on_removable_media);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void thread_proc();
|
void thread_proc();
|
||||||
// Calls thread_proc(), catches all C++ exceptions and shows them using wxApp::OnUnhandledException().
|
// Calls thread_proc(), catches all C++ exceptions and shows them using wxApp::OnUnhandledException().
|
||||||
@ -266,7 +267,6 @@ private:
|
|||||||
bool invalidate_all_steps();
|
bool invalidate_all_steps();
|
||||||
// If the background processing stop was requested, throw CanceledException.
|
// If the background processing stop was requested, throw CanceledException.
|
||||||
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
|
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
|
||||||
void finalize_gcode();
|
|
||||||
void prepare_upload();
|
void prepare_upload();
|
||||||
// To be executed at the background thread.
|
// To be executed at the background thread.
|
||||||
ThumbnailsList render_thumbnails(const ThumbnailsParams ¶ms);
|
ThumbnailsList render_thumbnails(const ThumbnailsParams ¶ms);
|
||||||
|
@ -125,9 +125,6 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user)
|
|||||||
m_sequential_print_clearance.m_evaluating = true;
|
m_sequential_print_clearance.m_evaluating = true;
|
||||||
reset_sequential_print_clearance();
|
reset_sequential_print_clearance();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The stop call above schedules some events that would be processed after the switch.
|
// The stop call above schedules some events that would be processed after the switch.
|
||||||
// Among else, on_process_completed would be called, which would stop slicing of
|
// Among else, on_process_completed would be called, which would stop slicing of
|
||||||
// the new bed. We need to stop the process, pump all the events out of the queue
|
// the new bed. We need to stop the process, pump all the events out of the queue
|
||||||
@ -2226,6 +2223,7 @@ void GLCanvas3D::render()
|
|||||||
wxGetApp().plater()->schedule_background_process();
|
wxGetApp().plater()->schedule_background_process();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
wxGetApp().plater()->show_autoslicing_action_buttons();
|
||||||
render_print_statistics();
|
render_print_statistics();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6721,6 +6719,7 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector()
|
|||||||
if (!s_multiple_beds.is_autoslicing()) {
|
if (!s_multiple_beds.is_autoslicing()) {
|
||||||
s_multiple_beds.start_autoslice([this](int i, bool user) { this->select_bed(i, user); });
|
s_multiple_beds.start_autoslice([this](int i, bool user) { this->select_bed(i, user); });
|
||||||
wxGetApp().sidebar().switch_to_autoslicing_mode();
|
wxGetApp().sidebar().switch_to_autoslicing_mode();
|
||||||
|
wxGetApp().plater()->show_autoslicing_action_buttons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2350,7 +2350,15 @@ void NotificationManager::push_exporting_finished_notification(const std::string
|
|||||||
{
|
{
|
||||||
close_notification_of_type(NotificationType::ExportFinished);
|
close_notification_of_type(NotificationType::ExportFinished);
|
||||||
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path };
|
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path };
|
||||||
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0);
|
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, dir_path), 0);
|
||||||
|
set_slicing_progress_hidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationManager::push_bulk_exporting_finished_notification(const std::string& dir_path, bool on_removable)
|
||||||
|
{
|
||||||
|
close_notification_of_type(NotificationType::ExportFinished);
|
||||||
|
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Bulk export finished.") + "\n" + dir_path};
|
||||||
|
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, dir_path), 0);
|
||||||
set_slicing_progress_hidden();
|
set_slicing_progress_hidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +231,7 @@ public:
|
|||||||
void set_sla(bool b) { set_fff(!b); }
|
void set_sla(bool b) { set_fff(!b); }
|
||||||
// Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button
|
// Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button
|
||||||
void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable);
|
void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable);
|
||||||
|
void push_bulk_exporting_finished_notification(const std::string& dir_path, bool on_removable);
|
||||||
// notifications with progress bar
|
// notifications with progress bar
|
||||||
// print host upload
|
// print host upload
|
||||||
void push_upload_job_notification(int id, float filesize, const std::string& filename, const std::string& host, float percentage = 0);
|
void push_upload_job_notification(int id, float filesize, const std::string& filename, const std::string& host, float percentage = 0);
|
||||||
@ -783,10 +784,15 @@ private:
|
|||||||
class ExportFinishedNotification : public PopNotification
|
class ExportFinishedNotification : public PopNotification
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExportFinishedNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool to_removable,const std::string& export_path,const std::string& export_dir_path)
|
ExportFinishedNotification(
|
||||||
: PopNotification(n, id_provider, evt_handler)
|
const NotificationData& n,
|
||||||
|
NotificationIDProvider& id_provider,
|
||||||
|
wxEvtHandler* evt_handler,
|
||||||
|
bool to_removable,
|
||||||
|
const std::string& export_dir_path
|
||||||
|
):
|
||||||
|
PopNotification(n, id_provider, evt_handler)
|
||||||
, m_to_removable(to_removable)
|
, m_to_removable(to_removable)
|
||||||
, m_export_path(export_path)
|
|
||||||
, m_export_dir_path(export_dir_path)
|
, m_export_dir_path(export_dir_path)
|
||||||
{
|
{
|
||||||
m_multiline = true;
|
m_multiline = true;
|
||||||
|
@ -534,6 +534,7 @@ struct Plater::priv
|
|||||||
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
|
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
|
||||||
|
|
||||||
void show_action_buttons(const bool is_ready_to_slice) const;
|
void show_action_buttons(const bool is_ready_to_slice) const;
|
||||||
|
void show_autoslicing_action_buttons() const;
|
||||||
bool can_show_upload_to_connect() const;
|
bool can_show_upload_to_connect() const;
|
||||||
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
|
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
|
||||||
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
// triangulate the bed and store the triangles into m_bed.m_triangles,
|
||||||
@ -2252,6 +2253,10 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
|||||||
}
|
}
|
||||||
)};
|
)};
|
||||||
|
|
||||||
|
if (any_status_changed) {
|
||||||
|
wxGetApp().plater()->show_autoslicing_action_buttons();
|
||||||
|
}
|
||||||
|
|
||||||
// If current bed was invalidated, update thumbnails for all beds:
|
// If current bed was invalidated, update thumbnails for all beds:
|
||||||
if (int num = s_multiple_beds.get_number_of_beds(); num > 1 && any_status_changed) {
|
if (int num = s_multiple_beds.get_number_of_beds(); num > 1 && any_status_changed) {
|
||||||
ThumbnailData data;
|
ThumbnailData data;
|
||||||
@ -2423,8 +2428,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
|||||||
const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ?
|
const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ?
|
||||||
_L("Slicing") + dots : _L("Slice now");
|
_L("Slicing") + dots : _L("Slice now");
|
||||||
sidebar->set_btn_label(ActionButtonType::Reslice, slice_string);
|
sidebar->set_btn_label(ActionButtonType::Reslice, slice_string);
|
||||||
|
if (background_process.empty()) {
|
||||||
if (background_process.finished())
|
sidebar->enable_buttons(false);
|
||||||
|
} else if (background_process.finished())
|
||||||
show_action_buttons(false);
|
show_action_buttons(false);
|
||||||
else if (!background_process.empty() &&
|
else if (!background_process.empty() &&
|
||||||
!background_process.running()) /* Do not update buttons if background process is running
|
!background_process.running()) /* Do not update buttons if background process is running
|
||||||
@ -3956,6 +3962,35 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice_) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::priv::show_autoslicing_action_buttons() const {
|
||||||
|
if (!s_multiple_beds.is_autoslicing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wxWindowUpdateLocker noUpdater(sidebar);
|
||||||
|
|
||||||
|
DynamicPrintConfig* selected_printer_config = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config();
|
||||||
|
const auto print_host_opt = selected_printer_config ? selected_printer_config->option<ConfigOptionString>("print_host") : nullptr;
|
||||||
|
const bool connect_gcode_shown = print_host_opt == nullptr && can_show_upload_to_connect();
|
||||||
|
|
||||||
|
RemovableDriveManager::RemovableDrivesStatus removable_media_status = wxGetApp().removable_drive_manager()->status();
|
||||||
|
|
||||||
|
bool updated{sidebar->show_export_all(true)};
|
||||||
|
updated = sidebar->show_connect_all(connect_gcode_shown) || updated;
|
||||||
|
updated = sidebar->show_export_removable_all(removable_media_status.has_removable_drives) || updated;
|
||||||
|
if (updated) {
|
||||||
|
sidebar->Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool all_finished{std::all_of(
|
||||||
|
this->fff_prints.begin(),
|
||||||
|
this->fff_prints.end(),
|
||||||
|
[](const std::unique_ptr<Print> &print){
|
||||||
|
return print->finished() || print->empty();
|
||||||
|
}
|
||||||
|
)};
|
||||||
|
sidebar->enable_bulk_buttons(all_finished);
|
||||||
|
}
|
||||||
|
|
||||||
void Plater::priv::enter_gizmos_stack()
|
void Plater::priv::enter_gizmos_stack()
|
||||||
{
|
{
|
||||||
assert(m_undo_redo_stack_active == &m_undo_redo_stack_main);
|
assert(m_undo_redo_stack_active == &m_undo_redo_stack_main);
|
||||||
@ -5679,14 +5714,24 @@ static wxString check_binary_vs_ascii_gcode_extension(PrinterTechnology pt, cons
|
|||||||
// This function should be deleted when binary G-codes become more common. The dialog is there to make the
|
// This function should be deleted when binary G-codes become more common. The dialog is there to make the
|
||||||
// transition period easier for the users, because bgcode files are not recognized by older firmwares
|
// transition period easier for the users, because bgcode files are not recognized by older firmwares
|
||||||
// without any error message.
|
// without any error message.
|
||||||
static void alert_when_exporting_binary_gcode(bool binary_output, const std::string& printer_notes)
|
void alert_when_exporting_binary_gcode(const std::string& printer_notes)
|
||||||
{
|
{
|
||||||
if (binary_output
|
const bool supports_binary = wxGetApp()
|
||||||
&& (boost::algorithm::contains(printer_notes, "PRINTER_MODEL_XL")
|
.preset_bundle->printers
|
||||||
|| boost::algorithm::contains(printer_notes, "PRINTER_MODEL_MINI")
|
.get_edited_preset()
|
||||||
|| boost::algorithm::contains(printer_notes, "PRINTER_MODEL_MK4")
|
.config.opt_bool("binary_gcode");
|
||||||
|| boost::algorithm::contains(printer_notes, "PRINTER_MODEL_MK3.9")))
|
const bool uses_binary = wxGetApp().app_config->get_bool("use_binary_gcode_when_supported");
|
||||||
{
|
const bool binary_output{supports_binary && uses_binary};
|
||||||
|
|
||||||
|
if (
|
||||||
|
binary_output
|
||||||
|
&& (
|
||||||
|
boost::algorithm::contains(printer_notes, "PRINTER_MODEL_XL")
|
||||||
|
|| boost::algorithm::contains(printer_notes, "PRINTER_MODEL_MINI")
|
||||||
|
|| boost::algorithm::contains(printer_notes, "PRINTER_MODEL_MK4")
|
||||||
|
|| boost::algorithm::contains(printer_notes, "PRINTER_MODEL_MK3.9")
|
||||||
|
)
|
||||||
|
) {
|
||||||
AppConfig* app_config = wxGetApp().app_config;
|
AppConfig* app_config = wxGetApp().app_config;
|
||||||
wxWindow* parent = wxGetApp().mainframe;
|
wxWindow* parent = wxGetApp().mainframe;
|
||||||
const std::string option_key = "dont_warn_about_firmware_version_when_exporting_binary_gcode";
|
const std::string option_key = "dont_warn_about_firmware_version_when_exporting_binary_gcode";
|
||||||
@ -5708,7 +5753,116 @@ static void alert_when_exporting_binary_gcode(bool binary_output, const std::str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<fs::path> Plater::get_default_output_file() {
|
||||||
|
try {
|
||||||
|
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
|
||||||
|
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
|
||||||
|
unsigned int state = this->p->update_restart_background_process(false, false);
|
||||||
|
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
const std::string path{
|
||||||
|
this->p->background_process.output_filepath_for_project(
|
||||||
|
into_path(get_project_filename(".3mf"))
|
||||||
|
)
|
||||||
|
};
|
||||||
|
return fs::path(Slic3r::fold_utf8_to_ascii(path));
|
||||||
|
} catch (const Slic3r::PlaceholderParserError &ex) {
|
||||||
|
// Show the error with monospaced font.
|
||||||
|
show_error(this, ex.what(), true);
|
||||||
|
return std::nullopt;
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
show_error(this, ex.what(), false);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_output_start_dir(const bool prefer_removable, const fs::path &default_output_file) {
|
||||||
|
const AppConfig &appconfig{*wxGetApp().app_config};
|
||||||
|
RemovableDriveManager &removable_drive_manager{*wxGetApp().removable_drive_manager()};
|
||||||
|
// Get a last save path, either to removable media or to an internal media.
|
||||||
|
std::string last_output_dir{appconfig.get_last_output_dir(
|
||||||
|
default_output_file.parent_path().string(),
|
||||||
|
prefer_removable
|
||||||
|
)};
|
||||||
|
if (!prefer_removable) {
|
||||||
|
return last_output_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a path to a removable media if it exists, prefering start_dir. Update the internal removable drives database.
|
||||||
|
std::string removable_dir{removable_drive_manager.get_removable_drive_path(last_output_dir)};
|
||||||
|
if (removable_dir.empty()) {
|
||||||
|
// Direct user to the last internal media.
|
||||||
|
return appconfig.get_last_output_dir(default_output_file.parent_path().string(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return removable_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<wxString> Plater::check_output_path_has_error(const boost::filesystem::path& path) const {
|
||||||
|
const std::string filename = path.filename().string();
|
||||||
|
const std::string ext = boost::algorithm::to_lower_copy(path.extension().string());
|
||||||
|
if (has_illegal_characters(filename)) {
|
||||||
|
return {
|
||||||
|
_L("The provided file name is not valid.") + "\n" +
|
||||||
|
_L("The following characters are not allowed by a FAT file system:") + " <>:/\\|?*\""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (this->printer_technology() == ptFFF) {
|
||||||
|
bool supports_binary = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_bool("binary_gcode");
|
||||||
|
bool uses_binary = wxGetApp().app_config->get_bool("use_binary_gcode_when_supported");
|
||||||
|
const wxString error{check_binary_vs_ascii_gcode_extension(
|
||||||
|
printer_technology(), ext, supports_binary && uses_binary
|
||||||
|
)};
|
||||||
|
if (!error.IsEmpty()) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<fs::path> Plater::get_output_path(const std::string &start_dir, const fs::path &default_output_file) {
|
||||||
|
const std::string ext = default_output_file.extension().string();
|
||||||
|
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
|
||||||
|
start_dir,
|
||||||
|
from_path(default_output_file.filename()),
|
||||||
|
printer_technology() == ptFFF ? GUI::file_wildcards(FT_GCODE, ext) :
|
||||||
|
GUI::sla_wildcards(active_sla_print().printer_config().sla_archive_format.value.c_str(), ext),
|
||||||
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dlg.ShowModal() != wxID_OK) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fs::path output_path{into_path(dlg.GetPath())};
|
||||||
|
if (auto error{check_output_path_has_error(output_path)}) {
|
||||||
|
const t_link_clicked on_link_clicked = [](const std::string& key) -> void { wxGetApp().jump_to_option(key); };
|
||||||
|
ErrorDialog(this, *error, on_link_clicked).ShowModal();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return output_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<fs::path> Plater::get_multiple_output_dir(const std::string &start_dir) {
|
||||||
|
wxDirDialog dlg(
|
||||||
|
this,
|
||||||
|
_L("Choose export directory:"),
|
||||||
|
start_dir
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dlg.ShowModal() != wxID_OK) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fs::path output_path{into_path(dlg.GetPath())};
|
||||||
|
if (auto error{check_output_path_has_error(output_path)}) {
|
||||||
|
const t_link_clicked on_link_clicked = [](const std::string& key) -> void { wxGetApp().jump_to_option(key); };
|
||||||
|
ErrorDialog(this, *error, on_link_clicked).ShowModal();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return output_path;
|
||||||
|
}
|
||||||
|
|
||||||
void Plater::export_gcode(bool prefer_removable)
|
void Plater::export_gcode(bool prefer_removable)
|
||||||
{
|
{
|
||||||
@ -5724,91 +5878,109 @@ void Plater::export_gcode(bool prefer_removable)
|
|||||||
|
|
||||||
// If possible, remove accents from accented latin characters.
|
// If possible, remove accents from accented latin characters.
|
||||||
// This function is useful for generating file names to be processed by legacy firmwares.
|
// This function is useful for generating file names to be processed by legacy firmwares.
|
||||||
fs::path default_output_file;
|
const auto optional_default_output_file{this->get_default_output_file()};
|
||||||
try {
|
if (!optional_default_output_file) {
|
||||||
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
|
|
||||||
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
|
|
||||||
unsigned int state = this->p->update_restart_background_process(false, false);
|
|
||||||
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
|
|
||||||
return;
|
|
||||||
default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf")));
|
|
||||||
} catch (const Slic3r::PlaceholderParserError &ex) {
|
|
||||||
// Show the error with monospaced font.
|
|
||||||
show_error(this, ex.what(), true);
|
|
||||||
return;
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
show_error(this, ex.what(), false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
const fs::path &default_output_file{*optional_default_output_file};
|
||||||
AppConfig &appconfig = *wxGetApp().app_config;
|
const std::string start_dir{get_output_start_dir(prefer_removable, default_output_file)};
|
||||||
RemovableDriveManager &removable_drive_manager = *wxGetApp().removable_drive_manager();
|
|
||||||
// Get a last save path, either to removable media or to an internal media.
|
|
||||||
std::string start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), prefer_removable);
|
|
||||||
if (prefer_removable) {
|
|
||||||
// Returns a path to a removable media if it exists, prefering start_dir. Update the internal removable drives database.
|
|
||||||
start_dir = removable_drive_manager.get_removable_drive_path(start_dir);
|
|
||||||
if (start_dir.empty())
|
|
||||||
// Direct user to the last internal media.
|
|
||||||
start_dir = appconfig.get_last_output_dir(default_output_file.parent_path().string(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::path output_path;
|
const auto optional_output_path{get_output_path(start_dir, default_output_file)};
|
||||||
{
|
if (!optional_output_path) {
|
||||||
std::string ext = default_output_file.extension().string();
|
return;
|
||||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 / SL1S file as:"),
|
}
|
||||||
start_dir,
|
const fs::path &output_path{*optional_output_path};
|
||||||
from_path(default_output_file.filename()),
|
|
||||||
printer_technology() == ptFFF ? GUI::file_wildcards(FT_GCODE, ext) :
|
if (printer_technology() == ptFFF) {
|
||||||
GUI::sla_wildcards(active_sla_print().printer_config().sla_archive_format.value.c_str(), ext),
|
alert_when_exporting_binary_gcode(
|
||||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
wxGetApp()
|
||||||
|
.preset_bundle->printers
|
||||||
|
.get_edited_preset()
|
||||||
|
.config.opt_string("printer_notes")
|
||||||
);
|
);
|
||||||
if (dlg.ShowModal() == wxID_OK) {
|
}
|
||||||
output_path = into_path(dlg.GetPath());
|
export_gcode_to_path(output_path, [&](const bool path_on_removable_media){
|
||||||
|
p->export_gcode(output_path, path_on_removable_media, PrintHostJob());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
auto check_for_error = [this](const boost::filesystem::path& path, wxString& err_out) -> bool {
|
void Plater::export_gcode_to_path(
|
||||||
const std::string filename = path.filename().string();
|
const fs::path &output_path,
|
||||||
const std::string ext = boost::algorithm::to_lower_copy(path.extension().string());
|
const std::function<void(bool)> &export_callback
|
||||||
if (has_illegal_characters(filename)) {
|
) {
|
||||||
err_out = _L("The provided file name is not valid.") + "\n" +
|
AppConfig &appconfig{*wxGetApp().app_config};
|
||||||
_L("The following characters are not allowed by a FAT file system:") + " <>:/\\|?*\"";
|
RemovableDriveManager &removable_drive_manager{*wxGetApp().removable_drive_manager()};
|
||||||
return true;
|
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
|
||||||
}
|
p->notification_manager->new_export_began(path_on_removable_media);
|
||||||
if (this->printer_technology() == ptFFF) {
|
p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL;
|
||||||
bool supports_binary = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_bool("binary_gcode");
|
p->last_output_path = output_path.string();
|
||||||
bool uses_binary = wxGetApp().app_config->get_bool("use_binary_gcode_when_supported");
|
p->last_output_dir_path = output_path.parent_path().string();
|
||||||
err_out = check_binary_vs_ascii_gcode_extension(printer_technology(), ext, supports_binary && uses_binary);
|
export_callback(path_on_removable_media);
|
||||||
}
|
// Storing a path to AppConfig either as path to removable media or a path to internal media.
|
||||||
return !err_out.IsEmpty();
|
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
|
||||||
};
|
// while the dialog was open.
|
||||||
|
appconfig.update_last_output_dir(output_path.parent_path().string(), path_on_removable_media);
|
||||||
|
}
|
||||||
|
|
||||||
wxString error_str;
|
struct PrintToExport{ std::reference_wrapper<Print> print;
|
||||||
if (check_for_error(output_path, error_str)) {
|
std::reference_wrapper<GCodeProcessorResult> processor_result;
|
||||||
const t_link_clicked on_link_clicked = [](const std::string& key) -> void { wxGetApp().jump_to_option(key); };
|
fs::path output_path;
|
||||||
ErrorDialog(this, error_str, on_link_clicked).ShowModal();
|
};
|
||||||
output_path.clear();
|
|
||||||
} else if (printer_technology() == ptFFF) {
|
void Plater::export_all_gcodes(bool prefer_removable) {
|
||||||
bool supports_binary = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_bool("binary_gcode");
|
const auto optional_default_output_file{this->get_default_output_file()};
|
||||||
bool uses_binary = wxGetApp().app_config->get_bool("use_binary_gcode_when_supported");
|
if (!optional_default_output_file) {
|
||||||
alert_when_exporting_binary_gcode(supports_binary && uses_binary,
|
return;
|
||||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_notes"));
|
}
|
||||||
}
|
const fs::path &default_output_file{*optional_default_output_file};
|
||||||
|
const std::string start_dir{get_output_start_dir(prefer_removable, default_output_file)};
|
||||||
|
const auto optional_output_dir{get_multiple_output_dir(start_dir)};
|
||||||
|
if (!optional_output_dir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fs_path &output_dir{*optional_output_dir};
|
||||||
|
|
||||||
|
std::vector<PrintToExport> prints_to_export;
|
||||||
|
|
||||||
|
for (std::size_t print_index{0}; print_index < this->get_fff_prints().size(); ++print_index) {
|
||||||
|
const std::unique_ptr<Print> &print{this->get_fff_prints()[print_index]};
|
||||||
|
if (!print || print->empty()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fs::path filename{
|
||||||
|
default_output_file.stem().string()
|
||||||
|
+ "_bed"
|
||||||
|
+ std::to_string(print_index + 1)
|
||||||
|
+ default_output_file.extension().string()
|
||||||
|
};
|
||||||
|
const fs::path output_file{output_dir / filename};
|
||||||
|
prints_to_export.push_back({*print, this->p->gcode_results[print_index], output_file});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! output_path.empty()) {
|
//BulkExportDialog dialog{prints_to_export};
|
||||||
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
|
//if (dialog.ShowModal() != wxID_OK) {
|
||||||
p->notification_manager->new_export_began(path_on_removable_media);
|
// return;
|
||||||
p->exporting_status = path_on_removable_media ? ExportingStatus::EXPORTING_TO_REMOVABLE : ExportingStatus::EXPORTING_TO_LOCAL;
|
//}
|
||||||
p->last_output_path = output_path.string();
|
//prints_to_export = dialog.get_prints_to_export();
|
||||||
p->last_output_dir_path = output_path.parent_path().string();
|
|
||||||
p->export_gcode(output_path, path_on_removable_media, PrintHostJob());
|
bool path_on_removable_media{false};
|
||||||
// Storing a path to AppConfig either as path to removable media or a path to internal media.
|
for (const PrintToExport &print_to_export : prints_to_export) {
|
||||||
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
|
this->p->background_process.set_fff_print(&print_to_export.print.get());
|
||||||
// while the dialog was open.
|
this->p->background_process.set_gcode_result(&print_to_export.processor_result.get());
|
||||||
appconfig.update_last_output_dir(output_path.parent_path().string(), path_on_removable_media);
|
export_gcode_to_path(
|
||||||
|
print_to_export.output_path,
|
||||||
}
|
[&](const bool on_removable){
|
||||||
|
this->p->background_process.finalize_gcode(
|
||||||
|
print_to_export.output_path.string(),
|
||||||
|
path_on_removable_media
|
||||||
|
);
|
||||||
|
path_on_removable_media = on_removable || path_on_removable_media;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->notification_manager->push_bulk_exporting_finished_notification(output_dir.string(), path_on_removable_media);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::export_stl_obj(bool extended, bool selection_only)
|
void Plater::export_stl_obj(bool extended, bool selection_only)
|
||||||
@ -6483,10 +6655,12 @@ void Plater::send_gcode_inner(DynamicPrintConfig* physical_printer_config)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supports_binary = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_bool("binary_gcode");
|
alert_when_exporting_binary_gcode(
|
||||||
bool uses_binary = wxGetApp().app_config->get_bool("use_binary_gcode_when_supported");
|
wxGetApp().
|
||||||
alert_when_exporting_binary_gcode(supports_binary && uses_binary,
|
preset_bundle->printers.
|
||||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_notes"));
|
get_edited_preset().
|
||||||
|
config.opt_string("printer_notes")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
upload_job.upload_data.upload_path = dlg.filename();
|
upload_job.upload_data.upload_path = dlg.filename();
|
||||||
@ -7128,6 +7302,8 @@ void Plater::update_menus() { p->menus.update(); }
|
|||||||
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
|
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
|
||||||
void Plater::show_action_buttons() const { p->show_action_buttons(p->ready_to_slice); }
|
void Plater::show_action_buttons() const { p->show_action_buttons(p->ready_to_slice); }
|
||||||
|
|
||||||
|
void Plater::show_autoslicing_action_buttons() const { p->show_autoslicing_action_buttons(); };
|
||||||
|
|
||||||
void Plater::copy_selection_to_clipboard()
|
void Plater::copy_selection_to_clipboard()
|
||||||
{
|
{
|
||||||
// At first try to copy selected values to the ObjectList's clipboard
|
// At first try to copy selected values to the ObjectList's clipboard
|
||||||
|
@ -215,6 +215,7 @@ public:
|
|||||||
void apply_cut_object_to_model(size_t init_obj_idx, const ModelObjectPtrs& cut_objects);
|
void apply_cut_object_to_model(size_t init_obj_idx, const ModelObjectPtrs& cut_objects);
|
||||||
|
|
||||||
void export_gcode(bool prefer_removable);
|
void export_gcode(bool prefer_removable);
|
||||||
|
void export_all_gcodes(bool prefer_removable);
|
||||||
void export_stl_obj(bool extended = false, bool selection_only = false);
|
void export_stl_obj(bool extended = false, bool selection_only = false);
|
||||||
bool export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
bool export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
||||||
void reload_from_disk();
|
void reload_from_disk();
|
||||||
@ -277,6 +278,7 @@ public:
|
|||||||
void update_menus();
|
void update_menus();
|
||||||
void show_action_buttons(const bool is_ready_to_slice) const;
|
void show_action_buttons(const bool is_ready_to_slice) const;
|
||||||
void show_action_buttons() const;
|
void show_action_buttons() const;
|
||||||
|
void show_autoslicing_action_buttons() const;
|
||||||
|
|
||||||
wxString get_project_filename(const wxString& extension = wxEmptyString) const;
|
wxString get_project_filename(const wxString& extension = wxEmptyString) const;
|
||||||
void set_project_filename(const wxString& filename);
|
void set_project_filename(const wxString& filename);
|
||||||
@ -447,6 +449,12 @@ public:
|
|||||||
wxMenu* multi_selection_menu();
|
wxMenu* multi_selection_menu();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::optional<fs_path> get_default_output_file();
|
||||||
|
std::optional<wxString> check_output_path_has_error(const boost::filesystem::path& path) const;
|
||||||
|
std::optional<fs_path> get_output_path(const std::string &start_dir, const fs_path &default_output_file);
|
||||||
|
std::optional<fs_path> get_multiple_output_dir(const std::string &start_dir);
|
||||||
|
|
||||||
|
void export_gcode_to_path(const fs_path &output_path, const std::function<void(bool)> &export_callback);
|
||||||
void reslice_until_step_inner(int step, const ModelObject &object, bool postpone_error_messages);
|
void reslice_until_step_inner(int step, const ModelObject &object, bool postpone_error_messages);
|
||||||
|
|
||||||
struct priv;
|
struct priv;
|
||||||
|
@ -513,11 +513,30 @@ Sidebar::Sidebar(Plater *parent)
|
|||||||
|
|
||||||
auto *sizer = new wxBoxSizer(wxVERTICAL);
|
auto *sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
sizer->Add(m_scrolled_panel, 1, wxEXPAND);
|
sizer->Add(m_scrolled_panel, 1, wxEXPAND);
|
||||||
sizer->Add(m_btns_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM
|
|
||||||
|
const int buttons_sizer_flags{
|
||||||
|
wxEXPAND
|
||||||
|
| wxLEFT
|
||||||
|
| wxBOTTOM
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
| wxRIGHT
|
| wxRIGHT
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
, margin_5);
|
};
|
||||||
|
sizer->Add(m_btns_sizer, 0, buttons_sizer_flags, margin_5);
|
||||||
|
|
||||||
|
m_autoslicing_btns_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
|
init_scalable_btn(&m_btn_export_all_gcode_removable, "export_to_sd", _L("Export all to SD card / Flash drive") + " " + GUI::shortkey_ctrl_prefix() + "U");
|
||||||
|
init_btn(&m_btn_export_all_gcode, _L("Export all G-codes") + dots, scaled_height);
|
||||||
|
init_btn(&m_btn_connect_gcode_all, _L("Send all to Connect"), scaled_height);
|
||||||
|
|
||||||
|
m_autoslicing_btns_sizer->Add(m_btn_export_all_gcode, 1, wxEXPAND);
|
||||||
|
m_autoslicing_btns_sizer->Add(m_btn_connect_gcode_all, 1, wxEXPAND | wxLEFT, margin_5);
|
||||||
|
m_autoslicing_btns_sizer->Add(m_btn_export_all_gcode_removable, 0, wxLEFT, margin_5);
|
||||||
|
|
||||||
|
m_autoslicing_btns_sizer->Show(false);
|
||||||
|
|
||||||
|
sizer->Add(m_autoslicing_btns_sizer, 0, buttons_sizer_flags | wxTOP, margin_5);
|
||||||
SetSizer(sizer);
|
SetSizer(sizer);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
@ -552,6 +571,14 @@ Sidebar::Sidebar(Plater *parent)
|
|||||||
|
|
||||||
this->Bind(wxEVT_COMBOBOX, &Sidebar::on_select_preset, this);
|
this->Bind(wxEVT_COMBOBOX, &Sidebar::on_select_preset, this);
|
||||||
|
|
||||||
|
m_btn_export_all_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||||
|
this->m_plater->export_all_gcodes(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_btn_export_all_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||||
|
this->m_plater->export_all_gcodes(true);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sidebar::~Sidebar() {}
|
Sidebar::~Sidebar() {}
|
||||||
@ -1098,6 +1125,15 @@ void Sidebar::show_btns_sizer(const bool show)
|
|||||||
m_scrolled_panel->Refresh();
|
m_scrolled_panel->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sidebar::show_bulk_btns_sizer(const bool show)
|
||||||
|
{
|
||||||
|
wxWindowUpdateLocker freeze_guard(this);
|
||||||
|
m_autoslicing_btns_sizer->Show(show);
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
m_scrolled_panel->Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
void Sidebar::enable_buttons(bool enable)
|
void Sidebar::enable_buttons(bool enable)
|
||||||
{
|
{
|
||||||
m_btn_reslice->Enable(enable);
|
m_btn_reslice->Enable(enable);
|
||||||
@ -1107,19 +1143,26 @@ void Sidebar::enable_buttons(bool enable)
|
|||||||
m_btn_connect_gcode->Enable(enable);
|
m_btn_connect_gcode->Enable(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sidebar::show_reslice(bool show) const {
|
void Sidebar::enable_bulk_buttons(bool enable)
|
||||||
|
{
|
||||||
|
m_btn_export_all_gcode->Enable(enable);
|
||||||
|
m_btn_export_all_gcode_removable->Enable(enable);
|
||||||
|
m_btn_connect_gcode_all->Enable(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sidebar::show_reslice(bool show) const {
|
||||||
if (this->m_autoslicing_mode) {
|
if (this->m_autoslicing_mode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_btn_reslice->Show(show);
|
return m_btn_reslice->Show(show);
|
||||||
}
|
}
|
||||||
bool Sidebar::show_export(bool show) const {
|
bool Sidebar::show_export(bool show) const {
|
||||||
if (this->m_autoslicing_mode) {
|
if (this->m_autoslicing_mode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_btn_export_gcode->Show(show);
|
return m_btn_export_gcode->Show(show);
|
||||||
}
|
}
|
||||||
bool Sidebar::show_send(bool show) const {
|
bool Sidebar::show_send(bool show) const {
|
||||||
if (this->m_autoslicing_mode) {
|
if (this->m_autoslicing_mode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1131,13 +1174,23 @@ bool Sidebar::show_export_removable(bool show) const {
|
|||||||
}
|
}
|
||||||
return m_btn_export_gcode_removable->Show(show);
|
return m_btn_export_gcode_removable->Show(show);
|
||||||
}
|
}
|
||||||
bool Sidebar::show_connect(bool show) const {
|
bool Sidebar::show_connect(bool show) const {
|
||||||
if (this->m_autoslicing_mode) {
|
if (this->m_autoslicing_mode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return m_btn_connect_gcode->Show(show);
|
return m_btn_connect_gcode->Show(show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sidebar::show_export_all(bool show) const {
|
||||||
|
return m_btn_export_all_gcode->Show(show);
|
||||||
|
};
|
||||||
|
bool Sidebar::show_export_removable_all(bool show) const {
|
||||||
|
return m_btn_export_all_gcode_removable->Show(show);
|
||||||
|
};
|
||||||
|
bool Sidebar::show_connect_all(bool show) const {
|
||||||
|
return m_btn_connect_gcode_all->Show(show);
|
||||||
|
};
|
||||||
|
|
||||||
void Sidebar::switch_to_autoslicing_mode() {
|
void Sidebar::switch_to_autoslicing_mode() {
|
||||||
this->show_sliced_info_sizer(false);
|
this->show_sliced_info_sizer(false);
|
||||||
this->show_btns_sizer(false);
|
this->show_btns_sizer(false);
|
||||||
@ -1150,6 +1203,7 @@ void Sidebar::switch_from_autoslicing_mode() {
|
|||||||
}
|
}
|
||||||
this->m_autoslicing_mode = false;
|
this->m_autoslicing_mode = false;
|
||||||
this->show_sliced_info_sizer(true);
|
this->show_sliced_info_sizer(true);
|
||||||
|
this->show_bulk_btns_sizer(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,12 +76,18 @@ class Sidebar : public wxPanel
|
|||||||
ObjectInfo* m_object_info { nullptr };
|
ObjectInfo* m_object_info { nullptr };
|
||||||
SlicedInfo* m_sliced_info { nullptr };
|
SlicedInfo* m_sliced_info { nullptr };
|
||||||
wxBoxSizer* m_btns_sizer { nullptr };
|
wxBoxSizer* m_btns_sizer { nullptr };
|
||||||
|
wxBoxSizer* m_autoslicing_btns_sizer { nullptr };
|
||||||
|
|
||||||
|
|
||||||
wxButton* m_btn_export_gcode { nullptr };
|
wxButton* m_btn_export_gcode { nullptr };
|
||||||
wxButton* m_btn_reslice { nullptr };
|
wxButton* m_btn_reslice { nullptr };
|
||||||
wxButton* m_btn_connect_gcode { nullptr };
|
wxButton* m_btn_connect_gcode { nullptr };
|
||||||
ScalableButton* m_btn_send_gcode { nullptr };
|
ScalableButton* m_btn_send_gcode { nullptr };
|
||||||
ScalableButton* m_btn_export_gcode_removable{ nullptr }; //exports to removable drives (appears only if removable drive is connected)
|
ScalableButton* m_btn_export_gcode_removable{ nullptr }; //exports to removable drives (appears only if removable drive is connected)
|
||||||
|
//
|
||||||
|
wxButton* m_btn_export_all_gcode { nullptr };
|
||||||
|
wxButton* m_btn_connect_gcode_all { nullptr };
|
||||||
|
ScalableButton* m_btn_export_all_gcode_removable{ nullptr };
|
||||||
|
|
||||||
std::unique_ptr<FreqChangedParams> m_frequently_changed_parameters;
|
std::unique_ptr<FreqChangedParams> m_frequently_changed_parameters;
|
||||||
std::unique_ptr<ObjectManipulation> m_object_manipulation;
|
std::unique_ptr<ObjectManipulation> m_object_manipulation;
|
||||||
@ -120,6 +126,7 @@ public:
|
|||||||
void show_info_sizer();
|
void show_info_sizer();
|
||||||
void show_sliced_info_sizer(const bool show);
|
void show_sliced_info_sizer(const bool show);
|
||||||
void show_btns_sizer(const bool show);
|
void show_btns_sizer(const bool show);
|
||||||
|
void show_bulk_btns_sizer(const bool show);
|
||||||
|
|
||||||
void update_sliced_info_sizer();
|
void update_sliced_info_sizer();
|
||||||
|
|
||||||
@ -131,6 +138,11 @@ public:
|
|||||||
bool show_export_removable(bool show) const;
|
bool show_export_removable(bool show) const;
|
||||||
bool show_connect(bool show) const;
|
bool show_connect(bool show) const;
|
||||||
|
|
||||||
|
void enable_bulk_buttons(bool enable);
|
||||||
|
bool show_export_all(bool show) const;
|
||||||
|
bool show_export_removable_all(bool show) const;
|
||||||
|
bool show_connect_all(bool show) const;
|
||||||
|
|
||||||
void switch_to_autoslicing_mode();
|
void switch_to_autoslicing_mode();
|
||||||
void switch_from_autoslicing_mode();
|
void switch_from_autoslicing_mode();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user