mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-21 21:58:03 -06:00
Fixed conflicts after merge with master
This commit is contained in:
commit
cc0688678c
51 changed files with 7369 additions and 6120 deletions
|
@ -804,6 +804,10 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height")));
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min(2) = -1e10;
|
||||
print_volume.min(0) -= BedEpsilon;
|
||||
print_volume.min(1) -= BedEpsilon;
|
||||
print_volume.max(0) += BedEpsilon;
|
||||
print_volume.max(1) += BedEpsilon;
|
||||
|
||||
ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside;
|
||||
|
||||
|
|
|
@ -611,6 +611,8 @@ struct _3DScene
|
|||
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
|
||||
};
|
||||
|
||||
static constexpr float BedEpsilon = EPSILON;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -68,9 +68,10 @@ bool SlicingProcessCompletedEvent::invalidate_plater() const
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string SlicingProcessCompletedEvent::format_error_message() const
|
||||
std::pair<std::string, bool> SlicingProcessCompletedEvent::format_error_message() const
|
||||
{
|
||||
std::string error;
|
||||
bool monospace = false;
|
||||
try {
|
||||
this->rethrow_exception();
|
||||
} catch (const std::bad_alloc& ex) {
|
||||
|
@ -78,12 +79,15 @@ std::string SlicingProcessCompletedEvent::format_error_message() const
|
|||
"If you are sure you have enough RAM on your system, this may also be a bug and we would "
|
||||
"be glad if you reported it."))) % SLIC3R_APP_NAME).str());
|
||||
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
|
||||
} catch (PlaceholderParserError &ex) {
|
||||
error = ex.what();
|
||||
monospace = true;
|
||||
} catch (std::exception &ex) {
|
||||
error = ex.what();
|
||||
} catch (...) {
|
||||
error = "Unknown C++ exception.";
|
||||
}
|
||||
return error;
|
||||
return std::make_pair(std::move(error), monospace);
|
||||
}
|
||||
|
||||
BackgroundSlicingProcess::BackgroundSlicingProcess()
|
||||
|
@ -149,30 +153,37 @@ void BackgroundSlicingProcess::process_fff()
|
|||
// 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 error_message;
|
||||
int copy_ret_val = copy_file(m_temp_output_path, export_path, error_message, m_export_path_on_removable_media);
|
||||
int copy_ret_val = CopyFileResult::SUCCESS;
|
||||
try
|
||||
{
|
||||
copy_ret_val = copy_file(m_temp_output_path, export_path, error_message, m_export_path_on_removable_media);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
}
|
||||
switch (copy_ret_val) {
|
||||
case SUCCESS: break; // no error
|
||||
case FAIL_COPY_FILE:
|
||||
case CopyFileResult::SUCCESS: break; // no error
|
||||
case CopyFileResult::FAIL_COPY_FILE:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
|
||||
break;
|
||||
case FAIL_FILES_DIFFERENT:
|
||||
case CopyFileResult::FAIL_FILES_DIFFERENT:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
|
||||
break;
|
||||
case FAIL_RENAMING:
|
||||
case CopyFileResult::FAIL_RENAMING:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
|
||||
break;
|
||||
case FAIL_CHECK_ORIGIN_NOT_OPENED:
|
||||
case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
|
||||
break;
|
||||
case FAIL_CHECK_TARGET_NOT_OPENED:
|
||||
case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
|
||||
break;
|
||||
default:
|
||||
throw Slic3r::RuntimeError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
|
||||
break;
|
||||
}
|
||||
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
|
|
|
@ -57,7 +57,8 @@ public:
|
|||
// Only valid if error()
|
||||
void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); }
|
||||
// Produce a human readable message to be displayed by a notification or a message box.
|
||||
std::string format_error_message() const;
|
||||
// 2nd parameter defines whether the output should be displayed with a monospace font.
|
||||
std::pair<std::string, bool> format_error_message() const;
|
||||
|
||||
private:
|
||||
StatusType m_status;
|
||||
|
|
|
@ -1095,23 +1095,48 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
|
|||
|
||||
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
||||
|
||||
static GLCanvas3D::ArrangeSettings load_arrange_settings()
|
||||
void GLCanvas3D::load_arrange_settings()
|
||||
{
|
||||
GLCanvas3D::ArrangeSettings settings;
|
||||
std::string dist_fff_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance_fff");
|
||||
|
||||
std::string dist_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance");
|
||||
std::string dist_fff_seq_print_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance_fff_seq_print");
|
||||
|
||||
std::string en_rot_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation");
|
||||
std::string dist_sla_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance_sla");
|
||||
|
||||
if (!dist_str.empty())
|
||||
settings.distance = std::stof(dist_str);
|
||||
std::string en_rot_fff_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation_fff");
|
||||
|
||||
if (!en_rot_str.empty())
|
||||
settings.enable_rotation = (en_rot_str == "1" || en_rot_str == "yes");
|
||||
std::string en_rot_fff_seqp_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation_fff_seq_print");
|
||||
|
||||
return settings;
|
||||
std::string en_rot_sla_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation_sla");
|
||||
|
||||
if (!dist_fff_str.empty())
|
||||
m_arrange_settings_fff.distance = std::stof(dist_fff_str);
|
||||
|
||||
if (!dist_fff_seq_print_str.empty())
|
||||
m_arrange_settings_fff_seq_print.distance = std::stof(dist_fff_seq_print_str);
|
||||
|
||||
if (!dist_sla_str.empty())
|
||||
m_arrange_settings_sla.distance = std::stof(dist_sla_str);
|
||||
|
||||
if (!en_rot_fff_str.empty())
|
||||
m_arrange_settings_fff.enable_rotation = (en_rot_fff_str == "1" || en_rot_fff_str == "yes");
|
||||
|
||||
if (!en_rot_fff_seqp_str.empty())
|
||||
m_arrange_settings_fff_seq_print.enable_rotation = (en_rot_fff_seqp_str == "1" || en_rot_fff_seqp_str == "yes");
|
||||
|
||||
if (!en_rot_sla_str.empty())
|
||||
m_arrange_settings_sla.enable_rotation = (en_rot_sla_str == "1" || en_rot_sla_str == "yes");
|
||||
}
|
||||
|
||||
PrinterTechnology GLCanvas3D::current_printer_technology() const
|
||||
{
|
||||
return m_process->current_printer_technology();
|
||||
}
|
||||
|
||||
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
||||
|
@ -1156,7 +1181,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
|||
#endif // ENABLE_RETINA_GL
|
||||
}
|
||||
|
||||
m_arrange_settings = load_arrange_settings();
|
||||
load_arrange_settings();
|
||||
|
||||
m_selection.set_volumes(&m_volumes.volumes);
|
||||
}
|
||||
|
@ -2554,7 +2579,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
|
||||
break;
|
||||
case WXK_ESCAPE: { deselect_all(); break; }
|
||||
case WXK_F5: { post_event(SimpleEvent(EVT_GLCANVAS_RELOAD_FROM_DISK)); break; }
|
||||
case WXK_F5:
|
||||
{
|
||||
if ((wxGetApp().is_editor() && !wxGetApp().plater()->model().objects.empty()) ||
|
||||
(wxGetApp().is_gcode_viewer() && !wxGetApp().plater()->get_last_loaded_gcode().empty()))
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_RELOAD_FROM_DISK));
|
||||
break;
|
||||
}
|
||||
case '0': { select_view("iso"); break; }
|
||||
case '1': { select_view("top"); break; }
|
||||
case '2': { select_view("bottom"); break; }
|
||||
|
@ -3921,37 +3952,60 @@ bool GLCanvas3D::_render_arrange_menu(float pos_x)
|
|||
imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
|
||||
|
||||
imgui->begin(_L("Arrange options"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
ArrangeSettings settings = m_arrange_settings;
|
||||
|
||||
ArrangeSettings settings = get_arrange_settings();
|
||||
ArrangeSettings &settings_out = get_arrange_settings();
|
||||
|
||||
auto &appcfg = wxGetApp().app_config;
|
||||
PrinterTechnology ptech = m_process->current_printer_technology();
|
||||
|
||||
bool settings_changed = false;
|
||||
float dist_min = 0.f;
|
||||
std::string dist_key = "min_object_distance", rot_key = "enable_rotation";
|
||||
std::string postfix;
|
||||
|
||||
if (ImGui::DragFloat(_L("Gal size").ToUTF8().data(), &settings.distance, .01f, 0.0f, 100.0f, "%5.2f")) {
|
||||
m_arrange_settings.distance = settings.distance;
|
||||
if (ptech == ptSLA) {
|
||||
dist_min = 0.f;
|
||||
postfix = "_sla";
|
||||
} else if (ptech == ptFFF) {
|
||||
auto co_opt = m_config->option<ConfigOptionBool>("complete_objects");
|
||||
if (co_opt && co_opt->value) {
|
||||
dist_min = float(min_object_distance(*m_config));
|
||||
postfix = "_fff_seq_print";
|
||||
} else {
|
||||
dist_min = 0.f;
|
||||
postfix = "_fff";
|
||||
}
|
||||
}
|
||||
|
||||
dist_key += postfix;
|
||||
rot_key += postfix;
|
||||
|
||||
imgui->text(_L("Use CTRL+left mouse key to enter text edit mode:"));
|
||||
|
||||
if (imgui->slider_float(_L("Clearance size"), &settings.distance, dist_min, 100.0f, "%5.2f") || dist_min > settings.distance) {
|
||||
settings.distance = std::max(dist_min, settings.distance);
|
||||
settings_out.distance = settings.distance;
|
||||
appcfg->set("arrange", dist_key.c_str(), std::to_string(settings_out.distance));
|
||||
settings_changed = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _L("Use CTRL+Left mouse button to enter text edit mode.\nUse SHIFT key to increase stepping.").ToUTF8().data());
|
||||
|
||||
if (imgui->checkbox(_L("Enable rotations (slow)"), settings.enable_rotation)) {
|
||||
m_arrange_settings.enable_rotation = settings.enable_rotation;
|
||||
settings_out.enable_rotation = settings.enable_rotation;
|
||||
appcfg->set("arrange", rot_key.c_str(), settings_out.enable_rotation? "1" : "0");
|
||||
settings_changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (imgui->button(_L("Reset"))) {
|
||||
m_arrange_settings = ArrangeSettings{};
|
||||
settings_out = ArrangeSettings{};
|
||||
settings_out.distance = std::max(dist_min, settings_out.distance);
|
||||
appcfg->set("arrange", dist_key.c_str(), std::to_string(settings_out.distance));
|
||||
appcfg->set("arrange", rot_key.c_str(), settings_out.enable_rotation? "1" : "0");
|
||||
settings_changed = true;
|
||||
}
|
||||
|
||||
if (settings_changed) {
|
||||
appcfg->set("arrange", "min_object_distance", std::to_string(m_arrange_settings.distance));
|
||||
appcfg->set("arrange", "enable_rotation", m_arrange_settings.enable_rotation? "1" : "0");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (imgui->button(_L("Arrange"))) {
|
||||
|
@ -4943,7 +4997,7 @@ void GLCanvas3D::_render_objects() const
|
|||
|
||||
if (m_config != nullptr) {
|
||||
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||
m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height"));
|
||||
m_volumes.set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
||||
m_volumes.check_outside_state(m_config, nullptr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -387,9 +387,11 @@ public:
|
|||
|
||||
struct ArrangeSettings
|
||||
{
|
||||
float distance = 6.;
|
||||
float accuracy = 0.65f;
|
||||
bool enable_rotation = false;
|
||||
float distance = 6.;
|
||||
// float distance_seq_print = 6.; // Used when sequential print is ON
|
||||
// float distance_sla = 6.;
|
||||
float accuracy = 0.65f; // Unused currently
|
||||
bool enable_rotation = false;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -463,7 +465,35 @@ private:
|
|||
mutable bool m_tooltip_enabled{ true };
|
||||
Slope m_slope;
|
||||
|
||||
ArrangeSettings m_arrange_settings;
|
||||
ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla,
|
||||
m_arrange_settings_fff_seq_print;
|
||||
|
||||
PrinterTechnology current_printer_technology() const;
|
||||
|
||||
template<class Self>
|
||||
static auto & get_arrange_settings(Self *self)
|
||||
{
|
||||
PrinterTechnology ptech = self->current_printer_technology();
|
||||
|
||||
auto *ptr = &self->m_arrange_settings_fff;
|
||||
|
||||
if (ptech == ptSLA) {
|
||||
ptr = &self->m_arrange_settings_sla;
|
||||
} else if (ptech == ptFFF) {
|
||||
auto co_opt = self->m_config->template option<ConfigOptionBool>("complete_objects");
|
||||
if (co_opt && co_opt->value) {
|
||||
ptr = &self->m_arrange_settings_fff_seq_print;
|
||||
} else {
|
||||
ptr = &self->m_arrange_settings_fff;
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
ArrangeSettings &get_arrange_settings() { return get_arrange_settings(this); }
|
||||
|
||||
void load_arrange_settings();
|
||||
|
||||
public:
|
||||
explicit GLCanvas3D(wxGLCanvas* canvas);
|
||||
|
@ -684,7 +714,17 @@ public:
|
|||
void use_slope(bool use) { m_slope.use(use); }
|
||||
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
|
||||
|
||||
const ArrangeSettings& get_arrange_settings() const { return m_arrange_settings; }
|
||||
ArrangeSettings get_arrange_settings() const
|
||||
{
|
||||
const ArrangeSettings &settings = get_arrange_settings(this);
|
||||
ArrangeSettings ret = settings;
|
||||
if (&settings == &m_arrange_settings_fff_seq_print) {
|
||||
ret.distance = std::max(ret.distance,
|
||||
float(min_object_distance(*m_config)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _is_shown_on_screen() const;
|
||||
|
|
|
@ -221,16 +221,16 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
|||
}
|
||||
}
|
||||
|
||||
void show_error(wxWindow* parent, const wxString& message)
|
||||
void show_error(wxWindow* parent, const wxString& message, bool monospaced_font)
|
||||
{
|
||||
ErrorDialog msg(parent, message);
|
||||
ErrorDialog msg(parent, message, monospaced_font);
|
||||
msg.ShowModal();
|
||||
}
|
||||
|
||||
void show_error(wxWindow* parent, const char* message)
|
||||
void show_error(wxWindow* parent, const char* message, bool monospaced_font)
|
||||
{
|
||||
assert(message);
|
||||
show_error(parent, wxString::FromUTF8(message));
|
||||
show_error(parent, wxString::FromUTF8(message), monospaced_font);
|
||||
}
|
||||
|
||||
void show_error_id(int id, const std::string& message)
|
||||
|
|
|
@ -39,9 +39,11 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
|
|||
// Change option value in config
|
||||
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
|
||||
|
||||
void show_error(wxWindow* parent, const wxString& message);
|
||||
void show_error(wxWindow* parent, const char* message);
|
||||
inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); }
|
||||
// If monospaced_font is true, the error message is displayed using html <code><pre></pre></code> tags,
|
||||
// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
|
||||
void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false);
|
||||
void show_error(wxWindow* parent, const char* message, bool monospaced_font = false);
|
||||
inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); }
|
||||
void show_error_id(int id, const std::string& message); // For Perl
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
|
||||
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
|
||||
|
|
|
@ -1710,11 +1710,12 @@ bool GUI_App::checked_tab(Tab* tab)
|
|||
}
|
||||
|
||||
// Update UI / Tabs to reflect changes in the currently loaded presets
|
||||
void GUI_App::load_current_presets()
|
||||
void GUI_App::load_current_presets(bool check_printer_presets_ /*= true*/)
|
||||
{
|
||||
// check printer_presets for the containing information about "Print Host upload"
|
||||
// and create physical printer from it, if any exists
|
||||
check_printer_presets();
|
||||
if (check_printer_presets_)
|
||||
check_printer_presets();
|
||||
|
||||
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
this->plater()->set_printer_technology(printer_technology);
|
||||
|
@ -1872,6 +1873,7 @@ wxString GUI_App::current_language_code_safe() const
|
|||
{ "pl", "pl_PL", },
|
||||
{ "uk", "uk_UA", },
|
||||
{ "zh", "zh_CN", },
|
||||
{ "ru", "ru_RU", },
|
||||
};
|
||||
wxString language_code = this->current_language_code().BeforeFirst('_');
|
||||
auto it = mapping.find(language_code);
|
||||
|
|
|
@ -206,7 +206,7 @@ public:
|
|||
void add_config_menu(wxMenuBar *menu);
|
||||
bool check_unsaved_changes(const wxString &header = wxString());
|
||||
bool checked_tab(Tab* tab);
|
||||
void load_current_presets();
|
||||
void load_current_presets(bool check_printer_presets = true);
|
||||
|
||||
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
|
||||
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
|
||||
|
|
|
@ -1007,7 +1007,7 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
|||
const std::string& opt_key,
|
||||
int axis) :
|
||||
wxTextCtrl(parent->parent(), wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxSize(5*int(wxGetApp().em_unit()), wxDefaultCoord), wxTE_PROCESS_ENTER),
|
||||
wxSize((wxOSX ? 5 : 6)*int(wxGetApp().em_unit()), wxDefaultCoord), wxTE_PROCESS_ENTER),
|
||||
m_opt_key(opt_key),
|
||||
m_axis(axis)
|
||||
{
|
||||
|
|
|
@ -169,27 +169,11 @@ void View3D::render()
|
|||
Preview::Preview(
|
||||
wxWindow* parent, Model* model, DynamicPrintConfig* config,
|
||||
BackgroundSlicingProcess* process, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process_func)
|
||||
: m_canvas_widget(nullptr)
|
||||
, m_canvas(nullptr)
|
||||
, m_left_sizer(nullptr)
|
||||
, m_layers_slider_sizer(nullptr)
|
||||
, m_bottom_toolbar_panel(nullptr)
|
||||
, m_label_view_type(nullptr)
|
||||
, m_choice_view_type(nullptr)
|
||||
, m_label_show(nullptr)
|
||||
, m_combochecklist_features(nullptr)
|
||||
, m_combochecklist_features_pos(0)
|
||||
, m_combochecklist_options(nullptr)
|
||||
, m_config(config)
|
||||
: m_config(config)
|
||||
, m_process(process)
|
||||
, m_gcode_result(gcode_result)
|
||||
, m_number_extruders(1)
|
||||
, m_preferred_color_mode("feature")
|
||||
, m_loaded(false)
|
||||
, m_schedule_background_process(schedule_background_process_func)
|
||||
#ifdef __linux__
|
||||
, m_volumes_cleanup_required(false)
|
||||
#endif // __linux__
|
||||
{
|
||||
if (init(parent, model))
|
||||
load_print();
|
||||
|
|
|
@ -76,17 +76,17 @@ private:
|
|||
|
||||
class Preview : public wxPanel
|
||||
{
|
||||
wxGLCanvas* m_canvas_widget;
|
||||
GLCanvas3D* m_canvas;
|
||||
wxBoxSizer* m_left_sizer;
|
||||
wxBoxSizer* m_layers_slider_sizer;
|
||||
wxPanel* m_bottom_toolbar_panel;
|
||||
wxStaticText* m_label_view_type;
|
||||
wxChoice* m_choice_view_type;
|
||||
wxStaticText* m_label_show;
|
||||
wxComboCtrl* m_combochecklist_features;
|
||||
size_t m_combochecklist_features_pos;
|
||||
wxComboCtrl* m_combochecklist_options;
|
||||
wxGLCanvas* m_canvas_widget { nullptr };
|
||||
GLCanvas3D* m_canvas { nullptr };
|
||||
wxBoxSizer* m_left_sizer { nullptr };
|
||||
wxBoxSizer* m_layers_slider_sizer { nullptr };
|
||||
wxPanel* m_bottom_toolbar_panel { nullptr };
|
||||
wxStaticText* m_label_view_type { nullptr };
|
||||
wxChoice* m_choice_view_type { nullptr };
|
||||
wxStaticText* m_label_show { nullptr };
|
||||
wxComboCtrl* m_combochecklist_features { nullptr };
|
||||
size_t m_combochecklist_features_pos { 0 };
|
||||
wxComboCtrl* m_combochecklist_options { nullptr };
|
||||
|
||||
DynamicPrintConfig* m_config;
|
||||
BackgroundSlicingProcess* m_process;
|
||||
|
@ -95,16 +95,16 @@ class Preview : public wxPanel
|
|||
#ifdef __linux__
|
||||
// We are getting mysterious crashes on Linux in gtk due to OpenGL context activation GH #1874 #1955.
|
||||
// So we are applying a workaround here.
|
||||
bool m_volumes_cleanup_required;
|
||||
bool m_volumes_cleanup_required { false };
|
||||
#endif /* __linux__ */
|
||||
|
||||
// Calling this function object forces Plater::schedule_background_process.
|
||||
std::function<void()> m_schedule_background_process;
|
||||
|
||||
unsigned int m_number_extruders;
|
||||
unsigned int m_number_extruders { 1 };
|
||||
std::string m_preferred_color_mode;
|
||||
|
||||
bool m_loaded;
|
||||
bool m_loaded { false };
|
||||
|
||||
DoubleSlider::Control* m_layers_slider{ nullptr };
|
||||
DoubleSlider::Control* m_moves_slider{ nullptr };
|
||||
|
|
|
@ -624,7 +624,7 @@ static bool selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|||
}
|
||||
|
||||
// mark a label with a ImGui::ColorMarkerHovered, if item is hovered
|
||||
char* marked_label = new char[255];
|
||||
char* marked_label = new char[512]; //255 symbols is not enough for translated string (e.t. to Russian)
|
||||
if (hovered)
|
||||
sprintf(marked_label, "%c%s", ImGui::ColorMarkerHovered, label);
|
||||
else
|
||||
|
|
|
@ -145,12 +145,13 @@ void ArrangeJob::process()
|
|||
{
|
||||
static const auto arrangestr = _(L("Arranging"));
|
||||
|
||||
GLCanvas3D::ArrangeSettings settings =
|
||||
m_plater->canvas3D()->get_arrange_settings();
|
||||
|
||||
const GLCanvas3D::ArrangeSettings &settings =
|
||||
static_cast<const GLCanvas3D*>(m_plater->canvas3D())->get_arrange_settings();
|
||||
|
||||
arrangement::ArrangeParams params;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
params.allow_rotations = settings.enable_rotation;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
|
||||
|
||||
auto count = unsigned(m_selected.size() + m_unprintable.size());
|
||||
Points bedpts = get_bed_shape(*m_plater->config());
|
||||
|
|
|
@ -29,7 +29,9 @@ void FillBedJob::prepare()
|
|||
for (ModelInstance *inst : model_object->instances)
|
||||
if (inst->printable) {
|
||||
ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
|
||||
++ap.priority; // need to be included in the result
|
||||
// Existing objects need to be included in the result. Only
|
||||
// the needed amount of object will be added, no more.
|
||||
++ap.priority;
|
||||
m_selected.emplace_back(ap);
|
||||
}
|
||||
|
||||
|
@ -38,11 +40,18 @@ void FillBedJob::prepare()
|
|||
m_bedpts = get_bed_shape(*m_plater->config());
|
||||
|
||||
auto &objects = m_plater->model().objects;
|
||||
BoundingBox bedbb = get_extents(m_bedpts);
|
||||
|
||||
for (size_t idx = 0; idx < objects.size(); ++idx)
|
||||
if (int(idx) != m_object_idx)
|
||||
for (ModelInstance *mi : objects[idx]->instances) {
|
||||
m_unselected.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
|
||||
m_unselected.back().bed_idx = 0;
|
||||
ArrangePolygon ap = get_arrange_poly(PtrWrapper{mi}, m_plater);
|
||||
auto ap_bb = ap.transformed_poly().contour.bounding_box();
|
||||
|
||||
if (ap.bed_idx == 0 && !bedbb.contains(ap_bb))
|
||||
ap.bed_idx = arrangement::UNARRANGED;
|
||||
|
||||
m_unselected.emplace_back(ap);
|
||||
}
|
||||
|
||||
if (auto wt = get_wipe_tower_arrangepoly(*m_plater))
|
||||
|
@ -55,18 +64,17 @@ void FillBedJob::prepare()
|
|||
double unsel_area = std::accumulate(m_unselected.begin(),
|
||||
m_unselected.end(), 0.,
|
||||
[](double s, const auto &ap) {
|
||||
return s + ap.poly.area();
|
||||
return s + (ap.bed_idx == 0) * ap.poly.area();
|
||||
}) / sc;
|
||||
|
||||
double fixed_area = unsel_area + m_selected.size() * poly_area;
|
||||
double bed_area = Polygon{m_bedpts}.area() / sc;
|
||||
|
||||
// This is the maximum range, the real number will always be close but less.
|
||||
double bed_area = Polygon{m_bedpts}.area() / sc;
|
||||
|
||||
m_status_range = (bed_area - fixed_area) / poly_area;
|
||||
// This is the maximum number of items, the real number will always be close but less.
|
||||
int needed_items = (bed_area - fixed_area) / poly_area;
|
||||
|
||||
ModelInstance *mi = model_object->instances[0];
|
||||
for (int i = 0; i < m_status_range; ++i) {
|
||||
for (int i = 0; i < needed_items; ++i) {
|
||||
ArrangePolygon ap;
|
||||
ap.poly = m_selected.front().poly;
|
||||
ap.bed_idx = arrangement::UNARRANGED;
|
||||
|
@ -77,18 +85,28 @@ void FillBedJob::prepare()
|
|||
};
|
||||
m_selected.emplace_back(ap);
|
||||
}
|
||||
|
||||
m_status_range = m_selected.size();
|
||||
|
||||
// The strides have to be removed from the fixed items. For the
|
||||
// arrangeable (selected) items bed_idx is ignored and the
|
||||
// translation is irrelevant.
|
||||
double stride = bed_stride(m_plater);
|
||||
for (auto &p : m_unselected)
|
||||
if (p.bed_idx > 0)
|
||||
p.translation(X) -= p.bed_idx * stride;
|
||||
}
|
||||
|
||||
void FillBedJob::process()
|
||||
{
|
||||
if (m_object_idx == -1 || m_selected.empty()) return;
|
||||
|
||||
GLCanvas3D::ArrangeSettings settings =
|
||||
m_plater->canvas3D()->get_arrange_settings();
|
||||
const GLCanvas3D::ArrangeSettings &settings =
|
||||
static_cast<const GLCanvas3D*>(m_plater->canvas3D())->get_arrange_settings();
|
||||
|
||||
arrangement::ArrangeParams params;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
params.allow_rotations = settings.enable_rotation;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
|
||||
bool do_stop = false;
|
||||
params.stopcondition = [this, &do_stop]() {
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "format.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <string_view>
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -84,6 +86,31 @@ public:
|
|||
};
|
||||
#endif // __APPLE__
|
||||
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
static wxIcon main_frame_icon(GUI_App::EAppMode app_mode)
|
||||
{
|
||||
#if _WIN32
|
||||
std::wstring path(size_t(MAX_PATH), wchar_t(0));
|
||||
int len = int(::GetModuleFileName(nullptr, path.data(), MAX_PATH));
|
||||
if (len > 0 && len < MAX_PATH) {
|
||||
path.erase(path.begin() + len, path.end());
|
||||
if (app_mode == GUI_App::EAppMode::GCodeViewer) {
|
||||
// Only in case the slicer was started with --gcodeviewer parameter try to load the icon from prusa-gcodeviewer.exe
|
||||
// Otherwise load it from the exe.
|
||||
for (const std::wstring_view exe_name : { std::wstring_view(L"prusa-slicer.exe"), std::wstring_view(L"prusa-slicer-console.exe") })
|
||||
if (boost::iends_with(path, exe_name)) {
|
||||
path.erase(path.end() - exe_name.size(), path.end());
|
||||
path += L"prusa-gcodeviewer.exe";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxIcon(path, wxBITMAP_TYPE_ICO);
|
||||
#else // _WIN32
|
||||
return wxIcon(Slic3r::var(app_mode == GUI_App::EAppMode::Editor ? "PrusaSlicer_128px.png" : "PrusaSlicer-gcodeviewer_128px.png"), wxBITMAP_TYPE_PNG);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
MainFrame::MainFrame() :
|
||||
DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
|
||||
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
|
||||
|
@ -115,35 +142,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
#endif // __APPLE__
|
||||
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
#if _WIN32
|
||||
{
|
||||
wxString src_path;
|
||||
wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &src_path, nullptr, nullptr, wxPATH_NATIVE);
|
||||
switch (wxGetApp().get_app_mode()) {
|
||||
default:
|
||||
case GUI_App::EAppMode::Editor: { src_path += "\\prusa-slicer.exe"; break; }
|
||||
case GUI_App::EAppMode::GCodeViewer: { src_path += "\\prusa-gcodeviewer.exe"; break; }
|
||||
}
|
||||
wxIconLocation icon_location;
|
||||
icon_location.SetFileName(src_path);
|
||||
SetIcon(icon_location);
|
||||
}
|
||||
#else
|
||||
switch (wxGetApp().get_app_mode())
|
||||
{
|
||||
default:
|
||||
case GUI_App::EAppMode::Editor:
|
||||
{
|
||||
SetIcon(wxIcon(Slic3r::var("PrusaSlicer_128px.png"), wxBITMAP_TYPE_PNG));
|
||||
break;
|
||||
}
|
||||
case GUI_App::EAppMode::GCodeViewer:
|
||||
{
|
||||
SetIcon(wxIcon(Slic3r::var("PrusaSlicer-gcodeviewer_128px.png"), wxBITMAP_TYPE_PNG));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
SetIcon(main_frame_icon(wxGetApp().get_app_mode()));
|
||||
|
||||
// initialize status bar
|
||||
m_statusbar = std::make_shared<ProgressStatusBar>(this);
|
||||
|
@ -1243,6 +1242,9 @@ void MainFrame::init_menubar_as_gcodeviewer()
|
|||
append_menu_item(fileMenu, wxID_ANY, _L("&Open G-code") + dots + "\tCtrl+O", _L("Open a G-code file"),
|
||||
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->load_gcode(); }, "open", nullptr,
|
||||
[this]() {return m_plater != nullptr; }, this);
|
||||
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from disk") + sep + "F5",
|
||||
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
|
||||
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
|
||||
fileMenu->AppendSeparator();
|
||||
append_menu_item(fileMenu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
|
||||
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
|
||||
|
|
|
@ -64,12 +64,9 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
|
|||
SetSizerAndFit(topsizer);
|
||||
}
|
||||
|
||||
MsgDialog::~MsgDialog() {}
|
||||
|
||||
|
||||
// ErrorDialog
|
||||
|
||||
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
||||
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_font)
|
||||
: MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_NAME),
|
||||
wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_NAME),
|
||||
wxID_NONE)
|
||||
|
@ -78,19 +75,23 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
|||
// Text shown as HTML, so that mouse selection and Ctrl-V to copy will work.
|
||||
wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
|
||||
{
|
||||
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1));
|
||||
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), monospaced_font ? 30 * wxGetApp().em_unit() : -1));
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
wxFont monospace = wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT);
|
||||
wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
|
||||
auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
|
||||
const int font_size = font.GetPointSize()-1;
|
||||
int size[] = {font_size, font_size, font_size, font_size, font_size, font_size, font_size};
|
||||
html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
|
||||
html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size);
|
||||
html->SetBorders(2);
|
||||
std::string msg_escaped = xml_escape(msg.ToUTF8().data());
|
||||
boost::replace_all(msg_escaped, "\r\n", "<br>");
|
||||
boost::replace_all(msg_escaped, "\n", "<br>");
|
||||
if (monospaced_font)
|
||||
// Code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
|
||||
msg_escaped = std::string("<pre><code>") + msg_escaped + "</code></pre>";
|
||||
html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>");
|
||||
content_sizer->Add(html, 1, wxEXPAND);
|
||||
}
|
||||
|
@ -99,15 +100,12 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
|||
btn_ok->SetFocus();
|
||||
btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING);
|
||||
|
||||
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192));
|
||||
// Use a small bitmap with monospaced font, as the error text will not be wrapped.
|
||||
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, monospaced_font ? 48 : 192));
|
||||
|
||||
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
|
||||
Fit();
|
||||
}
|
||||
|
||||
ErrorDialog::~ErrorDialog() {}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ struct MsgDialog : wxDialog
|
|||
MsgDialog(const MsgDialog &) = delete;
|
||||
MsgDialog &operator=(MsgDialog &&) = delete;
|
||||
MsgDialog &operator=(const MsgDialog &) = delete;
|
||||
virtual ~MsgDialog();
|
||||
virtual ~MsgDialog() = default;
|
||||
|
||||
// TODO: refactor with CreateStdDialogButtonSizer usage
|
||||
|
||||
|
@ -52,12 +52,14 @@ protected:
|
|||
class ErrorDialog : public MsgDialog
|
||||
{
|
||||
public:
|
||||
ErrorDialog(wxWindow *parent, const wxString &msg);
|
||||
// If monospaced_font is true, the error message is displayed using html <code><pre></pre></code> tags,
|
||||
// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
|
||||
ErrorDialog(wxWindow *parent, const wxString &msg, bool courier_font);
|
||||
ErrorDialog(ErrorDialog &&) = delete;
|
||||
ErrorDialog(const ErrorDialog &) = delete;
|
||||
ErrorDialog &operator=(ErrorDialog &&) = delete;
|
||||
ErrorDialog &operator=(const ErrorDialog &) = delete;
|
||||
virtual ~ErrorDialog();
|
||||
virtual ~ErrorDialog() = default;
|
||||
|
||||
private:
|
||||
wxString msg;
|
||||
|
|
|
@ -387,7 +387,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
|||
|
||||
option = m_og->get_option("fill_density");
|
||||
option.opt.label = L("Infill");
|
||||
option.opt.width = 7/*6*/;
|
||||
option.opt.width = 8;
|
||||
option.opt.sidetext = " ";
|
||||
line.append_option(option);
|
||||
|
||||
|
@ -2002,9 +2002,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
sidebar->Bind(EVT_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); });
|
||||
}
|
||||
|
||||
wxGLCanvas* view3D_canvas = view3D->get_wxglcanvas();
|
||||
wxGLCanvas* view3D_canvas = view3D->get_wxglcanvas();
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
if (wxGetApp().is_editor()) {
|
||||
// 3DScene events:
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this);
|
||||
|
@ -2046,8 +2046,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
|
||||
}
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [q](SimpleEvent&) { q->set_bed_shape(); });
|
||||
}
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [q](SimpleEvent&) { q->set_bed_shape(); });
|
||||
|
||||
// Preview events:
|
||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
|
||||
|
@ -2064,6 +2064,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_LAYERS_SLIDER, [this](wxKeyEvent& evt) { preview->move_layers_slider(evt); });
|
||||
#endif // ENABLE_ARROW_KEYS_WITH_SLIDERS
|
||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_layers_slider(evt); });
|
||||
if (wxGetApp().is_gcode_viewer())
|
||||
preview->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { this->q->reload_gcode_from_disk(); });
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
q->Bind(EVT_SLICING_COMPLETED, &priv::on_slicing_completed, this);
|
||||
|
@ -2363,7 +2365,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
|
||||
if (printer_technology == ptFFF)
|
||||
CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, &wxGetApp().preset_bundle->project_config);
|
||||
wxGetApp().load_current_presets();
|
||||
// For exporting from the amf/3mf we shouldn't check printer_presets for the containing information about "Print Host upload"
|
||||
wxGetApp().load_current_presets(false);
|
||||
is_project_file = true;
|
||||
}
|
||||
wxGetApp().app_config->update_config_dir(path.parent_path().string());
|
||||
|
@ -3640,19 +3643,20 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
|
||||
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||
this->background_process.reset_export();
|
||||
|
||||
// This bool stops showing export finished notification even when process_completed_with_error is false
|
||||
bool has_error = false;
|
||||
if (evt.error()) {
|
||||
std::string message = evt.format_error_message();
|
||||
std::pair<std::string, bool> message = evt.format_error_message();
|
||||
if (evt.critical_error()) {
|
||||
if (q->m_tracking_popup_menu)
|
||||
// We don't want to pop-up a message box when tracking a pop-up menu.
|
||||
// We postpone the error message instead.
|
||||
q->m_tracking_popup_menu_error_message = message;
|
||||
q->m_tracking_popup_menu_error_message = message.first;
|
||||
else
|
||||
show_error(q, message);
|
||||
show_error(q, message.first, message.second);
|
||||
} else
|
||||
notification_manager->push_slicing_error_notification(message);
|
||||
this->statusbar()->set_status_text(from_u8(message));
|
||||
notification_manager->push_slicing_error_notification(message.first);
|
||||
this->statusbar()->set_status_text(from_u8(message.first));
|
||||
if (evt.invalidate_plater())
|
||||
{
|
||||
const wxString invalid_str = _L("Invalid data");
|
||||
|
@ -3660,7 +3664,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
sidebar->set_btn_label(btn, invalid_str);
|
||||
process_completed_with_error = true;
|
||||
}
|
||||
|
||||
has_error = true;
|
||||
}
|
||||
if (evt.cancelled())
|
||||
this->statusbar()->set_status_text(_L("Cancelled"));
|
||||
|
@ -3695,11 +3699,11 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
show_action_buttons(false);
|
||||
}
|
||||
// If writing to removable drive was scheduled, show notification with eject button
|
||||
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !this->process_completed_with_error) {
|
||||
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
|
||||
show_action_buttons(false);
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
|
||||
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
|
||||
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !this->process_completed_with_error)
|
||||
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
|
||||
}
|
||||
exporting_status = ExportingStatus::NOT_EXPORTING;
|
||||
|
@ -4805,6 +4809,13 @@ void Plater::load_gcode(const wxString& filename)
|
|||
set_project_filename(filename);
|
||||
}
|
||||
|
||||
void Plater::reload_gcode_from_disk()
|
||||
{
|
||||
wxString filename(m_last_loaded_gcode);
|
||||
m_last_loaded_gcode.clear();
|
||||
load_gcode(filename);
|
||||
}
|
||||
|
||||
void Plater::refresh_print()
|
||||
{
|
||||
p->preview->refresh_print();
|
||||
|
@ -5215,9 +5226,12 @@ void Plater::export_gcode(bool prefer_removable)
|
|||
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 std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
} 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;
|
||||
}
|
||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||
|
@ -5575,9 +5589,12 @@ void Plater::send_gcode()
|
|||
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 std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
} 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;
|
||||
}
|
||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||
|
|
|
@ -144,6 +144,7 @@ public:
|
|||
void extract_config_from_project();
|
||||
void load_gcode();
|
||||
void load_gcode(const wxString& filename);
|
||||
void reload_gcode_from_disk();
|
||||
void refresh_print();
|
||||
|
||||
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
|
||||
|
@ -154,6 +155,8 @@ public:
|
|||
bool load_files(const wxArrayString& filenames);
|
||||
#endif // ENABLE_DRAG_AND_DROP_FIX
|
||||
|
||||
const wxString& get_last_loaded_gcode() const { return m_last_loaded_gcode; }
|
||||
|
||||
void update();
|
||||
void stop_jobs();
|
||||
void select_view(const std::string& direction);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <glob.h>
|
||||
#include <pwd.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/process.hpp>
|
||||
#endif
|
||||
|
@ -187,8 +188,9 @@ namespace search_for_drives_internal
|
|||
//if not same file system - could be removable drive
|
||||
if (! compare_filesystem_id(path, parent_path)) {
|
||||
//free space
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path);
|
||||
if (si.available != 0) {
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path, ec);
|
||||
if (!ec && si.available != 0) {
|
||||
//user id
|
||||
struct stat buf;
|
||||
stat(path.c_str(), &buf);
|
||||
|
|
|
@ -133,7 +133,7 @@ void SavePresetDialog::Item::update()
|
|||
if (existing->is_compatible)
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str());
|
||||
else
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is imcopatible with selected printer.")) % m_preset_name).str());
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incopatible with selected printer.")) % m_preset_name).str());
|
||||
info_line += "\n" + _L("Note: This preset will be replaced after saving");
|
||||
m_valid_type = Warning;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
|
|||
options.emplace_back(Option{ boost::nowide::widen(opt_key), type,
|
||||
(label + suffix).ToStdWstring(), (_(label) + suffix_local).ToStdWstring(),
|
||||
gc.group.ToStdWstring(), _(gc.group).ToStdWstring(),
|
||||
gc.category.ToStdWstring(), _(gc.category).ToStdWstring() });
|
||||
gc.category.ToStdWstring(), GUI::Tab::translate_category(gc.category, type).ToStdWstring() });
|
||||
};
|
||||
|
||||
for (std::string opt_key : config->keys())
|
||||
|
|
|
@ -432,6 +432,17 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str
|
|||
return page;
|
||||
}
|
||||
|
||||
// Names of categories is save in English always. We translate them only for UI.
|
||||
// But category "Extruder n" can't be translated regularly (using _()), so
|
||||
// just for this category we should splite the title and translate "Extruder" word separately
|
||||
wxString Tab::translate_category(const wxString& title, Preset::Type preset_type)
|
||||
{
|
||||
if (preset_type == Preset::TYPE_PRINTER && title.Contains("Extruder ")) {
|
||||
return _("Extruder") + title.SubString(8, title.Last());
|
||||
}
|
||||
return _(title);
|
||||
}
|
||||
|
||||
void Tab::OnActivate()
|
||||
{
|
||||
wxWindowUpdateLocker noUpdates(this);
|
||||
|
@ -509,7 +520,7 @@ void Tab::update_labels_colour()
|
|||
auto title = m_treectrl->GetItemText(cur_item);
|
||||
for (auto page : m_pages)
|
||||
{
|
||||
if (_(page->title()) != title)
|
||||
if (translate_category(page->title(), m_type) != title)
|
||||
continue;
|
||||
|
||||
const wxColor *clr = !page->m_is_nonsys_values ? &m_sys_label_clr :
|
||||
|
@ -736,7 +747,7 @@ void Tab::update_changed_tree_ui()
|
|||
auto title = m_treectrl->GetItemText(cur_item);
|
||||
for (auto page : m_pages)
|
||||
{
|
||||
if (_(page->title()) != title)
|
||||
if (translate_category(page->title(), m_type) != title)
|
||||
continue;
|
||||
bool sys_page = true;
|
||||
bool modified_page = false;
|
||||
|
@ -1132,7 +1143,7 @@ void Tab::update_wiping_button_visibility() {
|
|||
|
||||
void Tab::activate_option(const std::string& opt_key, const wxString& category)
|
||||
{
|
||||
wxString page_title = _(category);
|
||||
wxString page_title = translate_category(category, m_type);
|
||||
|
||||
auto cur_item = m_treectrl->GetFirstVisibleItem();
|
||||
if (!cur_item || !m_treectrl->IsVisible(cur_item))
|
||||
|
@ -1803,7 +1814,6 @@ void TabFilament::build()
|
|||
on_value_change(opt_key, value);
|
||||
};
|
||||
|
||||
// optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8));
|
||||
optgroup = page->new_optgroup(L("Temperature"));
|
||||
Line line = { L("Nozzle"), "" };
|
||||
line.append_option(optgroup->get_option("first_layer_temperature"));
|
||||
|
@ -2515,7 +2525,7 @@ void TabPrinter::build_unregular_pages()
|
|||
// Build missed extruder pages
|
||||
for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) {
|
||||
//# build page
|
||||
const wxString& page_name = wxString::Format(L("Extruder %d"), int(extruder_idx + 1));
|
||||
const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1));
|
||||
auto page = add_options_page(page_name, "funnel", true);
|
||||
m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page);
|
||||
|
||||
|
@ -2947,7 +2957,7 @@ void Tab::rebuild_page_tree()
|
|||
{
|
||||
if (!p->get_show())
|
||||
continue;
|
||||
auto itemId = m_treectrl->AppendItem(rootItem, _(p->title()), p->iconID());
|
||||
auto itemId = m_treectrl->AppendItem(rootItem, translate_category(p->title(), m_type), p->iconID());
|
||||
m_treectrl->SetItemTextColour(itemId, p->get_item_colour());
|
||||
if (p->title() == selected)
|
||||
item = itemId;
|
||||
|
@ -3286,7 +3296,7 @@ bool Tab::tree_sel_change_delayed()
|
|||
const auto sel_item = m_treectrl->GetSelection();
|
||||
const auto selection = sel_item ? m_treectrl->GetItemText(sel_item) : "";
|
||||
for (auto p : m_pages)
|
||||
if (_(p->title()) == selection)
|
||||
if (translate_category(p->title(), m_type) == selection)
|
||||
{
|
||||
page = p.get();
|
||||
m_is_nonsys_values = page->m_is_nonsys_values;
|
||||
|
|
|
@ -309,6 +309,7 @@ public:
|
|||
void on_roll_back_value(const bool to_sys = false);
|
||||
|
||||
PageShp add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages = false);
|
||||
static wxString translate_category(const wxString& title, Preset::Type preset_type);
|
||||
|
||||
virtual void OnActivate();
|
||||
virtual void on_preset_loaded() {}
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
#include "Plater.hpp"
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
|
||||
#ifndef __WXGTK__// msw_menuitem_bitmaps is used for MSW and OSX
|
||||
#ifdef __linux__
|
||||
#define wxLinux true
|
||||
#else
|
||||
#define wxLinux false
|
||||
// msw_menuitem_bitmaps is used for MSW and OSX
|
||||
static std::map<int, std::string> msw_menuitem_bitmaps;
|
||||
#ifdef __WXMSW__
|
||||
void msw_rescale_menu(wxMenu* menu)
|
||||
|
@ -653,7 +657,7 @@ void ModeButton::focus_button(const bool focus)
|
|||
Slic3r::GUI::wxGetApp().normal_font();
|
||||
|
||||
SetFont(new_font);
|
||||
SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_BTNSHADOW));
|
||||
SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : wxLinux ? wxSYS_COLOUR_GRAYTEXT : wxSYS_COLOUR_BTNSHADOW));
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue