diff --git a/deps/+LibBGCode/LibBGCode.cmake b/deps/+LibBGCode/LibBGCode.cmake index 3403646..ea528b2 100644 --- a/deps/+LibBGCode/LibBGCode.cmake +++ b/deps/+LibBGCode/LibBGCode.cmake @@ -1,8 +1,8 @@ set(LibBGCode_SOURCE_DIR "" CACHE PATH "Optionally specify local LibBGCode source directory") set(_source_dir_line - URL https://github.com/prusa3d/libbgcode/archive/04556c4f64d4b7a5942d8d193d1eb87fc7e1005f.zip - URL_HASH SHA256=f0745b2dae95f0a49ae75bfbe4d775c751499fc4245864675e2dab06c13b2c8f + URL https://github.com/prusa3d/libbgcode/archive/bc390aab4427589a6402b4c7f65cf4d0a8f987ec.zip + URL_HASH SHA256=0c86cb67232089728233014f937e2a07d133a61e31dd8811a9c905e563a49f24 ) if (LibBGCode_SOURCE_DIR) diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index a9f8bcb..08dc752 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -130,6 +130,8 @@ void AppConfig::set_defaults() if (get("auto_toolbar_size").empty()) set("auto_toolbar_size", "100"); + if (get("use_binary_gcode_when_supported").empty()) + set("use_binary_gcode_when_supported", "1"); if (get("notify_release").empty()) set("notify_release", "all"); // or "none" or "release" @@ -746,25 +748,7 @@ bool AppConfig::update_skein_dir(const std::string &dir) return false; // do not save "shapes gallery" directory return this->set("recent", "skein_directory", dir); } -/* -std::string AppConfig::get_last_output_dir(const std::string &alt) const -{ - - const auto it = m_storage.find(""); - if (it != m_storage.end()) { - const auto it2 = it->second.find("last_output_path"); - const auto it3 = it->second.find("remember_output_path"); - if (it2 != it->second.end() && it3 != it->second.end() && ! it2->second.empty() && it3->second == "1") - return it2->second; - } - return alt; -} -void AppConfig::update_last_output_dir(const std::string &dir) -{ - this->set("", "last_output_path", dir); -} -*/ std::string AppConfig::get_last_output_dir(const std::string& alt, const bool removable) const { std::string s1 = (removable ? "last_output_path_removable" : "last_output_path"); diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index c45c1e3..9f5c90f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -753,6 +753,7 @@ namespace DoExport { print_statistics.total_used_filament += used_filament; print_statistics.total_extruded_volume += extruded_volume; print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.; + print_statistics.total_wipe_tower_filament_weight += has_wipe_tower ? (extruded_volume - extruder.extruded_volume()) * extruder.filament_density() * 0.001 : 0.; print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.; } if (!export_binary_data) { @@ -843,7 +844,7 @@ static inline GCode::SmoothPathCache smooth_path_interpolate_global(const Print& void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb) { - const bool export_to_binary_gcode = print.full_print_config().option("gcode_binary")->value; + const bool export_to_binary_gcode = print.full_print_config().option("binary_gcode")->value; // if exporting gcode in binary format: // we generate here the data to be passed to the post-processor, who is responsible to export them to file // 1) generate the thumbnails @@ -1404,6 +1405,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail file.write("\n"); file.write_format(PrintStatistics::TotalFilamentUsedGValueMask.c_str(), print.m_print_statistics.total_weight); file.write_format(PrintStatistics::TotalFilamentCostValueMask.c_str(), print.m_print_statistics.total_cost); + file.write_format(PrintStatistics::TotalFilamentUsedWipeTowerValueMask.c_str(), print.m_print_statistics.total_wipe_tower_filament_weight); if (print.m_print_statistics.total_toolchanges > 0) file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges); file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); @@ -2192,7 +2194,7 @@ LayerResult GCodeGenerator::process_layer( print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config) + "\n"; } - gcode += this->change_layer(previous_layer_z, print_z); // this will increase m_layer_index + gcode += this->change_layer(previous_layer_z, print_z, result.spiral_vase_enable); // this will increase m_layer_index m_layer = &layer; if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) { this->m_previous_layer_distancer = GCode::Impl::get_expolygons_distancer(m_layer->lower_layer->lslices); @@ -2704,7 +2706,11 @@ Polygon Bed::get_inner_offset(const std::vector& shape, const double padd transform(begin(shape), end(shape), back_inserter(shape_scaled), [](const Vec2d& point){ return scaled(point); }); - return shrink({Polygon{shape_scaled}}, scaled(padding)).front(); + Polygons inner_offset{shrink({Polygon{shape_scaled}}, scaled(padding))}; + if (inner_offset.empty()) { + return Polygon{}; + } + return inner_offset.front(); } } @@ -2724,21 +2730,18 @@ std::optional GCodeGenerator::get_helical_layer_change_gcode( const Point n_gon_start_point{this->last_pos()}; - static GCode::Impl::Bed bed{ + GCode::Impl::Bed bed{ this->m_config.bed_shape.values, - circle_radius + circle_radius * 2 }; if (!bed.contains_within_padding(this->point_to_gcode(n_gon_start_point))) { return std::nullopt; } - const Point n_gon_centeroid{ - n_gon_start_point - + scaled(Vec2d{ - (bed.centroid - unscaled(n_gon_start_point)).normalized() - * circle_radius - }) - }; + const Vec2crd n_gon_vector{scaled(Vec2d{ + (bed.centroid - this->point_to_gcode(n_gon_start_point)).normalized() * circle_radius + })}; + const Point n_gon_centeroid{n_gon_start_point + n_gon_vector}; const Polygon n_gon{GCode::Impl::generate_regular_polygon( n_gon_centeroid, @@ -2763,8 +2766,11 @@ std::optional GCodeGenerator::get_helical_layer_change_gcode( } // called by GCodeGenerator::process_layer() -std::string GCodeGenerator::change_layer(coordf_t previous_layer_z, coordf_t print_z) -{ +std::string GCodeGenerator::change_layer( + coordf_t previous_layer_z, + coordf_t print_z, + const bool spiral_vase_enabled +) { std::string gcode; if (m_layer_count > 0) // Increment a progress bar indicator. @@ -2775,14 +2781,16 @@ std::string GCodeGenerator::change_layer(coordf_t previous_layer_z, coordf_t pri const std::string comment{"move to next layer (" + std::to_string(m_layer_index) + ")"}; - bool helical_layer_change{ - (!this->m_spiral_vase || !this->m_spiral_vase->is_enabled()) + bool do_helical_layer_change{ + !spiral_vase_enabled && print_z > previous_layer_z + && EXTRUDER_CONFIG(retract_layer_change) + && EXTRUDER_CONFIG(retract_length) > 0 && EXTRUDER_CONFIG(travel_ramping_lift) && EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90 }; const std::optional helix_gcode{ - helical_layer_change ? + do_helical_layer_change ? this->get_helical_layer_change_gcode( m_config.z_offset.value + previous_layer_z, m_config.z_offset.value + print_z, diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 4e0d8a9..28cdc7b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -351,7 +351,11 @@ private: const coordf_t print_z, const std::string& comment ); - std::string change_layer(coordf_t previous_layer_z, coordf_t print_z); + std::string change_layer( + coordf_t previous_layer_z, + coordf_t print_z, + const bool spiral_vase_enabled + ); std::string extrude_entity(const ExtrusionEntityReference &entity, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_loop(const ExtrusionLoop &loop, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_skirt(const ExtrusionLoop &loop_src, const ExtrusionFlow &extrusion_flow_override, diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 55018ca..0ce3c18 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -568,8 +568,8 @@ GCodeProcessor::GCodeProcessor() void GCodeProcessor::apply_config(const PrintConfig& config) { m_parser.apply_config(config); - m_binarizer.set_enabled(config.gcode_binary); - m_result.is_binary_file = config.gcode_binary; + m_binarizer.set_enabled(config.binary_gcode); + m_result.is_binary_file = config.binary_gcode; m_producer = EProducer::QIDISlicer; m_flavor = config.gcode_flavor; @@ -3687,6 +3687,7 @@ void GCodeProcessor::post_process() filament_total_cost += filament_cost[id]; } + double total_g_wipe_tower = m_print->print_statistics().total_wipe_tower_filament_weight; if (m_binarizer.is_enabled()) { // update print metadata auto stringify = [](const std::vector& values) { @@ -3707,11 +3708,13 @@ void GCodeProcessor::post_process() binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::FilamentCost, stringify(filament_cost)); binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::TotalFilamentUsedG, stringify({ filament_total_g })); binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::TotalFilamentCost, stringify({ filament_total_cost })); + binary_data.print_metadata.raw_data.emplace_back(PrintStatistics::TotalFilamentUsedWipeTower, stringify({ total_g_wipe_tower })); binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedMm, stringify(filament_mm)); // duplicated into print metadata binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedG, stringify(filament_g)); // duplicated into print metadata binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentCost, stringify(filament_cost)); // duplicated into print metadata binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::FilamentUsedCm3, stringify(filament_cm3)); // duplicated into print metadata + binary_data.printer_metadata.raw_data.emplace_back(PrintStatistics::TotalFilamentUsedWipeTower, stringify({ total_g_wipe_tower })); // duplicated into print metadata for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = m_time_processor.machines[i]; diff --git a/src/libslic3r/GCode/SpiralVase.hpp b/src/libslic3r/GCode/SpiralVase.hpp index f8bfa8c..fb461c2 100644 --- a/src/libslic3r/GCode/SpiralVase.hpp +++ b/src/libslic3r/GCode/SpiralVase.hpp @@ -19,9 +19,6 @@ public: m_enabled = en; } - bool is_enabled() const { - return m_enabled; - } std::string process_layer(const std::string &gcode); private: diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 7ea6353..8a9dbc5 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -454,7 +454,7 @@ static std::vector s_Preset_print_options { "support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_branch_diameter_double_wall", "support_tree_top_rate", "support_tree_branch_distance", "support_tree_tip_diameter", "dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius", - "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "gcode_binary","perimeter_extruder", + "extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder", "infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder", "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", @@ -517,7 +517,7 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", "autoemit_temperature_commands", - "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", + "bed_shape", "bed_custom_texture", "bed_custom_model", "binary_gcode", "z_offset", "gcode_flavor", "use_relative_e_distances", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. "host_type", "print_host", "printhost_apikey", "printhost_cafile", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 9502adf..e017dcd 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -64,6 +64,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "bed_temperature", "before_layer_gcode", "between_objects_gcode", + "binary_gcode", "bridge_acceleration", "bridge_fan_speed", //B15 @@ -121,7 +122,6 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "perimeter_acceleration", "post_process", "gcode_substitutions", - "gcode_binary", "printer_notes", "travel_ramping_lift", "travel_initial_part_length", @@ -1588,7 +1588,14 @@ std::string Print::output_filename(const std::string &filename_base) const DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); config.set_key_value("num_extruders", new ConfigOptionInt((int)m_config.nozzle_diameter.size())); config.set_key_value("default_output_extension", new ConfigOptionString(".gcode")); - return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config); + // Handle output_filename_format. There is a hack related to binary G-codes: gcode / bgcode substitution. + std::string output_filename_format = m_config.output_filename_format.value; + if (m_config.binary_gcode && boost::iends_with(output_filename_format, ".gcode")) + output_filename_format.insert(output_filename_format.end()-5, 'b'); + if (! m_config.binary_gcode && boost::iends_with(output_filename_format, ".bgcode")) + output_filename_format.erase(output_filename_format.end()-6); + + return this->PrintBase::output_filename(output_filename_format, ".gcode", filename_base, &config); } const std::string PrintStatistics::FilamentUsedG = "filament used [g]"; @@ -1610,6 +1617,8 @@ const std::string PrintStatistics::FilamentCostMask = "; filament cost ="; const std::string PrintStatistics::TotalFilamentCost = "total filament cost"; const std::string PrintStatistics::TotalFilamentCostMask = "; total filament cost ="; const std::string PrintStatistics::TotalFilamentCostValueMask = "; total filament cost = %.2lf\n"; +const std::string PrintStatistics::TotalFilamentUsedWipeTower = "total filament used for wipe tower [g]"; +const std::string PrintStatistics::TotalFilamentUsedWipeTowerValueMask = "; total filament used for wipe tower [g] = %.2lf\n"; DynamicConfig PrintStatistics::config() const { DynamicConfig config; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 739932e..c60e00f 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -486,6 +486,7 @@ struct PrintStatistics double total_weight; double total_wipe_tower_cost; double total_wipe_tower_filament; + double total_wipe_tower_filament_weight; std::vector printing_extruders; unsigned int initial_extruder_id; std::string initial_filament_type; @@ -507,6 +508,7 @@ struct PrintStatistics total_weight = 0.; total_wipe_tower_cost = 0.; total_wipe_tower_filament = 0.; + total_wipe_tower_filament_weight = 0.; initial_extruder_id = 0; initial_filament_type.clear(); printing_filament_types.clear(); @@ -527,6 +529,8 @@ struct PrintStatistics static const std::string TotalFilamentCost; static const std::string TotalFilamentCostMask; static const std::string TotalFilamentCostValueMask; + static const std::string TotalFilamentUsedWipeTower; + static const std::string TotalFilamentUsedWipeTowerValueMask; }; using PrintObjectPtrs = std::vector; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6447e47..a404943 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1546,11 +1546,6 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionStrings()); - def = this->add("gcode_binary", coBool); - def->label = L("Export as binary G-code"); - def->tooltip = L("Export G-code in binary format."); - def->mode = comExpert; - def->set_default_value(new ConfigOptionBool(0)); def = this->add("high_current_on_filament_swap", coBool); def->label = L("High extruder current on filament swap"); def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange" @@ -1826,6 +1821,12 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(true)); + def = this->add("binary_gcode", coBool); + def->label = L("Supports binary G-code"); + def->tooltip = L("Enable, if the firmware supports binary G-code format (bgcode). " + "To generate .bgcode files, make sure you have binary G-code enabled in Configuration->Preferences->Other."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBool(false)); def = this->add("machine_limits_usage", coEnum); def->label = L("How to apply limits"); def->full_label = L("Purpose of Machine Limits"); @@ -4452,6 +4453,7 @@ static std::set PrintConfigDef_ignore = { "ensure_vertical_shell_thickness", // Disabled in 2.6.0-alpha6, this option is problematic "infill_only_where_needed", + "gcode_binary" // Introduced in 2.7.0-alpha1, removed in 2.7.1 (replaced by binary_gcode). }; void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index c24be44..624ffb9 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -688,6 +688,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, autoemit_temperature_commands)) ((ConfigOptionString, before_layer_gcode)) ((ConfigOptionString, between_objects_gcode)) + ((ConfigOptionBool, binary_gcode)) ((ConfigOptionFloats, deretract_speed)) ((ConfigOptionString, end_gcode)) ((ConfigOptionStrings, end_filament_gcode)) @@ -724,7 +725,6 @@ PRINT_CONFIG_CLASS_DEFINE( // i - case insensitive // w - whole word ((ConfigOptionStrings, gcode_substitutions)) - ((ConfigOptionBool, gcode_binary)) ((ConfigOptionString, layer_gcode)) ((ConfigOptionFloat, max_print_speed)) ((ConfigOptionFloat, max_volumetric_speed)) diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index bbb1a13..fd4bb1e 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -198,9 +198,10 @@ wxString Field::get_tooltip_text(const wxString& default_string) opt_id += "]"; } + bool newline_after_name = boost::iends_with(opt_id, "_gcode") && opt_id != "binary_gcode"; return from_u8(m_opt.tooltip) + "\n" + _L("default value") + "\t: " + - (boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string + - (boost::iends_with(opt_id, "_gcode") ? "" : "\n") + + (newline_after_name ? "\n" : "") + default_string + + (newline_after_name ? "" : "\n") + _L("parameter name") + "\t: " + opt_id; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 929b681..d9a39ed 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2023,7 +2023,7 @@ void GLCanvas3D::render() } #if ENABLE_BINARIZED_GCODE_DEBUG_WINDOW - if (wxGetApp().plater()->is_view3D_shown() && current_printer_technology() != ptSLA && fff_print()->config().gcode_binary) + if (wxGetApp().plater()->is_view3D_shown() && current_printer_technology() != ptSLA && fff_print()->config().binary_gcode) show_binary_gcode_debug_window(); #endif // ENABLE_BINARIZED_GCODE_DEBUG_WINDOW std::string tooltip; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 96f68e2..2d08f9d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -220,7 +220,7 @@ bool GLGizmoSVG::create_volume(std::string_view svg_file, const Vec2d &mouse_pos } bool GLGizmoSVG::is_svg(const ModelVolume &volume) { - return volume.emboss_shape.has_value(); + return volume.emboss_shape.has_value() && volume.emboss_shape->svg_file.has_value(); } bool GLGizmoSVG::is_svg_object(const ModelVolume &volume) { @@ -1174,6 +1174,7 @@ void GLGizmoSVG::set_volume_by_selection() // calculate scale for height and depth inside of scaled object instance calculate_scale(); // must be before calculation of tesselation + // checking that exist is inside of function "is_svg" EmbossShape &es = *volume->emboss_shape; EmbossShape::SvgFile &svg_file = *es.svg_file; if (svg_file.image == nullptr) { diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index 1203d92..9c40fa5 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -264,6 +264,13 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, const std::funct { create(m_content, 84); } +HtmlCapableRichMessageDialog::HtmlCapableRichMessageDialog(wxWindow *parent, + const wxString &msg, + const wxString &caption, + long style, + const std::function &on_link_clicked) + : RichMessageDialogBase(parent, HtmlContent{msg, false, true, on_link_clicked}, caption, style) +{} // WarningDialog WarningDialog::WarningDialog(wxWindow *parent, @@ -289,19 +296,29 @@ MessageDialog::MessageDialog(wxWindow* parent, add_msg_content(this, content_sizer, HtmlContent{ get_wraped_wxString(message) }); finalize(); } +#endif -// RichMessageDialog +// RichMessageDialogBase -RichMessageDialog::RichMessageDialog(wxWindow* parent, +RichMessageDialogBase::RichMessageDialogBase(wxWindow* parent, const wxString& message, const wxString& caption/* = wxEmptyString*/, long style/* = wxOK*/) + : RichMessageDialogBase(parent, HtmlContent{get_wraped_wxString(message)}, caption, style) +{} + +RichMessageDialogBase::RichMessageDialogBase(wxWindow* parent, const HtmlContent& content, const wxString& caption, long style) : MsgDialog(parent, caption.IsEmpty() ? wxString::Format(_L("%s info"), SLIC3R_APP_NAME) : caption, wxEmptyString, style) { - add_msg_content(this, content_sizer, HtmlContent{ get_wraped_wxString(message) }); + m_content = content; // We need a copy for the on_link_clicked lambda. + add_msg_content(this, content_sizer, m_content); +#ifdef _WIN32 // See comment in the header where m_checkBox is defined. m_checkBox = new ::CheckBox(this, m_checkBoxText); +#else + m_checkBox = new wxCheckBox(this, wxID_ANY, m_checkBoxText); +#endif wxGetApp().UpdateDarkUI(m_checkBox); m_checkBox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { m_checkBoxValue = m_checkBox->GetValue(); }); @@ -310,7 +327,7 @@ RichMessageDialog::RichMessageDialog(wxWindow* parent, finalize(); } -int RichMessageDialog::ShowModal() +int RichMessageDialogBase::ShowModal() { if (m_checkBoxText.IsEmpty()) m_checkBox->Hide(); @@ -322,7 +339,6 @@ int RichMessageDialog::ShowModal() return wxDialog::ShowModal(); } -#endif // InfoDialog diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index 308fd92..fbbe40d 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -101,58 +101,31 @@ public: wxString get_wraped_wxString(const wxString& text_in, size_t line_len = 80); -#ifdef _WIN32 -// Generic static line, used intead of wxStaticLine -class StaticLine: public wxTextCtrl -{ -public: - StaticLine( wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxLI_HORIZONTAL, - const wxString& name = wxString::FromAscii(wxTextCtrlNameStr)) - : wxTextCtrl(parent, id, wxEmptyString, pos, size!=wxDefaultSize ? size : (style == wxLI_HORIZONTAL ? wxSize(10, 1) : wxSize(1, 10)), wxSIMPLE_BORDER, wxDefaultValidator, name) - { - this->Enable(false); - } - ~StaticLine() {} -}; - -// Generic message dialog, used intead of wxMessageDialog -class MessageDialog : public MsgDialog -{ -public: - // NOTE! Don't change a signature of contsrucor. It have to be tha same as for wxMessageDialog - MessageDialog( wxWindow *parent, - const wxString& message, - const wxString& caption = wxEmptyString, - long style = wxOK); - MessageDialog(MessageDialog&&) = delete; - MessageDialog(const MessageDialog&) = delete; - MessageDialog &operator=(MessageDialog&&) = delete; - MessageDialog &operator=(const MessageDialog&) = delete; - virtual ~MessageDialog() = default; -}; // Generic rich message dialog, used intead of wxRichMessageDialog -class RichMessageDialog : public MsgDialog +class RichMessageDialogBase : public MsgDialog { +// Using CheckBox causes some weird sizer-related issues on Linux and macOS. To get around the problem before +// we find a better fix, we will fallback to wxCheckBox in this dialog. This makes little difference for most dialogs, +// We currently only use this class as a base for HtmlCapableRichMessageDialog on Linux and macOS. The normal +// RichMessageDialog is just an alias for wxRichMessageDialog on these platforms. +#ifdef _WIN32 CheckBox* m_checkBox{ nullptr }; +#else + wxCheckBox* m_checkBox{ nullptr }; +#endif wxString m_checkBoxText; bool m_checkBoxValue{ false }; public: // NOTE! Don't change a signature of contsrucor. It have to be tha same as for wxRichMessageDialog - RichMessageDialog( wxWindow *parent, - const wxString& message, - const wxString& caption = wxEmptyString, - long style = wxOK); - RichMessageDialog(RichMessageDialog&&) = delete; - RichMessageDialog(const RichMessageDialog&) = delete; - RichMessageDialog &operator=(RichMessageDialog&&) = delete; - RichMessageDialog &operator=(const RichMessageDialog&) = delete; - virtual ~RichMessageDialog() = default; + RichMessageDialogBase(wxWindow* parent, const wxString& message, const wxString& caption = wxEmptyString, long style = wxOK); + RichMessageDialogBase(wxWindow* parent, const HtmlContent& content, const wxString& caption = wxEmptyString, long style = wxOK); + RichMessageDialogBase(RichMessageDialogBase&&) = delete; + RichMessageDialogBase(const RichMessageDialogBase&) = delete; + RichMessageDialogBase &operator=(RichMessageDialogBase&&) = delete; + RichMessageDialogBase &operator=(const RichMessageDialogBase&) = delete; + virtual ~RichMessageDialogBase() = default; int ShowModal() override; @@ -273,7 +246,44 @@ private: m_ok, m_cancel, m_help; + HtmlContent m_content; }; + + +#ifdef _WIN32 +// Generic static line, used intead of wxStaticLine +class StaticLine: public wxTextCtrl +{ +public: + StaticLine( wxWindow* parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxLI_HORIZONTAL, + const wxString& name = wxString::FromAscii(wxTextCtrlNameStr)) + : wxTextCtrl(parent, id, wxEmptyString, pos, size!=wxDefaultSize ? size : (style == wxLI_HORIZONTAL ? wxSize(10, 1) : wxSize(1, 10)), wxSIMPLE_BORDER, wxDefaultValidator, name) + { + this->Enable(false); + } + ~StaticLine() {} +}; + +// Generic message dialog, used intead of wxMessageDialog +class MessageDialog : public MsgDialog +{ +public: + // NOTE! Don't change a signature of contsrucor. It have to be tha same as for wxMessageDialog + MessageDialog(wxWindow *parent, + const wxString& message, + const wxString& caption = wxEmptyString, + long style = wxOK); + MessageDialog(MessageDialog &&) = delete; + MessageDialog(const MessageDialog &) = delete; + MessageDialog &operator=(MessageDialog &&) = delete; + MessageDialog &operator=(const MessageDialog &) = delete; + virtual ~MessageDialog() = default; +}; +using RichMessageDialog = RichMessageDialogBase; #else // just a wrapper for wxStaticLine to use the same code on all platforms class StaticLine : public wxStaticLine @@ -315,6 +325,15 @@ public: }; #endif +class HtmlCapableRichMessageDialog : public RichMessageDialogBase +{ +public: + HtmlCapableRichMessageDialog(wxWindow *parent, const wxString &msg, const wxString& caption, long style, const std::function &on_link_clicked); + ~HtmlCapableRichMessageDialog() {} + +private: + HtmlContent m_content; +}; // Generic info dialog, used for displaying exceptions class InfoDialog : public MsgDialog { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2a7cb2a..47a8ab9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -964,7 +964,7 @@ Sidebar::Sidebar(Plater *parent) enable_buttons(false); - auto *btns_sizer = new wxBoxSizer(wxVERTICAL); + auto *btns_sizer = new wxBoxSizer(wxHORIZONTAL); auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL); complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND); @@ -973,8 +973,8 @@ Sidebar::Sidebar(Plater *parent) // complect_btns_sizer->Add(p->btn_eject_device); - btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5); - btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5); + btns_sizer->Add(p->btn_reslice, 1, wxEXPAND | wxTOP | wxBOTTOM, margin_5); + btns_sizer->Add(complect_btns_sizer, 1, wxEXPAND | wxTOP | wxBOTTOM, margin_5); auto *sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(p->scrolled, 1, wxEXPAND); @@ -3333,6 +3333,10 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // bitmap of enum UpdateBackgroundProcessReturnState unsigned int return_state = 0; + // Get the config ready. The binary gcode flag depends on Preferences, which the backend has no access to. + DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(); + if (full_config.has("binary_gcode")) // needed for SLA + full_config.set("binary_gcode", bool(full_config.opt_bool("binary_gcode") & wxGetApp().app_config->get_bool("use_binary_gcode_when_supported"))); // If the update_background_process() was not called by the timer, kill the timer, // so the update_restart_background_process() will not be called again in vain. background_process_timer.Stop(); @@ -3340,7 +3344,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool update_print_volume_state(); // Apply new config to the possibly running background task. bool was_running = background_process.running(); - Print::ApplyStatus invalidated = background_process.apply(q->model(), wxGetApp().preset_bundle->full_config()); + Print::ApplyStatus invalidated = background_process.apply(q->model(), full_config); // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. if (view3D->is_layers_editing_enabled()) @@ -6642,7 +6646,7 @@ ProjectDropDialog::ProjectDropDialog(const std::string& filename) main_sizer->Add(stb_sizer, 1, wxEXPAND | wxRIGHT | wxLEFT, 10); wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL); - wxCheckBox* check = new wxCheckBox(this, wxID_ANY, _L("Don't show again")); + ::CheckBox* check = new ::CheckBox(this, _L("Don't show again")); check->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& evt) { wxGetApp().app_config->set("show_drop_project_dialog", evt.IsChecked() ? "0" : "1"); }); @@ -7126,14 +7130,14 @@ static wxString check_binary_vs_ascii_gcode_extension(PrinterTechnology pt, cons if (binary_output && ascii_extension) { // TRN The placeholder %1% is the file extension the user has selected. err_out = format_wxstr(_L("Cannot save binary G-code with %1% extension.\n\n" - "Use a different extension or disable binary G-code export " - "in Print Settings."), ext, "output_filename_format;print", "gcode_binary;print"); + "Use a different extension or disable binary G-code export " + "in Printer Settings."), ext, "binary_gcode;printer"); } if (!binary_output && binary_extension) { // TRN The placeholder %1% is the file extension the user has selected. err_out = format_wxstr(_L("Cannot save ASCII G-code with %1% extension.\n\n" - "Use a different extension or enable binary G-code export " - "in Print Settings."), ext, "output_filename_format;print", "gcode_binary;print"); + "Use a different extension or enable binary G-code export " + "in Printer Settings."), ext, "binary_gcode;printer"); } } return err_out; @@ -7157,9 +7161,15 @@ static void alert_when_exporting_binary_gcode(bool binary_output, const std::str const std::string option_key = "dont_warn_about_firmware_version_when_exporting_binary_gcode"; if (app_config->get(option_key) != "1") { - RichMessageDialog dialog(parent, _L("You are exporting binary G-code for a Prusa printer. Please, make sure that your printer " - "is running firmware version 5.1.0-alpha2 or later. Older firmwares are not able to handle binary G-codes."), - _L("Exporting binary G-code"), wxICON_WARNING | wxOK); + const wxString url = "https://qidi.io/binary-gcode"; + HtmlCapableRichMessageDialog dialog(parent, + format_wxstr(_L("You are exporting binary G-code for a QIDI printer. " + "Binary G-code enables significantly faster uploads. " + "Ensure that your printer is running firmware version 5.1.0 or newer, as older versions do not support binary G-codes.\n\n" + "To learn more about binary G-code, visit %1%."), + url), + _L("Warning"), wxOK, + [&url](const std::string&) { wxGetApp().open_browser_with_warning_dialog(url); }); dialog.ShowCheckBox(_L("Don't show again")); if (dialog.ShowModal() == wxID_OK && dialog.IsCheckBoxChecked()) app_config->set(option_key, "1"); @@ -7229,7 +7239,11 @@ void Plater::export_gcode(bool prefer_removable) _L("The following characters are not allowed by a FAT file system:") + " <>:/\\|?*\""; return true; } - err_out = check_binary_vs_ascii_gcode_extension(printer_technology(), ext, wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("gcode_binary")); + 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"); + err_out = check_binary_vs_ascii_gcode_extension(printer_technology(), ext, supports_binary && uses_binary); + } return !err_out.IsEmpty(); }; @@ -7237,8 +7251,10 @@ void Plater::export_gcode(bool prefer_removable) if (check_for_error(output_path, error_str)) { ErrorDialog(this, error_str, [this](const std::string& key) -> void { sidebar().jump_to_option(key); }).ShowModal(); output_path.clear(); - } else { - alert_when_exporting_binary_gcode(wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("gcode_binary"), + } else if (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"); + alert_when_exporting_binary_gcode(supports_binary && uses_binary, wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_notes")); } } @@ -7785,18 +7801,21 @@ void Plater::send_gcode() PrintHostSendDialog dlg(default_output_file, upload_job.printhost->get_post_upload_actions(), groups, storage_paths, storage_names); if (dlg.ShowModal() == wxID_OK) { - { + if (printer_technology() == ptFFF) { const std::string ext = boost::algorithm::to_lower_copy(dlg.filename().extension().string()); - const bool binary_output = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("gcode_binary"); + const bool binary_output = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_bool("binary_gcode") && + wxGetApp().app_config->get_bool("use_binary_gcode_when_supported"); const wxString error_str = check_binary_vs_ascii_gcode_extension(printer_technology(), ext, binary_output); if (! error_str.IsEmpty()) { ErrorDialog(this, error_str, t_kill_focus([](const std::string& key) -> void { wxGetApp().sidebar().jump_to_option(key); })).ShowModal(); return; } + 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"); + alert_when_exporting_binary_gcode(supports_binary && uses_binary, + wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_notes")); } - alert_when_exporting_binary_gcode(wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("gcode_binary"), - wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_string("printer_notes")); upload_job.upload_data.upload_path = dlg.filename(); upload_job.upload_data.post_action = dlg.post_action(); upload_job.upload_data.group = dlg.group(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 3bce1fa..7677abb 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -616,6 +616,10 @@ void PreferencesDialog::build() }; + append_bool_option(m_optgroup_other, "use_binary_gcode_when_supported", L("Use binary G-code when the printer supports it"), + L("If the 'Supports binary G-code' option is enabled in Printer Settings, " + "checking this option will result in the export of G-code in binary format."), + app_config->get_bool("use_binary_gcode_when_supported")); append_bool_option(m_optgroup_other, "suppress_hyperlinks", L("Suppress to open hyperlink in browser"), L("If enabled, QIDISlicer will not open a hyperlinks in your browser."), diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 67f99cd..754f6e2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1698,34 +1698,8 @@ void TabPrint::build() Option option = optgroup->get_option("output_filename_format"); option.opt.full_width = true; optgroup->append_single_option_line(option); - optgroup->append_single_option_line("gcode_binary"); - optgroup->m_on_change = [this](const t_config_option_key& opt_key, boost::any value) - { - if (opt_key == "gcode_binary") { - const bool is_binary = m_config->opt_bool("gcode_binary"); - std::string output_filename_format = m_config->opt_string("output_filename_format"); - bool modified = false; - if (is_binary && boost::iends_with(output_filename_format, ".gcode")) { - output_filename_format = output_filename_format.substr(0, output_filename_format.length() - 5) + "bgcode"; - modified = true; - } - else if (!is_binary && boost::iends_with(output_filename_format, ".bgcode")) { - output_filename_format = output_filename_format.substr(0, output_filename_format.length() - 6) + "gcode"; - modified = true; - } - if (modified) { - DynamicPrintConfig new_conf = *m_config; - auto off_option = static_cast(m_config->option("output_filename_format")->clone()); - off_option->value = output_filename_format; - new_conf.set_key_value("output_filename_format", off_option); - load_config(new_conf); - } - } - update_dirty(); - update(); - }; optgroup = page->new_optgroup(L("Other")); @@ -2752,6 +2726,7 @@ void TabPrinter::build_fff() optgroup->append_single_option_line("silent_mode"); optgroup->append_single_option_line("remaining_times"); + optgroup->append_single_option_line("binary_gcode"); optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { wxTheApp->CallAfter([this, opt_key, value]() { diff --git a/t/layers.t b/t/layers.t index fef9445..6065d78 100644 --- a/t/layers.t +++ b/t/layers.t @@ -62,7 +62,7 @@ use Slic3r::Test qw(_eq); { my $config = Slic3r::Config->new; $config->set('fill_density', 0); # just for making the test faster - $config->set('gcode_binary', 0); + $config->set('binary_gcode', 0); my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2); my @z = ();