mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge remote-tracking branch 'remote/master' into SoftFever
# Conflicts: # resources/profiles/BBL/filament/Bambu PC @BBL X1C.json # resources/profiles/BBL/filament/Bambu TPU 95A @BBL X1C.json
This commit is contained in:
		
						commit
						b806df7710
					
				
					 269 changed files with 10330 additions and 32230 deletions
				
			
		|  | @ -1220,7 +1220,7 @@ int CLI::run(int argc, char **argv) | |||
| 
 | ||||
|         for (int i = 0; i < plate_data_list.size(); i++) { | ||||
|             PlateData *plate_data = plate_data_list[i]; | ||||
|             for (auto it = plate_data->slice_flaments_info.begin(); it != plate_data->slice_flaments_info.end(); it++) { | ||||
|             for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) { | ||||
|                 it->type  = filament_types?filament_types->get_at(it->id):"PLA"; | ||||
|                 it->color = filament_color?filament_color->get_at(it->id):"#FFFFFF"; | ||||
|                 //it->filament_id = filament_id?filament_id->get_at(it->id):"unknown";
 | ||||
|  | @ -1729,7 +1729,7 @@ extern "C" { | |||
|             argv_ptrs[i] = argv_narrow[i].data(); | ||||
| 
 | ||||
| //BBS: register default exception handler
 | ||||
| #if BBL_RELEASE_TO_PUBLIC | ||||
| #if 1 | ||||
|         SET_DEFULTER_HANDLER(); | ||||
| #else | ||||
|         AddVectoredExceptionHandler(1, CBaseException::UnhandledExceptionFilter); | ||||
|  |  | |||
|  | @ -164,9 +164,8 @@ namespace ImGui | |||
|     const wchar_t HeightRangeIcon          = 0x0813; | ||||
|     const wchar_t FoldButtonIcon           = 0x0814; | ||||
|     const wchar_t UnfoldButtonIcon         = 0x0815; | ||||
|     const wchar_t GcodePauseIcon           = 0x0816; | ||||
|     const wchar_t SphereButtonIcon         = 0x0817; | ||||
|     const wchar_t FragmentFilterIcon       = 0x0818; | ||||
|     const wchar_t SphereButtonIcon         = 0x0816; | ||||
|     const wchar_t FragmentFilterIcon       = 0x0817; | ||||
| 
 | ||||
| //    void MyFunction(const char* name, const MyMatrix44& v);
 | ||||
| } | ||||
|  |  | |||
|  | @ -4117,7 +4117,7 @@ bool ImGui::BBLInputScalar(const char *label, ImGuiDataType data_type, void *p_d | |||
| 
 | ||||
|     if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; | ||||
| 
 | ||||
|     char buf[16]; | ||||
|     char buf[8]; | ||||
|     DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); | ||||
| 
 | ||||
|     bool value_changed = false; | ||||
|  | @ -6235,7 +6235,11 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl | |||
|         if (g.Style.FrameBorderSize > 0.0f) | ||||
|             RenderFrameBorder(bb.Min, bb.Max, rounding); | ||||
|         else | ||||
|         #ifdef __APPLE__ | ||||
|             window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding,NULL,2.0f); // Color button are often in need of some sort of border
 | ||||
|         #else | ||||
|             window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
 | ||||
|         #endif | ||||
|     } | ||||
| 
 | ||||
|     // Drag and Drop Source
 | ||||
|  |  | |||
|  | @ -256,9 +256,15 @@ void AppConfig::set_defaults() | |||
|         set("backup_interval", "10"); | ||||
|     } | ||||
| 
 | ||||
| #if BBL_RELEASE_TO_PUBLIC | ||||
|     if (get("iot_environment").empty()) { | ||||
|         set("iot_environment", "3"); | ||||
|     } | ||||
| #else | ||||
|     if (get("iot_environment").empty()) { | ||||
|         set("iot_environment", "1"); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     // Remove legacy window positions/sizes
 | ||||
|     erase("app", "main_frame_maximized"); | ||||
|  | @ -1003,12 +1009,7 @@ std::string AppConfig::get_region() | |||
| std::string AppConfig::get_country_code() | ||||
| { | ||||
|     std::string region = get_region(); | ||||
|     /* fix PRE environment when release to public */ | ||||
| #if 0 | ||||
|     this->set("iot_environment", "2"); | ||||
|     return "ENV_CN_PRE"; | ||||
| #else | ||||
|     //if (is_engineering_region()) { return region; }
 | ||||
|     if (is_engineering_region()) { return region; } | ||||
|     if (region == "CHN" || region == "China") | ||||
|         return "CN"; | ||||
|     else if (region == "USA") | ||||
|  | @ -1022,7 +1023,7 @@ std::string AppConfig::get_country_code() | |||
|     else | ||||
|         return "Others"; | ||||
|     return ""; | ||||
| #endif | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool AppConfig::is_engineering_region(){ | ||||
|  |  | |||
|  | @ -762,40 +762,7 @@ bool compSecondMoment(const ExPolygons& expolys, double& smExpolysX, double& smE | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // BBS: thermal length is calculated according to the material of a volume
 | ||||
| double getThermalLength(const ModelVolume* modelVolumePtr) { | ||||
|     double thermalLength = 200.; | ||||
|     auto aa = modelVolumePtr->extruder_id(); | ||||
|     if (Model::extruderParamsMap.find(aa) != Model::extruderParamsMap.end()) { | ||||
|         if (Model::extruderParamsMap.at(aa).materialName == "ABS" || | ||||
|             Model::extruderParamsMap.at(aa).materialName == "PA-CF" || | ||||
|             Model::extruderParamsMap.at(aa).materialName == "PET-CF") { | ||||
|             thermalLength = 100; | ||||
|         } | ||||
|         if (Model::extruderParamsMap.at(aa).materialName == "PC") { | ||||
|             thermalLength = 40; | ||||
|         } | ||||
|         if (Model::extruderParamsMap.at(aa).materialName == "TPU") { | ||||
|             thermalLength = 1000; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|     return thermalLength; | ||||
| } | ||||
| 
 | ||||
| // BBS: thermal length calculation for a group of volumes
 | ||||
| double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs) | ||||
| { | ||||
|     double thermalLength = 1250.; | ||||
| 
 | ||||
|     for (const auto& modelVolumePtr : modelVolumePtrs) { | ||||
|         if (modelVolumePtr != nullptr) { | ||||
|             // the thermal length of a group is decided by the volume with shortest thermal length
 | ||||
|             thermalLength = std::min(thermalLength, getThermalLength(modelVolumePtr)); | ||||
|         } | ||||
|     } | ||||
|     return thermalLength; | ||||
| } | ||||
| 
 | ||||
| //BBS: config brimwidth by volumes
 | ||||
| double configBrimWidthByVolumes(double deltaT, double adhension, double maxSpeed, const ModelVolume* modelVolumePtr, const ExPolygons& expolys) | ||||
|  | @ -825,7 +792,7 @@ double configBrimWidthByVolumes(double deltaT, double adhension, double maxSpeed | |||
|     const double& bboxX = bbox2.size()(0); | ||||
|     const double& bboxY = bbox2.size()(1); | ||||
|     double thermalLength = sqrt(bboxX * bboxX + bboxY * bboxY) * SCALING_FACTOR; | ||||
|     double thermalLengthRef = getThermalLength(modelVolumePtr); | ||||
|     double thermalLengthRef = Model::getThermalLength(modelVolumePtr); | ||||
| 
 | ||||
|     double height_to_area = std::max(height / Ixx * (bbox2.size()(1) * SCALING_FACTOR), height / Iyy * (bbox2.size()(0) * SCALING_FACTOR)); | ||||
|     double brim_width = adhension * std::min(std::min(std::max(height_to_area * maxSpeed / 24, thermalLength * 8. / thermalLengthRef * std::min(height, 30.) / 30.), 18.), 1.5 * thermalLength); | ||||
|  | @ -846,8 +813,12 @@ double configBrimWidthByVolumeGroups(double adhension, double maxSpeed, const st | |||
|     BoundingBoxf3 mergedBbx; | ||||
|     for (const auto& modelVolumePtr : modelVolumePtrs) { | ||||
|         if (modelVolumePtr->is_model_part()) { | ||||
|             auto rawBoundingbox = modelVolumePtr->mesh().transformed_bounding_box(modelVolumePtr->get_matrix()); | ||||
|             auto bbox = modelVolumePtr->get_object()->instances.front()->transform_bounding_box(rawBoundingbox); | ||||
|             Slic3r::Transform3d t; | ||||
|             if (modelVolumePtr->get_object()->instances.size() > 0) | ||||
|                 t = modelVolumePtr->get_object()->instances.front()->get_matrix() * modelVolumePtr->get_matrix(); | ||||
|             else | ||||
|                 t = modelVolumePtr->get_matrix(); | ||||
|             auto bbox = modelVolumePtr->mesh().transformed_bounding_box(t); | ||||
|             mergedBbx.merge(bbox); | ||||
|         } | ||||
|     } | ||||
|  | @ -870,7 +841,7 @@ double configBrimWidthByVolumeGroups(double adhension, double maxSpeed, const st | |||
|     const double& bboxX = bbox2.size()(0); | ||||
|     const double& bboxY = bbox2.size()(1); | ||||
|     double thermalLength = sqrt(bboxX * bboxX + bboxY * bboxY) * SCALING_FACTOR; | ||||
|     double thermalLengthRef = getThermalLength(modelVolumePtrs); | ||||
|     double thermalLengthRef = Model::getThermalLength(modelVolumePtrs); | ||||
| 
 | ||||
|     double height_to_area = std::max(height / Ixx * (bbox2.size()(1) * SCALING_FACTOR), height / Iyy * (bbox2.size()(0) * SCALING_FACTOR)); | ||||
|     double brim_width = adhension * std::min(std::min(std::max(height_to_area * maxSpeed / 24, thermalLength * 8. / thermalLengthRef * std::min(height, 30.) / 30.), 18.), 1.5 * thermalLength); | ||||
|  | @ -884,26 +855,13 @@ double configBrimWidthByVolumeGroups(double adhension, double maxSpeed, const st | |||
| } | ||||
| 
 | ||||
| //BBS: create all brims
 | ||||
| static ExPolygons outer_inner_brim_area(const Print& print, const ConstPrintObjectPtrs& top_level_objects_with_brim, | ||||
| static ExPolygons outer_inner_brim_area(const Print& print, | ||||
|     const float no_brim_offset, std::map<ObjectID, ExPolygons>& brimAreaMap, | ||||
|     std::map<ObjectID, ExPolygons>& supportBrimAreaMap, | ||||
|     std::vector<std::pair<ObjectID, unsigned int>>& objPrintVec, | ||||
|     std::vector<unsigned int>& printExtruders) | ||||
| { | ||||
|     std::unordered_set<size_t> top_level_objects_idx; | ||||
|     top_level_objects_idx.reserve(top_level_objects_with_brim.size()); | ||||
|     for (const PrintObject* object : top_level_objects_with_brim) | ||||
|         top_level_objects_idx.insert(object->id().id); | ||||
| 
 | ||||
|     unsigned int support_material_extruder = printExtruders.front() + 1; | ||||
|     auto allExtruders = print.extruders(); | ||||
|     if (print.has_support_material()) { | ||||
|         assert(top_level_objects_with_brim.front()->config().support_filament >= 0); | ||||
|         if (top_level_objects_with_brim.front()->config().support_filament > 0) | ||||
|             support_material_extruder = top_level_objects_with_brim.front()->config().support_filament; | ||||
|         allExtruders.push_back(support_material_extruder - 1); | ||||
|         sort_remove_duplicates(allExtruders); | ||||
|     } | ||||
| 
 | ||||
|     ExPolygons brim_area; | ||||
|     ExPolygons no_brim_area; | ||||
|  | @ -927,7 +885,6 @@ static ExPolygons outer_inner_brim_area(const Print& print, const ConstPrintObje | |||
|             float              brim_offset = scale_(object->config().brim_object_gap.value); | ||||
|             double             flowWidth = print.brim_flow().scaled_spacing() * SCALING_FACTOR; | ||||
|             float              brim_width = scale_(floor(object->config().brim_width.value / flowWidth / 2) * flowWidth * 2); | ||||
|             const bool         top_outer_brim = top_level_objects_idx.find(object->id().id) != top_level_objects_idx.end(); | ||||
|             const float        scaled_flow_width = print.brim_flow().scaled_spacing(); | ||||
|             const float        scaled_additional_brim_width = scale_(floor(5 / flowWidth / 2) * flowWidth * 2); | ||||
|             const float        scaled_half_min_adh_length = scale_(1.1); | ||||
|  | @ -1017,8 +974,13 @@ static ExPolygons outer_inner_brim_area(const Print& print, const ConstPrintObje | |||
|                 if (brimAreaMap.find(object->id()) != brimAreaMap.end()) | ||||
|                     expolygons_append(brim_area, brimAreaMap[object->id()]); | ||||
|             } | ||||
|             if ((print.config().print_sequence == PrintSequence::ByObject) && top_level_objects_with_brim.front()->config().support_filament == 0) | ||||
|                 support_material_extruder = objectWithExtruder.second; | ||||
|             support_material_extruder = object->config().support_filament; | ||||
|             if (support_material_extruder == 0 && object->has_support_material()) { | ||||
|                 if (print.config().print_sequence == PrintSequence::ByObject) | ||||
|                     support_material_extruder = objectWithExtruder.second; | ||||
|                 else | ||||
|                     support_material_extruder = printExtruders.front() + 1; | ||||
|             } | ||||
|             if (support_material_extruder == extruderNo && brimToWrite.at(object->id()).sup) { | ||||
|                 if (!object->support_layers().empty()) { | ||||
|                     for (const Polygon& support_contour : object->support_layers().front()->support_fills.polygons_covered_by_spacing()) { | ||||
|  | @ -1658,10 +1620,7 @@ void make_brim(const Print& print, PrintTryCancel try_cancel, Polygons& islands_ | |||
|     std::map<ObjectID, ExPolygons> supportBrimAreaMap; | ||||
|     Flow                 flow = print.brim_flow(); | ||||
|     const auto           scaled_resolution = scaled<double>(print.config().resolution.value); | ||||
|     std::vector<ExPolygons> bottom_layers_expolygons = get_print_bottom_layers_expolygons(print); | ||||
|     ConstPrintObjectPtrs    top_level_objects_with_brim = get_top_level_objects_with_brim(print, bottom_layers_expolygons); | ||||
|     Polygons                islands = top_level_outer_brim_islands(top_level_objects_with_brim, scaled_resolution); | ||||
|     ExPolygons           islands_area_ex = outer_inner_brim_area(print, top_level_objects_with_brim, | ||||
|     ExPolygons           islands_area_ex = outer_inner_brim_area(print, | ||||
|         float(flow.scaled_spacing()), brimAreaMap, supportBrimAreaMap, objPrintVec, printExtruders); | ||||
| 
 | ||||
|     // BBS: Find boundingbox of the first layer
 | ||||
|  |  | |||
|  | @ -122,8 +122,6 @@ set(lisbslic3r_sources | |||
|     GCode/SpiralVase.hpp | ||||
|     GCode/SeamPlacer.cpp | ||||
|     GCode/SeamPlacer.hpp | ||||
|     GCode/SpeedGenerator.cpp | ||||
|     GCode/SpeedGenerator.hpp | ||||
|     GCode/ToolOrdering.cpp | ||||
|     GCode/ToolOrdering.hpp | ||||
|     GCode/WipeTower.cpp | ||||
|  | @ -317,6 +315,12 @@ set(lisbslic3r_sources | |||
|     SLA/ReprojectPointsOnMesh.hpp | ||||
| ) | ||||
| 
 | ||||
| if (APPLE) | ||||
|     list(APPEND lisbslic3r_sources | ||||
| 			MacUtils.mm | ||||
|         ) | ||||
| endif () | ||||
| 
 | ||||
| add_library(libslic3r STATIC ${lisbslic3r_sources}  | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h" | ||||
|     ${OpenVDBUtils_SOURCES}) | ||||
|  |  | |||
|  | @ -4,6 +4,9 @@ | |||
| #include <cassert> | ||||
| #include "Geometry.hpp" | ||||
| 
 | ||||
| 
 | ||||
| //BBS: Refer to ArcWelderLib for the arc fitting functions
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| //BBS: threshold used to judge collineation
 | ||||
|  |  | |||
|  | @ -127,6 +127,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer) | |||
| 	std::vector<std::vector<const SurfaceFillParams*>> 	region_to_surface_params(layer.regions().size(), std::vector<const SurfaceFillParams*>()); | ||||
|     SurfaceFillParams									params; | ||||
|     bool 												has_internal_voids = false; | ||||
| 	const PrintObjectConfig&							object_config = layer.object()->config(); | ||||
| 	for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) { | ||||
| 		const LayerRegion  &layerm = *layer.regions()[region_id]; | ||||
| 		region_to_surface_params[region_id].assign(layerm.fill_surfaces.size(), nullptr); | ||||
|  | @ -163,7 +164,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer) | |||
| 		        params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern); | ||||
| 				params.flow   = params.bridge ? | ||||
| 					//BBS: always enable thick bridge for internal bridge
 | ||||
| 					layerm.bridging_flow(extrusion_role, (surface.is_bridge() && !surface.is_external()) || g_config_thick_bridges) : | ||||
| 					layerm.bridging_flow(extrusion_role, (surface.is_bridge() && !surface.is_external()) || object_config.thick_bridges) : | ||||
| 					layerm.flow(extrusion_role, (surface.thickness == -1) ? layer.height : surface.thickness); | ||||
| 
 | ||||
| 				// Calculate flow spacing for infill pattern generation.
 | ||||
|  |  | |||
|  | @ -80,9 +80,8 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface* surface, cons | |||
| 
 | ||||
|             ThickPolylines polylines; | ||||
|             for (ExPolygon& ex : gaps_ex_sorted) { | ||||
|                 //BBS: medial axis algorithm can't handle duplicated points in expolygon.
 | ||||
|                 //Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|                 ex.douglas_peucker(SCALED_RESOLUTION); | ||||
|                 //BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|                 ex.douglas_peucker(SCALED_RESOLUTION * 0.1); | ||||
|                 ex.medial_axis(max, min, &polylines); | ||||
|             } | ||||
| 
 | ||||
|  | @ -114,9 +113,8 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface* surface, cons | |||
| 
 | ||||
|         ThickPolylines polylines; | ||||
|         for (ExPolygon& ex : external_gaps_collapsed) { | ||||
|             //BBS: medial axis algorithm can't handle duplicated points in expolygon.
 | ||||
|             //Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|             ex.douglas_peucker(SCALED_RESOLUTION); | ||||
|             //BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|             ex.douglas_peucker(SCALED_RESOLUTION * 0.1); | ||||
|             ex.medial_axis(max, min, &polylines); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3156,7 +3156,7 @@ void FillMonotonicLineWGapFill::fill_surface_extrusion(const Surface* surface, c | |||
|         ThickPolylines polylines; | ||||
|         for (ExPolygon& ex : gaps_ex_sorted) { | ||||
|             //BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|             ex.douglas_peucker(SCALED_RESOLUTION); | ||||
|             ex.douglas_peucker(SCALED_RESOLUTION * 0.1); | ||||
|             ex.medial_axis(max, min, &polylines); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -232,6 +232,7 @@ static constexpr const char* LOCK_ATTR = "locked"; | |||
| static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; | ||||
| static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; | ||||
| static constexpr const char* PATTERN_FILE_ATTR = "pattern_file"; | ||||
| static constexpr const char* PATTERN_BBOX_FILE_ATTR = "pattern_bbox_file"; | ||||
| static constexpr const char* OBJECT_ID_ATTR = "object_id"; | ||||
| static constexpr const char* INSTANCEID_ATTR = "instance_id"; | ||||
| static constexpr const char* PLATERID_ATTR = "plater_id"; | ||||
|  | @ -451,7 +452,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) | |||
|         info.id     = it->first; | ||||
|         info.used_m = used_filament_m; | ||||
|         info.used_g = used_filament_g; | ||||
|         slice_flaments_info.push_back(info); | ||||
|         slice_filaments_info.push_back(info); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1464,9 +1465,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) | |||
|             plate_data_list[it->first-1]->gcode_prediction = it->second->gcode_prediction; | ||||
|             plate_data_list[it->first-1]->gcode_weight = it->second->gcode_weight; | ||||
|             plate_data_list[it->first-1]->toolpath_outside = it->second->toolpath_outside; | ||||
|             plate_data_list[it->first-1]->slice_flaments_info = it->second->slice_flaments_info; | ||||
|             plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info; | ||||
|             plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file; | ||||
|             plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file; | ||||
|             plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file; | ||||
|             it++; | ||||
|         } | ||||
| 
 | ||||
|  | @ -3039,6 +3041,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) | |||
|             { | ||||
|                 m_curr_plater->pattern_file = value; | ||||
|             } | ||||
|             else if (key == PATTERN_BBOX_FILE_ATTR) | ||||
|             { | ||||
|                 m_curr_plater->pattern_bbox_file = value; | ||||
|             } | ||||
|             else if (key == INSTANCEID_ATTR) | ||||
|             { | ||||
|                 m_curr_instance.instance_id = atoi(value.c_str()); | ||||
|  | @ -3110,7 +3116,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) | |||
|             filament_info.color = color; | ||||
|             filament_info.used_m = atof(used_m.c_str()); | ||||
|             filament_info.used_g = atof(used_g.c_str()); | ||||
|             m_curr_plater->slice_flaments_info.push_back(filament_info); | ||||
|             m_curr_plater->slice_filaments_info.push_back(filament_info); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | @ -5327,10 +5333,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) | |||
|                     stream << "    <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n"; | ||||
|                 } | ||||
| 
 | ||||
|                 if (plate_data->pattern_thumbnail.is_valid()) { | ||||
|                 if (!plate_data->pattern_file.empty()) { | ||||
|                     std::string pattern_file_in_3mf = (boost::format(PATTERN_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); | ||||
|                     stream << "    <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_file_in_3mf << "\"/>\n"; | ||||
|                 } | ||||
|                 if (!plate_data->pattern_bbox_file.empty()) { | ||||
|                     std::string pattern_bbox_file_in_3mf = (boost::format(PATTERN_CONFIG_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); | ||||
|                     stream << "    <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PATTERN_BBOX_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << pattern_bbox_file_in_3mf << "\"/>\n"; | ||||
|                 } | ||||
| 
 | ||||
|                 if (instance_size > 0) | ||||
|                 { | ||||
|  | @ -5430,7 +5440,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) | |||
|                 stream << "    <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_WEIGHT_ATTR      << "\" " << VALUE_ATTR << "=\"" <<  plate_data->get_gcode_weight_str() << "\"/>\n"; | ||||
|                 stream << "    <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR      << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n"; | ||||
| 
 | ||||
|                 for (auto it = plate_data->slice_flaments_info.begin(); it != plate_data->slice_flaments_info.end(); it++) | ||||
|                 for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) | ||||
|                 { | ||||
|                     stream << "    <" << FILAMENT_TAG << " " << FILAMENT_ID_TAG << "=\"" << std::to_string(it->id + 1) << "\" " | ||||
|                            << FILAMENT_TYPE_TAG << "=\"" << it->type << "\" " | ||||
|  | @ -5903,7 +5913,8 @@ private: | |||
|                 break; | ||||
|             case AddObject: { | ||||
|                 { | ||||
|                     _BBS_3MF_Exporter e; | ||||
|                     CNumericLocalesSetter locales_setter; | ||||
|                     _BBS_3MF_Exporter     e; | ||||
|                     e.save_object_mesh(t.path, *t.object, (int) t.id); | ||||
|                     // response to delete cloned object
 | ||||
|                 } | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ public: | |||
|     std::string _3mf_thumbnail; | ||||
|     std::string _3mf_printer_thumbnail_middle; | ||||
|     std::string _3mf_printer_thumbnail_small; | ||||
|      | ||||
| 
 | ||||
|     PackingTemporaryData() {} | ||||
| }; | ||||
| 
 | ||||
|  | @ -63,9 +63,10 @@ struct PlateData | |||
|     ThumbnailData   plate_thumbnail; | ||||
|     ThumbnailData   pattern_thumbnail; | ||||
|     std::string     pattern_file; | ||||
|     std::string     pattern_bbox_file; | ||||
|     std::string     gcode_prediction; | ||||
|     std::string     gcode_weight; | ||||
|     std::vector<FilamentInfo> slice_flaments_info; | ||||
|     std::vector<FilamentInfo> slice_filaments_info; | ||||
|     bool            is_sliced_valid = false; | ||||
|     bool            toolpath_outside {false}; | ||||
| 
 | ||||
|  | @ -114,7 +115,7 @@ enum class LoadStrategy | |||
| { | ||||
|     Default = 0, | ||||
|     AddDefaultInstances = 1, | ||||
|     CheckVersion = 2,  | ||||
|     CheckVersion = 2, | ||||
|     LoadModel = 4, | ||||
|     LoadConfig = 8, | ||||
|     LoadAuxiliary = 16, | ||||
|  | @ -223,7 +224,7 @@ extern bool store_bbs_3mf(StoreParams& store_params); | |||
| 
 | ||||
| extern void release_PlateData_list(PlateDataPtrs& plate_data_list); | ||||
| 
 | ||||
| // backup & restore project 
 | ||||
| // backup & restore project
 | ||||
| 
 | ||||
| extern void save_object_mesh(ModelObject& object); | ||||
| 
 | ||||
|  |  | |||
|  | @ -2542,6 +2542,24 @@ GCode::LayerResult GCode::process_layer( | |||
|                 // Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
 | ||||
|                 bool            interface_dontcare = object.config().support_interface_filament.value == 0; | ||||
| 
 | ||||
|                 // BBS: apply wiping overridden extruders
 | ||||
|                 WipingExtrusions& wiping_extrusions = const_cast<LayerTools&>(layer_tools).wiping_extrusions(); | ||||
|                 if (support_dontcare) { | ||||
|                     int extruder_override = wiping_extrusions.get_support_extruder_overrides(&object); | ||||
|                     if (extruder_override >= 0) { | ||||
|                         support_extruder = extruder_override; | ||||
|                         support_dontcare = false; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (interface_dontcare) { | ||||
|                     int extruder_override = wiping_extrusions.get_support_interface_extruder_overrides(&object); | ||||
|                     if (extruder_override >= 0) { | ||||
|                         interface_extruder = extruder_override; | ||||
|                         interface_dontcare = false; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // BBS: try to print support base with a filament other than interface filament
 | ||||
|                 if (support_dontcare && !interface_dontcare) { | ||||
|                     unsigned int dontcare_extruder = first_extruder_id; | ||||
|  | @ -2609,7 +2627,16 @@ GCode::LayerResult GCode::process_layer( | |||
|                 // Shall the support interface be printed with the active extruder, preferably with non-soluble, to avoid tool changes?
 | ||||
|                 bool            interface_dontcare = object.config().support_interface_filament.value == 0; | ||||
| 
 | ||||
|                 // BBS: apply wiping overridden extruders
 | ||||
|                 WipingExtrusions& wiping_extrusions = const_cast<LayerTools&>(layer_tools).wiping_extrusions(); | ||||
|                 if (support_dontcare) { | ||||
|                     int extruder_override = wiping_extrusions.get_support_extruder_overrides(&object); | ||||
|                     if (extruder_override >= 0) { | ||||
|                         support_extruder = extruder_override; | ||||
|                         support_dontcare = false; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (support_dontcare || interface_dontcare) { | ||||
|                     // Some support will be printed with "don't care" material, preferably non-soluble.
 | ||||
|                     // Is the current extruder assigned a soluble filament?
 | ||||
|  | @ -2897,8 +2924,12 @@ GCode::LayerResult GCode::process_layer( | |||
| 
 | ||||
|                     // BBS
 | ||||
|                     WipingExtrusions& wiping_extrusions = const_cast<LayerTools&>(layer_tools).wiping_extrusions(); | ||||
|                     bool support_overridden = wiping_extrusions.is_support_overridden(layer.object()); | ||||
|                     bool support_intf_overridden = wiping_extrusions.is_support_interface_overridden(layer.object()); | ||||
| 
 | ||||
|                     ExtrusionRole support_extrusion_role = instance_to_print.object_by_extruder.support_extrusion_role; | ||||
|                     if (print_wipe_extrusions == 0) | ||||
|                     bool is_overridden = support_extrusion_role == erSupportMaterialInterface ? support_intf_overridden : support_overridden; | ||||
|                     if (is_overridden == (print_wipe_extrusions != 0)) | ||||
|                         support_eec.entities = filter_by_extrusion_role(instance_to_print.object_by_extruder.support->entities, instance_to_print.object_by_extruder.support_extrusion_role); | ||||
| 
 | ||||
|                     for (auto& ptr : support_eec.entities) | ||||
|  |  | |||
|  | @ -1,50 +0,0 @@ | |||
| #include "SpeedGenerator.hpp" | ||||
| #include "libslic3r/ExtrusionEntity.hpp" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| #define BOOST_SPIRIT_THREADSAFE | ||||
| #include <boost/property_tree/ptree.hpp> | ||||
| #include <boost/property_tree/json_parser.hpp> | ||||
| #include <boost/date_time.hpp> | ||||
| #include <boost/foreach.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| SpeedGenerator::SpeedGenerator() { | ||||
| 	// default is 100 speed
 | ||||
| 	for (int i = 0; i < 6; i++) { | ||||
| 		speed_table[i] = 100; | ||||
| 	} | ||||
| 	std::string config_file = resources_dir() + "/PerimeterSpeedConfig.json"; | ||||
| 	std::string encoded_path = encode_path(config_file.c_str()); | ||||
| 	boost::property_tree::read_json<boost::property_tree::ptree>(encoded_path, root); | ||||
| 	if (root.count("speed_table")) { | ||||
| 		int i = 0; | ||||
| 		auto array6 = root.get_child("speed_table"); | ||||
| 		for (auto pos = array6.begin(); pos != array6.end() && i < 6; pos++, i++) | ||||
| 			speed_table[i] = pos->second.get_value<int>(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| double SpeedGenerator::calculate_speed(const ExtrusionPath& path, double max_speed, double min_speed) { | ||||
| 	// limit the speed in case of F0 generated in gcode when user set 0 speed in UI
 | ||||
| 	// which cause printer stopped. 1mm/s is slow enough and can make printer not really stopped.
 | ||||
| 	max_speed = max_speed < 1 ? 1 : max_speed; | ||||
| 	min_speed = min_speed < 1 ? 1 : min_speed; | ||||
| 	// switch min and max speed if user set the max speed to be slower than min_speed
 | ||||
| 	if (max_speed < min_speed) { | ||||
| 		double temp = max_speed; | ||||
| 		max_speed = min_speed; | ||||
| 		min_speed = temp; | ||||
| 	} | ||||
| 	speed_table[0] = max_speed; | ||||
| 
 | ||||
| 	int overhang_degree = path.get_overhang_degree(); | ||||
| 	assert(overhang_degree >= 0 && overhang_degree <= 6); | ||||
| 	double speed = (double)speed_table[overhang_degree]; | ||||
| 	speed = std::max(speed, min_speed); | ||||
| 	speed = std::min(speed, max_speed); | ||||
| 	return speed; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,22 +0,0 @@ | |||
| #ifndef libslic3r_SpeedGenerator_hpp_ | ||||
| #define libslic3r_SpeedGenerator_hpp_ | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class ExtrusionPath; | ||||
| 
 | ||||
| class SpeedGenerator { | ||||
| public: | ||||
| 	SpeedGenerator(); | ||||
| 	double calculate_speed(const ExtrusionPath& path, double max_speed, double min_speed); | ||||
| 
 | ||||
| private: | ||||
| 	boost::property_tree::ptree root; | ||||
| 	int speed_table[6]; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // libslic3r_SpeedGenerator_hpp_
 | ||||
|  | @ -304,6 +304,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto | |||
|             layer_tools.extruders.push_back(extruder_interface); | ||||
|         if (has_support || has_interface) { | ||||
|             layer_tools.has_support = true; | ||||
|             layer_tools.wiping_extrusions().is_support_overriddable_and_mark(role, object); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -321,6 +322,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto | |||
|             layer_tools.extruders.push_back(extruder_interface); | ||||
|         if (has_support || has_interface) { | ||||
|             layer_tools.has_support = true; | ||||
|             layer_tools.wiping_extrusions().is_support_overriddable_and_mark(role, object); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -797,6 +799,19 @@ void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, size | |||
|     copies_vector[copy_id] = extruder; | ||||
| } | ||||
| 
 | ||||
| // BBS
 | ||||
| void WipingExtrusions::set_support_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies) | ||||
| { | ||||
|     something_overridden = true; | ||||
|     support_map.emplace(object, extruder); | ||||
| } | ||||
| 
 | ||||
| void WipingExtrusions::set_support_interface_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies) | ||||
| { | ||||
|     something_overridden = true; | ||||
|     support_intf_map.emplace(object, extruder); | ||||
| } | ||||
| 
 | ||||
| // Finds first non-soluble extruder on the layer
 | ||||
| int WipingExtrusions::first_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const | ||||
| { | ||||
|  | @ -834,6 +849,25 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // BBS
 | ||||
| bool WipingExtrusions::is_support_overriddable(const ExtrusionRole role, const PrintObject& object) const | ||||
| { | ||||
|     if (!object.config().flush_into_support) | ||||
|         return false; | ||||
| 
 | ||||
|     if (role == erMixed) { | ||||
|         return object.config().support_filament == 0 || object.config().support_interface_filament == 0; | ||||
|     } | ||||
|     else if (role == erSupportMaterial || role == erSupportTransition) { | ||||
|         return object.config().support_filament == 0; | ||||
|     } | ||||
|     else if (role == erSupportMaterialInterface) { | ||||
|         return object.config().support_interface_filament == 0; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| // Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
 | ||||
| // and returns volume that is left to be wiped on the wipe tower.
 | ||||
| float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe) | ||||
|  | @ -844,6 +878,10 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int | |||
|     if (! this->something_overridable || volume_to_wipe <= 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder)) | ||||
|         return std::max(0.f, volume_to_wipe); // Soluble filament cannot be wiped in a random infill, neither the filament after it
 | ||||
| 
 | ||||
|     // BBS
 | ||||
|     if (print.config().filament_is_support.get_at(old_extruder)) | ||||
|         return std::max(0.f, volume_to_wipe); // Support filament cannot be used to print support, infill, wipe_tower, etc.
 | ||||
| 
 | ||||
|     // we will sort objects so that dedicated for wiping are at the beginning:
 | ||||
|     ConstPrintObjectPtrs object_list = print.objects().vector(); | ||||
|     std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config().flush_into_objects; }); | ||||
|  | @ -876,7 +914,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int | |||
|             for (const LayerRegion *layerm : this_layer->regions()) { | ||||
|                 const auto ®ion = layerm->region(); | ||||
| 
 | ||||
|                 if (!object->config().flush_into_infill && !object->config().flush_into_objects) | ||||
|                 if (!object->config().flush_into_infill && !object->config().flush_into_objects && !object->config().flush_into_support) | ||||
|                     continue; | ||||
|                 bool wipe_into_infill_only = !object->config().flush_into_objects && object->config().flush_into_infill; | ||||
|                 bool is_infill_first = print.config().wall_infill_order == WallInfillOrder::InfillInnerOuter || | ||||
|  | @ -918,6 +956,46 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int | |||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // BBS
 | ||||
|             if (object->config().flush_into_support) { | ||||
|                 auto& object_config = object->config(); | ||||
|                 const SupportLayer* this_support_layer = object->get_support_layer_at_printz(lt.print_z, EPSILON); | ||||
|                 const TreeSupportLayer* this_tree_support_layer = object->get_tree_support_layer_at_printz(lt.print_z, EPSILON); | ||||
| 
 | ||||
|                 do { | ||||
|                     if (this_support_layer == nullptr && this_tree_support_layer == nullptr) | ||||
|                         break; | ||||
| 
 | ||||
|                     bool support_overriddable = object_config.support_filament == 0; | ||||
|                     bool support_intf_overriddable = object_config.support_interface_filament == 0; | ||||
|                     if (!support_overriddable && !support_intf_overriddable) | ||||
|                         break; | ||||
| 
 | ||||
|                     auto& entities = this_support_layer != nullptr ? this_support_layer->support_fills.entities : this_tree_support_layer->support_fills.entities; | ||||
|                     if (support_overriddable && !is_support_overridden(object)) { | ||||
|                         set_support_extruder_override(object, copy, new_extruder, num_of_copies); | ||||
|                         for (const ExtrusionEntity* ee : entities) { | ||||
|                             if (ee->role() == erSupportMaterial || ee->role() == erSupportTransition) | ||||
|                                 volume_to_wipe -= ee->total_volume(); | ||||
| 
 | ||||
|                             if (volume_to_wipe <= 0.f) | ||||
|                                 return 0.f; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if (support_intf_overriddable && !is_support_interface_overridden(object)) { | ||||
|                         set_support_interface_extruder_override(object, copy, new_extruder, num_of_copies); | ||||
|                         for (const ExtrusionEntity* ee : entities) { | ||||
|                             if (ee->role() == erSupportMaterialInterface) | ||||
|                                 volume_to_wipe -= ee->total_volume(); | ||||
| 
 | ||||
|                             if (volume_to_wipe <= 0.f) | ||||
|                                 return 0.f; | ||||
|                         } | ||||
|                     } | ||||
|                 } while (0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 	// Some purge remains to be done on the Wipe Tower.
 | ||||
|  | @ -1010,4 +1088,24 @@ const WipingExtrusions::ExtruderPerCopy* WipingExtrusions::get_extruder_override | |||
|     return overrides; | ||||
| } | ||||
| 
 | ||||
| // BBS
 | ||||
| int WipingExtrusions::get_support_extruder_overrides(const PrintObject* object) | ||||
| { | ||||
|     auto iter = support_map.find(object); | ||||
|     if (iter != support_map.end()) | ||||
|         return iter->second; | ||||
| 
 | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| int WipingExtrusions::get_support_interface_extruder_overrides(const PrintObject* object) | ||||
| { | ||||
|     auto iter = support_intf_map.find(object); | ||||
|     if (iter != support_intf_map.end()) | ||||
|         return iter->second; | ||||
| 
 | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -32,6 +32,8 @@ public: | |||
| 
 | ||||
|     // This is called from GCode::process_layer - see implementation for further comments:
 | ||||
|     const ExtruderPerCopy* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies); | ||||
|     int get_support_extruder_overrides(const PrintObject* object); | ||||
|     int get_support_interface_extruder_overrides(const PrintObject* object); | ||||
| 
 | ||||
|     // This function goes through all infill entities, decides which ones will be used for wiping and
 | ||||
|     // marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
 | ||||
|  | @ -46,6 +48,22 @@ public: | |||
|     	return out; | ||||
|     } | ||||
| 
 | ||||
|     // BBS
 | ||||
|     bool is_support_overriddable(const ExtrusionRole role, const PrintObject& object) const; | ||||
|     bool is_support_overriddable_and_mark(const ExtrusionRole role, const PrintObject& object) { | ||||
|         bool out = this->is_support_overriddable(role, object); | ||||
|         this->something_overridable |= out; | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     bool is_support_overridden(const PrintObject* object) const { | ||||
|         return support_map.find(object) != support_map.end(); | ||||
|     } | ||||
| 
 | ||||
|     bool is_support_interface_overridden(const PrintObject* object) const { | ||||
|         return support_intf_map.find(object) != support_intf_map.end(); | ||||
|     } | ||||
| 
 | ||||
|     void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; } | ||||
| 
 | ||||
| private: | ||||
|  | @ -54,6 +72,9 @@ private: | |||
| 
 | ||||
|     // This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
 | ||||
|     void set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies); | ||||
|     // BBS
 | ||||
|     void set_support_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies); | ||||
|     void set_support_interface_extruder_override(const PrintObject* object, size_t copy_id, int extruder, size_t num_of_copies); | ||||
| 
 | ||||
|     // Returns true in case that entity is not printed with its usual extruder for a given copy:
 | ||||
|     bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const { | ||||
|  | @ -62,6 +83,9 @@ private: | |||
|     } | ||||
| 
 | ||||
|     std::map<const ExtrusionEntity*, ExtruderPerCopy> entity_map;  // to keep track of who prints what
 | ||||
|     // BBS
 | ||||
|     std::map<const PrintObject*, int> support_map; | ||||
|     std::map<const PrintObject*, int> support_intf_map; | ||||
|     bool something_overridable = false; | ||||
|     bool something_overridden = false; | ||||
|     const LayerTools* m_layer_tools = nullptr;    // so we know which LayerTools object this belongs to
 | ||||
|  |  | |||
|  | @ -251,6 +251,12 @@ public: | |||
|     }; | ||||
|     std::vector<std::pair<ExPolygon *, int>> area_groups; | ||||
| 
 | ||||
|     enum OverhangType { | ||||
|         Detected=0, | ||||
|         Enforced | ||||
|     }; | ||||
|     std::map<const ExPolygon *, OverhangType> overhang_types; | ||||
| 
 | ||||
|     virtual bool has_extrusions() const { return !support_fills.empty(); } | ||||
| 
 | ||||
|     void simplify_support_extrusion_path() { this->simplify_support_entity_collection(&support_fills);} | ||||
|  |  | |||
|  | @ -70,6 +70,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec | |||
| 
 | ||||
|     const PrintConfig       &print_config  = this->layer()->object()->print()->config(); | ||||
|     const PrintRegionConfig ®ion_config = this->region().config(); | ||||
|     const PrintObjectConfig& object_config = this->layer()->object()->config(); | ||||
|     // This needs to be in sync with PrintObject::_slice() slicing_mode_normal_below_layer!
 | ||||
|     bool spiral_mode = print_config.spiral_mode && | ||||
|         //FIXME account for raft layers.
 | ||||
|  | @ -100,7 +101,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec | |||
|      | ||||
|     g.layer_id              = (int)this->layer()->id(); | ||||
|     g.ext_perimeter_flow    = this->flow(frExternalPerimeter); | ||||
|     g.overhang_flow         = this->bridging_flow(frPerimeter, g_config_thick_bridges); | ||||
|     g.overhang_flow         = this->bridging_flow(frPerimeter, object_config.thick_bridges); | ||||
|     g.solid_infill_flow     = this->flow(frSolidInfill); | ||||
|      | ||||
|     g.process(); | ||||
|  | @ -118,6 +119,9 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly | |||
|     const bool      has_infill = this->region().config().sparse_infill_density.value > 0.; | ||||
|     const float		margin 	   = float(scale_(EXTERNAL_INFILL_MARGIN)); | ||||
| 
 | ||||
|     // BBS
 | ||||
|     const PrintObjectConfig& object_config = this->layer()->object()->config(); | ||||
| 
 | ||||
| #ifdef SLIC3R_DEBUG_SLICE_PROCESSING | ||||
|     export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-initial"); | ||||
| #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ | ||||
|  | @ -285,7 +289,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly | |||
|                 // would get merged into a single one while they need different directions
 | ||||
|                 // also, supply the original expolygon instead of the grown one, because in case
 | ||||
|                 // of very thin (but still working) anchors, the grown expolygon would go beyond them
 | ||||
|                 BridgeDetector bd(initial, lower_layer->lslices, this->bridging_flow(frInfill, g_config_thick_bridges).scaled_width()); | ||||
|                 BridgeDetector bd(initial, lower_layer->lslices, this->bridging_flow(frInfill, object_config.thick_bridges).scaled_width()); | ||||
|                 #ifdef SLIC3R_DEBUG | ||||
|                 printf("Processing bridge at layer %zu:\n", this->layer()->id()); | ||||
|                 #endif | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/libslic3r/MacUtils.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/libslic3r/MacUtils.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #ifndef __MAC_UTILS_H | ||||
| #define __MAC_UTILS_H | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| bool is_macos_support_boost_add_file_log(); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										15
									
								
								src/libslic3r/MacUtils.mm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/libslic3r/MacUtils.mm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| #import <Foundation/Foundation.h> | ||||
| #import "MacUtils.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| bool is_macos_support_boost_add_file_log() | ||||
| { | ||||
|     if (@available(macOS 12.0, *)) { | ||||
| 		return true; | ||||
| 	} else { | ||||
| 	    return false; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| }; // namespace Slic3r | ||||
|  | @ -2754,6 +2754,41 @@ double Model::findMaxSpeed(const ModelObject* object) { | |||
|     if (objMaxSpeed <= 0) objMaxSpeed = 250.; | ||||
|     return objMaxSpeed; | ||||
| } | ||||
| 
 | ||||
| // BBS: thermal length is calculated according to the material of a volume
 | ||||
| double Model::getThermalLength(const ModelVolume* modelVolumePtr) { | ||||
|     double thermalLength = 200.; | ||||
|     auto aa = modelVolumePtr->extruder_id(); | ||||
|     if (Model::extruderParamsMap.find(aa) != Model::extruderParamsMap.end()) { | ||||
|         if (Model::extruderParamsMap.at(aa).materialName == "ABS" || | ||||
|             Model::extruderParamsMap.at(aa).materialName == "PA-CF" || | ||||
|             Model::extruderParamsMap.at(aa).materialName == "PET-CF") { | ||||
|             thermalLength = 100; | ||||
|         } | ||||
|         if (Model::extruderParamsMap.at(aa).materialName == "PC") { | ||||
|             thermalLength = 40; | ||||
|         } | ||||
|         if (Model::extruderParamsMap.at(aa).materialName == "TPU") { | ||||
|             thermalLength = 1000; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|     return thermalLength; | ||||
| } | ||||
| 
 | ||||
| // BBS: thermal length calculation for a group of volumes
 | ||||
| double Model::getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs) | ||||
| { | ||||
|     double thermalLength = 1250.; | ||||
| 
 | ||||
|     for (const auto& modelVolumePtr : modelVolumePtrs) { | ||||
|         if (modelVolumePtr != nullptr) { | ||||
|             // the thermal length of a group is decided by the volume with shortest thermal length
 | ||||
|             thermalLength = std::min(thermalLength, getThermalLength(modelVolumePtr)); | ||||
|         } | ||||
|     } | ||||
|     return thermalLength; | ||||
| } | ||||
| // max printing speed, difference in bed temperature and envirument temperature and bed adhension coefficients are considered 
 | ||||
| double ModelInstance::get_auto_brim_width(double deltaT, double adhension) const | ||||
| { | ||||
|  | @ -2763,9 +2798,10 @@ double ModelInstance::get_auto_brim_width(double deltaT, double adhension) const | |||
|     auto bbox_size = transform_bounding_box(raw_bbox).size(); | ||||
|     double height_to_area = std::max(bbox_size(2) / (bbox_size(0) * bbox_size(0) * bbox_size(1)), | ||||
|         bbox_size(2) / (bbox_size(1) * bbox_size(1) * bbox_size(0))); | ||||
|     double thermalLength = std::max(bbox_size(0), bbox_size(1)); | ||||
|     double thermalLength = sqrt(bbox_size(0)* bbox_size(0) + bbox_size(1)* bbox_size(1)); | ||||
|     double thermalLengthRef = Model::getThermalLength(object->volumes); | ||||
| 
 | ||||
|     double brim_width = adhension * std::min(std::min(std::max(height_to_area * 200 * maxSpeed/200, (deltaT-30)/75 * thermalLength * 0.15), 20.), 1.5 * thermalLength); | ||||
|     double brim_width = adhension * std::min(std::min(std::max(height_to_area * 200 * maxSpeed/200, thermalLength * 8. / thermalLengthRef * std::min(bbox_size(2), 30.) / 30.), 20.), 1.5 * thermalLength); | ||||
|     // small brims are omitted
 | ||||
|     if (brim_width < 5 && brim_width < 1.5 * thermalLength) | ||||
|         brim_width = 0; | ||||
|  |  | |||
|  | @ -1274,6 +1274,9 @@ public: | |||
|         ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr); | ||||
|     // BBS
 | ||||
|     static double findMaxSpeed(const ModelObject* object); | ||||
|     static double getThermalLength(const ModelVolume* modelVolumePtr); | ||||
|     static double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs); | ||||
| 
 | ||||
|     // BBS: backup
 | ||||
|     static Model read_from_archive( | ||||
|         const std::string& input_file, | ||||
|  |  | |||
|  | @ -553,58 +553,33 @@ void PerimeterGenerator::process() | |||
|                         offset_top_surface = 0; | ||||
|                     //don't takes into account too thin areas
 | ||||
|                     double min_width_top_surface = std::max(double(ext_perimeter_spacing / 2 + 10), 1.0 * (double(perimeter_width))); | ||||
|                     //make thin upper surfaces disapear with -+offset_top_surface
 | ||||
|                     ExPolygons grown_upper_slices; | ||||
|                     //do offset2 per island, to avoid big blob merging
 | ||||
|                     //remove polygon too thin (but don't mess with holes)
 | ||||
|                     for (const ExPolygon& expoly_to_grow : *this->upper_slices) { | ||||
|                         //only offset the contour, as it can merge holes
 | ||||
|                         Polygons contour = offset2({ ExPolygon(expoly_to_grow.contour) }, -offset_top_surface, offset_top_surface + min_width_top_surface); | ||||
|                         if (!contour.empty()) { | ||||
|                             if (expoly_to_grow.holes.empty()) { | ||||
|                                 for (Polygon& p : contour) | ||||
|                                     grown_upper_slices.push_back(ExPolygon{ p }); | ||||
|                             } | ||||
|                             else { | ||||
|                                 Polygons holes = expoly_to_grow.holes; | ||||
|                                 for (Polygon& h : holes) | ||||
|                                     h.reverse(); | ||||
|                                 holes = offset(holes, -min_width_top_surface); | ||||
|                                 for (ExPolygon p : diff_ex(contour, holes)) | ||||
|                                     grown_upper_slices.push_back(p); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     grown_upper_slices = union_ex(grown_upper_slices); | ||||
|                     ExPolygons grown_upper_slices = offset_ex(*this->upper_slices, min_width_top_surface); | ||||
|                     //set the clip to a virtual "second perimeter"
 | ||||
|                     fill_clip = offset_ex(last, -double(ext_perimeter_spacing)); | ||||
|                     auto fill_clip_old = fill_clip; | ||||
|                     // get the real top surface
 | ||||
|                     const ExPolygons top_grown_polygons = diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes); | ||||
|                     ExPolygons top_polygons = diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes); | ||||
| 
 | ||||
|                     //get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the min_width_top_surface we removed a bit before)
 | ||||
|                     //also remove the ext_perimeter_spacing/2 width because we are faking the external periemter, and we will remove ext_perimeter_spacing2
 | ||||
|                     const ExPolygons inner_polygons = diff_ex(last, | ||||
|                                                               offset_ex(top_grown_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)), | ||||
|                                                               ApplySafetyOffset::Yes); | ||||
|                     ExPolygons inner_polygons = diff_ex(last, | ||||
|                                                         offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)), | ||||
|                                                         ApplySafetyOffset::Yes); | ||||
|                     // get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly the polygons to fill.
 | ||||
|                     const ExPolygons top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes); | ||||
|                     top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes); | ||||
|                     // increase by half peri the inner space to fill the frontier between last and stored.
 | ||||
|                     top_fills = union_ex(top_fills, top_polygons); | ||||
|                     //set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap.
 | ||||
|                     double infill_spacing_unscaled = this->config->sparse_infill_line_width.value; | ||||
|                     //if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, nozzle_diameter);
 | ||||
|                     fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2)); | ||||
|                     last = intersection_ex(inner_polygons, last); | ||||
|                     //{
 | ||||
|                     //    std::stringstream stri;
 | ||||
|                     //    stri << this->layer->id() << "_1_"<< i <<"_only_one_peri"<< ".svg";
 | ||||
|                     //    SVG svg(stri.str());
 | ||||
|                     //    svg.draw(to_polylines(oldLast), "orange");
 | ||||
|                     //    svg.draw(to_polylines(fill_clip), "purple");
 | ||||
|                     //    svg.draw(to_polylines(top_fills), "green");
 | ||||
|                     //    svg.draw(to_polylines(inner_polygons), "yellow");
 | ||||
|                     //    svg.draw(to_polylines(top_polygons), "cyan");
 | ||||
|                     //    svg.draw(to_polylines(oldLast), "orange");
 | ||||
|                     //    svg.draw(to_polylines(last), "red");
 | ||||
|                     //    svg.draw(to_polylines(fill_clip_old), "green");
 | ||||
|                     //    svg.Close();
 | ||||
|                     //}
 | ||||
|                 } | ||||
|  | @ -700,9 +675,8 @@ void PerimeterGenerator::process() | |||
|                 offset2_ex(gaps, - float(max / 2.), float(max / 2. + ClipperSafetyOffset))); | ||||
|             ThickPolylines polylines; | ||||
|             for (ExPolygon& ex : gaps_ex) { | ||||
|                 //BBS: medial axis algorithm can't handle duplicated points in expolygon.
 | ||||
|                 //Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|                 ex.douglas_peucker(SCALED_RESOLUTION); | ||||
|                 //BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
 | ||||
|                 ex.douglas_peucker(surface_simplify_resolution); | ||||
|                 ex.medial_axis(max, min, &polylines); | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ public: | |||
|             overhang_flow(flow), solid_infill_flow(flow), | ||||
|             config(config), object_config(object_config), print_config(print_config), | ||||
|             m_spiral_vase(spiral_mode), | ||||
|             m_scaled_resolution(scaled<double>(print_config->resolution.value)), | ||||
|             m_scaled_resolution(scaled<double>(print_config->resolution.value > EPSILON ? print_config->resolution.value : EPSILON)), | ||||
|             loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), | ||||
|             m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1), m_ext_mm3_per_mm_smaller_width(-1) | ||||
|         {} | ||||
|  |  | |||
|  | @ -311,6 +311,54 @@ bool Polyline::is_straight() const | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void Polyline::append(const Polyline &src) | ||||
| { | ||||
|     if (!src.is_valid()) return; | ||||
| 
 | ||||
|     if (this->points.empty()) { | ||||
|         this->points = src.points; | ||||
|         this->fitting_result = src.fitting_result; | ||||
|     } else { | ||||
|         //BBS: append the first point to create connection first, update the fitting date as well
 | ||||
|         this->append(src.points[0]); | ||||
|         //BBS: append a polyline which has fitting data to a polyline without fitting data.
 | ||||
|         //Then create a fake fitting data first, so that we can keep the fitting data in last polyline
 | ||||
|         if (this->fitting_result.empty() && | ||||
|             !src.fitting_result.empty()) { | ||||
|             this->fitting_result.emplace_back(PathFittingData{ 0, this->points.size() - 1, EMovePathType::Linear_move, ArcSegment() }); | ||||
|         } | ||||
|         //BBS: then append the remain points
 | ||||
|         MultiPoint::append(src.points.begin() + 1, src.points.end()); | ||||
|         //BBS: finally append the fitting data
 | ||||
|         append_fitting_result_after_append_polyline(src); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Polyline::append(Polyline &&src) | ||||
| { | ||||
|     if (!src.is_valid()) return; | ||||
| 
 | ||||
|     if (this->points.empty()) { | ||||
|         this->points = std::move(src.points); | ||||
|         this->fitting_result = std::move(src.fitting_result); | ||||
|     } else { | ||||
|         //BBS: append the first point to create connection first, update the fitting date as well
 | ||||
|         this->append(src.points[0]); | ||||
|         //BBS: append a polyline which has fitting data to a polyline without fitting data.
 | ||||
|         //Then create a fake fitting data first, so that we can keep the fitting data in last polyline
 | ||||
|         if (this->fitting_result.empty() && | ||||
|             !src.fitting_result.empty()) { | ||||
|             this->fitting_result.emplace_back(PathFittingData{ 0, this->points.size() - 1, EMovePathType::Linear_move, ArcSegment() }); | ||||
|         } | ||||
|         //BBS: then append the remain points
 | ||||
|         MultiPoint::append(src.points.begin() + 1, src.points.end()); | ||||
|         //BBS: finally append the fitting data
 | ||||
|         append_fitting_result_after_append_polyline(src); | ||||
|         src.points.clear(); | ||||
|         src.fitting_result.clear(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Polyline::append_fitting_result_after_append_points() { | ||||
|     if (!fitting_result.empty()) { | ||||
|         if (fitting_result.back().is_linear_move()) { | ||||
|  | @ -326,14 +374,6 @@ void Polyline::append_fitting_result_after_append_points() { | |||
| 
 | ||||
| void Polyline::append_fitting_result_after_append_polyline(const Polyline& src) | ||||
| { | ||||
|     //BBS: append a polyline which has fitting data to a polyline without fitting data.
 | ||||
|     //Then create a fake fitting data first, so that we can keep the fitting data in last polyline
 | ||||
|     if (this->fitting_result.empty() && | ||||
|         !src.fitting_result.empty()) { | ||||
|         if (!this->points.empty()) | ||||
|             this->fitting_result.emplace_back(PathFittingData{ 0, this->size() - 1, EMovePathType::Linear_move, ArcSegment() }); | ||||
|     } | ||||
| 
 | ||||
|     if (!this->fitting_result.empty()) { | ||||
|         //BBS: offset and save the fitting_result from src polyline
 | ||||
|         if (!src.fitting_result.empty()) { | ||||
|  | @ -346,7 +386,7 @@ void Polyline::append_fitting_result_after_append_polyline(const Polyline& src) | |||
|             } | ||||
|         } else { | ||||
|             //BBS: the append polyline has no fitting data, then append as linear move directly
 | ||||
|             size_t new_start = fitting_result.back().end_point_index; | ||||
|             size_t new_start = this->fitting_result.back().end_point_index; | ||||
|             size_t new_end = this->size() - 1; | ||||
|             if (new_start != new_end) | ||||
|                 this->fitting_result.emplace_back(PathFittingData{ new_start, new_end, EMovePathType::Linear_move, ArcSegment() }); | ||||
|  |  | |||
|  | @ -99,41 +99,8 @@ public: | |||
|         MultiPoint::append(std::move(src)); | ||||
|         append_fitting_result_after_append_points(); | ||||
|     } | ||||
|     void append(const Polyline &src)  | ||||
|     { | ||||
|         if (!src.is_valid()) return; | ||||
| 
 | ||||
|         if (this->points.empty()) { | ||||
|             this->points = src.points; | ||||
|             this->fitting_result = src.fitting_result; | ||||
|         } else { | ||||
|             //BBS: append the first point to create connection first, update the fitting date as well
 | ||||
|             this->append(src.points[0]); | ||||
|             //BBS: then append the remain points
 | ||||
|             MultiPoint::append(src.points.begin() + 1, src.points.end()); | ||||
|             //BBS: finally append the fitting data
 | ||||
|             append_fitting_result_after_append_polyline(src); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void append(Polyline &&src)  | ||||
|     { | ||||
|         if (!src.is_valid()) return; | ||||
| 
 | ||||
|         if (this->points.empty()) { | ||||
|             this->points = std::move(src.points); | ||||
|             this->fitting_result = std::move(src.fitting_result); | ||||
|         } else { | ||||
|             //BBS: append the first point to create connection first, update the fitting date as well
 | ||||
|             this->append(src.points[0]); | ||||
|             //BBS: then append the remain points
 | ||||
|             MultiPoint::append(src.points.begin() + 1, src.points.end()); | ||||
|             //BBS: finally append the fitting data
 | ||||
|             append_fitting_result_after_append_polyline(src); | ||||
|             src.points.clear(); | ||||
|             src.fitting_result.clear(); | ||||
|         } | ||||
|     } | ||||
|     void append(const Polyline& src); | ||||
|     void append(Polyline&& src); | ||||
|    | ||||
|     const Point& last_point() const override { return this->points.back(); } | ||||
|     const Point& leftmost_point() const; | ||||
|  |  | |||
|  | @ -666,7 +666,7 @@ static std::vector<std::string> s_Preset_print_options { | |||
|     //"independent_support_layer_height",
 | ||||
|     "support_angle", "support_interface_top_layers", "support_interface_bottom_layers", | ||||
|     "support_interface_pattern", "support_interface_spacing", "support_interface_loop_pattern", | ||||
|     "support_top_z_distance", "support_on_build_plate_only", "bridge_no_support","max_bridge_length", "print_sequence", | ||||
|     "support_top_z_distance", "support_on_build_plate_only", "bridge_no_support", "thick_bridges", "max_bridge_length", "print_sequence", | ||||
|     "filename_format", "wall_filament", | ||||
|     "sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament", | ||||
|     "ooze_prevention", "standby_temperature_delta", "interface_shells", "line_width", "initial_layer_line_width", | ||||
|  | @ -675,7 +675,7 @@ static std::vector<std::string> s_Preset_print_options { | |||
|     "elefant_foot_compensation", "xy_contour_compensation", "xy_hole_compensation", "resolution", "enable_prime_tower", | ||||
|     "prime_tower_width", "prime_tower_brim_width", "prime_volume", | ||||
|     "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits", | ||||
|     "flush_into_infill", "flush_into_objects", | ||||
|     "flush_into_infill", "flush_into_objects", "flush_into_support", | ||||
|     // BBS
 | ||||
|      "tree_support_branch_angle", "tree_support_with_infill", "tree_support_wall_count", "tree_support_branch_distance", | ||||
|      "tree_support_branch_diameter", | ||||
|  |  | |||
|  | @ -181,6 +181,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n | |||
|             || opt_key == "flush_volumes_matrix" | ||||
|             || opt_key == "prime_volume" | ||||
|             || opt_key == "flush_into_infill" | ||||
|             || opt_key == "flush_into_support" | ||||
|             || opt_key == "initial_layer_infill_speed" | ||||
|             || opt_key == "travel_speed" | ||||
|             || opt_key == "travel_speed_z" | ||||
|  |  | |||
|  | @ -165,7 +165,6 @@ class ConstSupportLayerPtrsAdaptor : public ConstVectorOfPtrsAdaptor<SupportLaye | |||
| 
 | ||||
| // BBS
 | ||||
| typedef std::vector<TreeSupportLayer*>        TreeSupportLayerPtrs; | ||||
| typedef std::vector<const TreeSupportLayer*>  ConstTreeSupportLayerPtrs; | ||||
| class ConstTreeSupportLayerPtrsAdaptor : public ConstVectorOfPtrsAdaptor<TreeSupportLayer> { | ||||
|     friend PrintObject; | ||||
|     ConstTreeSupportLayerPtrsAdaptor(const TreeSupportLayerPtrs* data) : ConstVectorOfPtrsAdaptor<TreeSupportLayer>(data) {} | ||||
|  | @ -300,7 +299,8 @@ public: | |||
|         const Layer* current_layer, | ||||
|         float extrusion_width, | ||||
|         PolysType* overhang_regions, | ||||
|         float max_bridge_length = scale_(10)); | ||||
|         float max_bridge_length = scale_(10), | ||||
|         bool break_bridge=false); | ||||
| 
 | ||||
|     // Bounding box is used to align the object infill patterns, and to calculate attractor for the rear seam.
 | ||||
|     // The bounding box may not be quite snug.
 | ||||
|  | @ -340,6 +340,10 @@ public: | |||
|     // Get a layer approximately at print_z.
 | ||||
|     const Layer*	get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const; | ||||
|     Layer*			get_layer_at_printz(coordf_t print_z, coordf_t epsilon); | ||||
|     // BBS
 | ||||
|     const Layer*    get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon) const; | ||||
|     Layer*          get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon); | ||||
| 
 | ||||
|     // Get the first layer approximately bellow print_z.
 | ||||
|     const Layer*	get_first_layer_bellow_printz(coordf_t print_z, coordf_t epsilon) const; | ||||
| 
 | ||||
|  | @ -354,6 +358,7 @@ public: | |||
|     void  clear_tree_support_layers(); | ||||
|     size_t tree_support_layer_count() const { return m_tree_support_layers.size(); } | ||||
|     std::shared_ptr<TreeSupportData> alloc_tree_support_preview_cache(); | ||||
|     void clear_tree_support_preview_cache() { m_tree_support_preview_cache.reset(); } | ||||
| 
 | ||||
|     size_t          support_layer_count() const { return m_support_layers.size(); } | ||||
|     void            clear_support_layers(); | ||||
|  |  | |||
|  | @ -686,7 +686,15 @@ void PrintConfigDef::init_fff_params() | |||
|     def->tooltip = L("Don't support the whole bridge area which make support very large. " | ||||
|                      "Bridge usually can be printing directly without support if not very long"); | ||||
|     def->mode = comAdvanced; | ||||
|     def->set_default_value(new ConfigOptionBool(true)); | ||||
|     def->set_default_value(new ConfigOptionBool(false)); | ||||
| 
 | ||||
|     def = this->add("thick_bridges", coBool); | ||||
|     def->label = L("Thick bridges"); | ||||
|     def->category = L("Layers and Perimeters"); | ||||
|     def->tooltip = L("If enabled, bridges are more reliable, can bridge longer distances, but may look worse. " | ||||
|         "If disabled, bridges look better but are reliable just for shorter bridged distances."); | ||||
|     def->mode = comAdvanced; | ||||
|     def->set_default_value(new ConfigOptionBool(false)); | ||||
| 
 | ||||
|     def = this->add("max_bridge_length", coFloat); | ||||
|     def->label = L("Max bridge length"); | ||||
|  | @ -722,10 +730,7 @@ void PrintConfigDef::init_fff_params() | |||
|     def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values(); | ||||
|     def->enum_values.push_back("concentric"); | ||||
|     def->enum_values.push_back("zig-zag"); | ||||
| #if !BBL_RELEASE_TO_PUBLIC | ||||
|     def->enum_values.push_back("monotonic"); | ||||
| #endif | ||||
|     //BBS: use monotonicline pattern to replace monotonic for top and bottom surface
 | ||||
|     def->enum_values.push_back("monotonicline"); | ||||
|     //def->enum_values.push_back("alignedrectilinear");
 | ||||
|     //def->enum_values.push_back("hilbertcurve");
 | ||||
|  | @ -733,9 +738,7 @@ void PrintConfigDef::init_fff_params() | |||
|     //def->enum_values.push_back("octagramspiral");
 | ||||
|     def->enum_labels.push_back(L("Concentric")); | ||||
|     def->enum_labels.push_back(L("Zig zag")); | ||||
| #if !BBL_RELEASE_TO_PUBLIC | ||||
|     def->enum_labels.push_back(L("Monotonic")); | ||||
| #endif | ||||
|     def->enum_labels.push_back(L("Monotonic line")); | ||||
|     //def->enum_labels.push_back(L("Aligned Rectilinear"));
 | ||||
|     //def->enum_labels.push_back(L("Hilbert Curve"));
 | ||||
|  | @ -1627,8 +1630,10 @@ void PrintConfigDef::init_fff_params() | |||
| 
 | ||||
|     def = this->add("reduce_infill_retraction", coBool); | ||||
|     def->label = L("Reduce infill retraction"); | ||||
|     def->tooltip = L("Don't retract when the travel is in infill area absolutely. That means the oozing can't been seen"); | ||||
|     def->mode = comDevelop; | ||||
|     def->tooltip = L("Don't retract when the travel is in infill area absolutely. That means the oozing can't been seen. " | ||||
|                      "This can reduce times of retraction for complex model and save printing time, but make slicing and " | ||||
|                      "G-code generating slower"); | ||||
|     def->mode = comAdvanced; | ||||
|     def->set_default_value(new ConfigOptionBool(true)); | ||||
| 
 | ||||
|     def = this->add("ooze_prevention", coBool); | ||||
|  | @ -2545,6 +2550,13 @@ void PrintConfigDef::init_fff_params() | |||
|         "If the walls are printed with transparent filament, the mixed color infill will be seen outside"); | ||||
|     def->set_default_value(new ConfigOptionBool(false)); | ||||
| 
 | ||||
|     def = this->add("flush_into_support", coBool); | ||||
|     def->category = L("Flush options"); | ||||
|     def->label = L("Flush into objects' support"); | ||||
|     def->tooltip = L("Purging after filament change will be done inside objects' support. " | ||||
|         "This may lower the amount of waste and decrease the print time"); | ||||
|     def->set_default_value(new ConfigOptionBool(true)); | ||||
| 
 | ||||
|     def = this->add("flush_into_objects", coBool); | ||||
|     def->category = L("Flush options"); | ||||
|     def->label = L("Flush into this object"); | ||||
|  | @ -3345,12 +3357,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va | |||
|         //But now these key-value must be absolute value.
 | ||||
|         //Reset to default value by erasing these key to avoid parsing error.
 | ||||
|         opt_key = ""; | ||||
|     } else if (opt_key == "top_surface_pattern" || opt_key == "bottom_surface_pattern") { | ||||
| #if BBL_RELEASE_TO_PUBLIC | ||||
|         //BBS: replace monotonic pattern to be monotonicline for top and bottom surface
 | ||||
|         if (value == "monotonic") | ||||
|             value = "monotonicline"; | ||||
| #endif | ||||
|     } else if (opt_key == "filament_type" && value == "PA-CF") { | ||||
|         value == "PA"; | ||||
|     } else if (opt_key == "inherits_cummulative") { | ||||
|  | @ -3372,7 +3378,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va | |||
|         , "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative" | ||||
| #endif /* HAS_PRESSURE_EQUALIZER */ | ||||
|         // BBS
 | ||||
|         , "thick_bridges","support_sharp_tails","remove_small_overhangs", "support_with_sheath", | ||||
|         , "support_sharp_tails","remove_small_overhangs", "support_with_sheath", | ||||
|         "tree_support_branch_diameter_angle", "tree_support_collision_resolution", | ||||
|         "small_perimeter_speed", "max_volumetric_speed", "max_print_speed", | ||||
|         "support_bottom_z_distance", "support_closing_radius", "slicing_mode", "slice_closing_radius", | ||||
|  |  | |||
|  | @ -596,6 +596,7 @@ PRINT_CONFIG_CLASS_DEFINE( | |||
|     ((ConfigOptionEnum<SupportMaterialStyle>, support_style)) | ||||
|     // BBS
 | ||||
|     ((ConfigOptionBool,                independent_support_layer_height)) | ||||
|     ((ConfigOptionBool,                thick_bridges)) | ||||
|     // Overhang angle threshold.
 | ||||
|     ((ConfigOptionInt,                 support_threshold_angle)) | ||||
|     ((ConfigOptionFloat,               support_object_xy_distance)) | ||||
|  | @ -604,6 +605,7 @@ PRINT_CONFIG_CLASS_DEFINE( | |||
|     ((ConfigOptionBool,                flush_into_objects)) | ||||
|     // BBS
 | ||||
|     ((ConfigOptionBool,                flush_into_infill)) | ||||
|     ((ConfigOptionBool,                flush_into_support)) | ||||
|     // BBS
 | ||||
|     ((ConfigOptionFloat,              tree_support_branch_distance)) | ||||
|     ((ConfigOptionFloat,              tree_support_branch_diameter)) | ||||
|  |  | |||
|  | @ -566,7 +566,7 @@ void PrintObject::clear_tree_support_layers() | |||
| 
 | ||||
| std::shared_ptr<TreeSupportData> PrintObject::alloc_tree_support_preview_cache() | ||||
| { | ||||
|     if (m_tree_support_preview_cache == nullptr) { | ||||
|     if (!m_tree_support_preview_cache) { | ||||
|         const coordf_t layer_height = m_config.layer_height.value; | ||||
|         const coordf_t xy_distance = m_config.support_object_xy_distance.value; | ||||
|         const double angle = m_config.tree_support_branch_angle.value * M_PI / 180.; | ||||
|  | @ -787,7 +787,8 @@ bool PrintObject::invalidate_state_by_config_options( | |||
|             invalidated |= m_print->invalidate_step(psGCodeExport); | ||||
|         } else if ( | ||||
|                opt_key == "flush_into_infill" | ||||
|             || opt_key == "flush_into_objects") { | ||||
|             || opt_key == "flush_into_objects" | ||||
|             || opt_key == "flush_into_support") { | ||||
|             invalidated |= m_print->invalidate_step(psWipeTower); | ||||
|             invalidated |= m_print->invalidate_step(psGCodeExport); | ||||
|         } else { | ||||
|  | @ -827,7 +828,7 @@ bool PrintObject::invalidate_step(PrintObjectStep step) | |||
|     } | ||||
| 
 | ||||
|     // Wipe tower depends on the ordering of extruders, which in turn depends on everything.
 | ||||
|     // It also decides about what the flush_into_infill / wipe_into_object features will do,
 | ||||
|     // It also decides about what the flush_into_infill / wipe_into_object / flush_into_support features will do,
 | ||||
|     // and that too depends on many of the settings.
 | ||||
|     invalidated |= m_print->invalidate_step(psWipeTower); | ||||
|     // Invalidate G-code export in any case.
 | ||||
|  | @ -2297,7 +2298,8 @@ void PrintObject::remove_bridges_from_contacts( | |||
|     const Layer* current_layer, | ||||
|     float extrusion_width, | ||||
|     PolysType* overhang_regions, | ||||
|     float max_bridge_length) | ||||
|     float max_bridge_length, | ||||
|     bool break_bridge) | ||||
| { | ||||
|     // Extrusion width accounts for the roundings of the extrudates.
 | ||||
|     // It is the maximum widh of the extrudate.
 | ||||
|  | @ -2305,6 +2307,7 @@ void PrintObject::remove_bridges_from_contacts( | |||
|     Lines overhang_perimeters = to_lines(*overhang_regions); | ||||
|     auto layer_regions = current_layer->regions(); | ||||
|     Polygons lower_layer_polygons = to_polygons(lower_layer->lslices); | ||||
|     const PrintObjectConfig& object_config = current_layer->object()->config(); | ||||
| 
 | ||||
|     Polygons all_bridges; | ||||
|     for (LayerRegion* layerm : layer_regions) | ||||
|  | @ -2321,7 +2324,7 @@ void PrintObject::remove_bridges_from_contacts( | |||
|             // since we're dealing with bridges, we can't assume width is larger than spacing,
 | ||||
|             // so we take the largest value and also apply safety offset to be ensure no gaps
 | ||||
|             // are left in between
 | ||||
|         Flow bridge_flow = layerm->bridging_flow(frPerimeter, g_config_thick_bridges); | ||||
|         Flow bridge_flow = layerm->bridging_flow(frPerimeter, object_config.thick_bridges); | ||||
|         float w = float(std::max(bridge_flow.scaled_width(), bridge_flow.scaled_spacing())); | ||||
|         for (Polyline& polyline : overhang_perimeters) | ||||
|             if (polyline.is_straight()) { | ||||
|  | @ -2338,12 +2341,16 @@ void PrintObject::remove_bridges_from_contacts( | |||
|                 if (supported[0] && supported[1]) { | ||||
|                     Polylines lines; | ||||
|                     if (polyline.length() > max_bridge_length + 10) { | ||||
|                         // equally divide the polyline
 | ||||
|                         float len = polyline.length() / ceil(polyline.length() / max_bridge_length); | ||||
|                         lines = polyline.equally_spaced_lines(len); | ||||
|                         for (auto& line : lines) { | ||||
|                             line.clip_start(fw); | ||||
|                             line.clip_end(fw); | ||||
|                         if (break_bridge) { | ||||
|                             // equally divide the polyline
 | ||||
|                             float len = polyline.length() / ceil(polyline.length() / max_bridge_length); | ||||
|                             lines = polyline.equally_spaced_lines(len); | ||||
|                             for (auto& line : lines) { | ||||
|                                 if (line.is_valid()) | ||||
|                                     line.clip_start(fw); | ||||
|                                 if (line.is_valid()) | ||||
|                                     line.clip_end(fw); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|  | @ -2357,8 +2364,52 @@ void PrintObject::remove_bridges_from_contacts( | |||
|         // remove the entire bridges and only support the unsupported edges
 | ||||
|         //FIXME the brided regions are already collected as layerm->bridged. Use it?
 | ||||
|         for (const Surface& surface : layerm->fill_surfaces.surfaces) | ||||
|             if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) | ||||
|                 polygons_append(bridges, surface.expolygon); | ||||
|             if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) { | ||||
|                 auto bbox      = get_extents(surface.expolygon); | ||||
|                 auto bbox_size = bbox.size(); | ||||
|                 if (bbox_size[0] < max_bridge_length || bbox_size[1] < max_bridge_length) | ||||
|                     polygons_append(bridges, surface.expolygon); | ||||
|                 else { | ||||
|                     if (break_bridge) { | ||||
|                         Polygons holes; | ||||
|                         int      x0 = bbox.min.x(); | ||||
|                         int      x1 = bbox.max.x(); | ||||
|                         int      y0 = bbox.min.y(); | ||||
|                         int      y1 = bbox.max.y();          | ||||
|                         const int grid_lw = int(w/2); // grid line width
 | ||||
|                          | ||||
| #if 1 | ||||
|                         if (fabs(surface.bridge_angle-0)<fabs(surface.bridge_angle-M_PI_2)) { | ||||
|                             int step = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length); | ||||
|                             for (int x = x0 + step; x < x1; x += step) { | ||||
|                                 Polygon poly; | ||||
|                                 poly.points = {Point(x - grid_lw, y0), Point(x + grid_lw, y0), Point(x + grid_lw, y1), Point(x - grid_lw, y1)}; | ||||
|                                 holes.emplace_back(poly); | ||||
|                             } | ||||
|                         } else { | ||||
|                             int step = bbox_size(1) / ceil(bbox_size(1) / max_bridge_length); | ||||
|                             for (int y = y0 + step; y < y1; y += step) { | ||||
|                                 Polygon poly; | ||||
|                                 poly.points = {Point(x0, y - grid_lw), Point(x0, y + grid_lw), Point(x1, y + grid_lw), Point(x1, y - grid_lw)}; | ||||
|                                 holes.emplace_back(poly); | ||||
|                             } | ||||
|                         } | ||||
| #else | ||||
|                         int stepx = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length); | ||||
|                         int stepy  = bbox_size(1) / ceil(bbox_size(1) / max_bridge_length); | ||||
|                         for (int x = x0 + stepx; x < x1; x += stepx) | ||||
|                             for (int y = y0 + stepy; y < y1; y += stepy) { | ||||
|                                 Polygon poly; | ||||
|                                 poly.points = {Point(x-grid_lw, y - grid_lw), Point(x+grid_lw, y - grid_lw), Point(x+grid_lw, y + grid_lw), Point(x-grid_lw, y + grid_lw)}; | ||||
|                                 holes.emplace_back(poly); | ||||
|                             } | ||||
| 
 | ||||
| #endif | ||||
|                         auto expoly = diff_ex(surface.expolygon, holes); | ||||
|                         polygons_append(bridges, expoly); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         //FIXME add the gap filled areas. Extrude the gaps with a bridge flow?
 | ||||
|         // Remove the unsupported ends of the bridges from the bridged areas.
 | ||||
|         //FIXME add supports at regular intervals to support long bridges!
 | ||||
|  | @ -2380,13 +2431,13 @@ template void PrintObject::remove_bridges_from_contacts<ExPolygons>( | |||
|     const Layer* current_layer, | ||||
|     float extrusion_width, | ||||
|     ExPolygons* overhang_regions, | ||||
|     float max_bridge_length); | ||||
|     float max_bridge_length, bool break_bridge); | ||||
| template void PrintObject::remove_bridges_from_contacts<Polygons>( | ||||
|     const Layer* lower_layer, | ||||
|     const Layer* current_layer, | ||||
|     float extrusion_width, | ||||
|     Polygons* overhang_regions, | ||||
|     float max_bridge_length); | ||||
|     float max_bridge_length, bool break_bridge); | ||||
| 
 | ||||
| 
 | ||||
| bool PrintObject::is_support_necessary() | ||||
|  | @ -2721,4 +2772,20 @@ const Layer *PrintObject::get_first_layer_bellow_printz(coordf_t print_z, coordf | |||
|     return (it == m_layers.begin()) ? nullptr : *(--it); | ||||
| } | ||||
| 
 | ||||
| // BBS
 | ||||
| const Layer* PrintObject::get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon) const { | ||||
|     coordf_t limit_upper = bottom_z + epsilon; | ||||
|     coordf_t limit_lower = bottom_z - epsilon; | ||||
| 
 | ||||
|     for (const Layer* layer : m_layers) { | ||||
|         if (layer->bottom_z() > limit_lower) | ||||
|             return layer->bottom_z() < limit_upper ? layer : nullptr; | ||||
|     } | ||||
| 
 | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| Layer* PrintObject::get_layer_at_bottomz(coordf_t bottom_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_bottomz(bottom_z, epsilon)); } | ||||
| 
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -446,6 +446,9 @@ static std::vector<std::vector<ExPolygons>> slices_to_regions( | |||
| std::string fix_slicing_errors(PrintObject* object, LayerPtrs &layers, const std::function<void()> &throw_if_canceled) | ||||
| { | ||||
|     std::string error_msg;//BBS
 | ||||
| 
 | ||||
|     if (layers.size() == 0) return error_msg; | ||||
| 
 | ||||
|     // Collect layers with slicing errors.
 | ||||
|     // These layers will be fixed in parallel.
 | ||||
|     std::vector<size_t> buggy_layers; | ||||
|  | @ -740,24 +743,39 @@ static inline void apply_mm_segmentation(PrintObject &print_object, ThrowOnCance | |||
| bool doesVolumeIntersect(VolumeSlices& vs1, VolumeSlices& vs2) | ||||
| { | ||||
|     if (vs1.volume_id == vs2.volume_id) return true; | ||||
|     if (vs1.slices.size() != vs1.slices.size()) return false; | ||||
|     if (vs1.slices.size() != vs2.slices.size()) return false; | ||||
| 
 | ||||
|     double offsetValue = 0.4 / SCALING_FACTOR; | ||||
|     for (int i = 0; i != vs1.slices.size(); ++i) { | ||||
|         auto eps1 = offset_ex(vs1.slices[i], offsetValue); | ||||
|         auto eps2 = offset_ex(vs2.slices[i], offsetValue); | ||||
| 
 | ||||
|         if (!intersection_ex(eps1, eps2).empty()) return true; | ||||
|         if (vs1.slices[i].empty()) continue; | ||||
|         if (!vs2.slices[i].empty() && !intersection_ex(vs1.slices[i], vs2.slices[i]).empty()) return true; | ||||
|         if (i + 1 != vs2.slices.size() && !vs2.slices[i + 1].empty()) { | ||||
|             if (!intersection_ex(vs1.slices[i], vs2.slices[i + 1]).empty()) return true; | ||||
|         } | ||||
|         if (i - 1 >= 0 && !vs2.slices[i - 1].empty()) { | ||||
|             if (!intersection_ex(vs1.slices[i], vs2.slices[i - 1]).empty()) return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| //BBS: grouping the volumes of an object according to their connection relationship
 | ||||
| bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<groupedVolumeSlices>& groups) | ||||
| bool groupingVolumes(std::vector<VolumeSlices> objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution) | ||||
| { | ||||
|     int existGroups = 0; | ||||
|     std::vector<int> groupIndex(objSliceByVolume.size(), -1); | ||||
| 
 | ||||
|     double offsetValue = 0.4 / SCALING_FACTOR; | ||||
| 
 | ||||
|     for (int i = 0; i != objSliceByVolume.size(); ++i) { | ||||
|         for (int j = 0; j != objSliceByVolume[i].slices.size(); ++j) { | ||||
|             objSliceByVolume[i].slices[j] = offset_ex(objSliceByVolume[i].slices[j], offsetValue); | ||||
|             for (ExPolygon& poly_ex : objSliceByVolume[i].slices[j]) | ||||
|                 poly_ex.douglas_peucker(resolution); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i != objSliceByVolume.size(); ++i) { | ||||
|         if (groupIndex[i] < 0) { | ||||
|             groupIndex[i] = i; | ||||
|  | @ -765,7 +783,7 @@ bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<gr | |||
|         } | ||||
|         for (int j = i + 1; j != objSliceByVolume.size(); ++j) { | ||||
|             if (doesVolumeIntersect(objSliceByVolume[i], objSliceByVolume[j])) { | ||||
|                 if (groupIndex[j] < 0) groupIndex[j] = i; | ||||
|                 if (groupIndex[j] < 0) groupIndex[j] = groupIndex[i]; | ||||
|                 if (groupIndex[j] != groupIndex[i]) { | ||||
|                     int retain = std::min(groupIndex[i], groupIndex[j]); | ||||
|                     int cover = std::max(groupIndex[i], groupIndex[j]); | ||||
|  | @ -791,9 +809,6 @@ bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<gr | |||
|         if (!exist) groupVector.push_back(gi); | ||||
|     } | ||||
| 
 | ||||
|     if (groupVector.size() != existGroups); | ||||
| 
 | ||||
| 
 | ||||
|     // group volumes and their slices according to the grouping Vector
 | ||||
|     groups.clear(); | ||||
| 
 | ||||
|  | @ -808,9 +823,7 @@ bool groupingVolumes(std::vector<VolumeSlices>& objSliceByVolume, std::vector<gr | |||
|         } | ||||
| 
 | ||||
|         // the slices of a group should be unioned
 | ||||
|         double offsetValue = 0.4 / SCALING_FACTOR; | ||||
|         gvs.slices = offset_ex(union_ex(offset_ex(gvs.slices, offsetValue)), -offsetValue); | ||||
|         double resolution = 0.0125 / SCALING_FACTOR; | ||||
|         gvs.slices = offset_ex(union_ex(gvs.slices), -offsetValue); | ||||
|         for (ExPolygon& poly_ex : gvs.slices) | ||||
|             poly_ex.douglas_peucker(resolution); | ||||
| 
 | ||||
|  | @ -830,6 +843,24 @@ std::vector<VolumeSlices> findPartVolumes(const std::vector<VolumeSlices>& objSl | |||
|     return outPut; | ||||
| } | ||||
| 
 | ||||
| void applyNegtiveVolumes(ModelVolumePtrs model_volumes, const std::vector<VolumeSlices>& objSliceByVolume, std::vector<groupedVolumeSlices>& groups, double resolution) { | ||||
|     ExPolygons negTotal; | ||||
|     for (const auto& vs : objSliceByVolume) { | ||||
|         for (const auto& mv : model_volumes) { | ||||
|             if (vs.volume_id == mv->id() && mv->is_negative_volume()) { | ||||
|                 if (vs.slices.size() > 0) { | ||||
|                     append(negTotal, vs.slices.front()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for (auto& g : groups) { | ||||
|         g.slices = diff_ex(g.slices, negTotal); | ||||
|         for (ExPolygon& poly_ex : g.slices) | ||||
|             poly_ex.douglas_peucker(resolution); | ||||
|     } | ||||
| } | ||||
| // 1) Decides Z positions of the layers,
 | ||||
| // 2) Initializes layers and their regions
 | ||||
| // 3) Slices the object meshes
 | ||||
|  | @ -873,9 +904,10 @@ void PrintObject::slice_volumes() | |||
|     } | ||||
| 
 | ||||
|     //BBS: "model_part" volumes are grouded according to their connections
 | ||||
|     const auto           scaled_resolution = scaled<double>(print->config().resolution.value); | ||||
|     std::vector<VolumeSlices> objSliceByVolumeParts = findPartVolumes(objSliceByVolume, this->model_object()->volumes); | ||||
|     groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups); | ||||
| 
 | ||||
|     groupingVolumes(objSliceByVolumeParts, firstLayerObjSliceByGroups, scaled_resolution); | ||||
|     applyNegtiveVolumes(this->model_object()->volumes, objSliceByVolume, firstLayerObjSliceByGroups, scaled_resolution); | ||||
| 
 | ||||
|     std::vector<std::vector<ExPolygons>> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs, | ||||
|         std::move(objSliceByVolume), | ||||
|  |  | |||
|  | @ -29,12 +29,13 @@ enum MachineBedType { | |||
| 
 | ||||
| struct FilamentInfo | ||||
| { | ||||
|     int         id; // filament id = extruder id, start with 0.
 | ||||
|     int         id;         // filament id = extruder id, start with 0.
 | ||||
|     std::string type; | ||||
|     std::string color; | ||||
|     float       used_m; | ||||
|     float       used_g; | ||||
|     int         tray_id; | ||||
|     int         tray_id;    // start with 0
 | ||||
|     float       distance; | ||||
| }; | ||||
| 
 | ||||
| class BBLSliceInfo { | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ public: | |||
|     float height; | ||||
|     bool  flipY; | ||||
| 
 | ||||
|     SVG() = default; | ||||
|     SVG(const char* afilename) : | ||||
|         arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false) | ||||
|         { open(filename); } | ||||
|  |  | |||
|  | @ -118,10 +118,11 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters | |||
|             sp1.first_print_layer_height            == sp2.first_print_layer_height             && | ||||
|             sp1.first_object_layer_height           == sp2.first_object_layer_height            && | ||||
|             sp1.first_object_layer_bridging         == sp2.first_object_layer_bridging          && | ||||
|             // BBS: following  are not required for equal layer height.
 | ||||
|             // Since the z-gap diff may be multiple of layer height.
 | ||||
| #if 0 | ||||
|             sp1.soluble_interface                   == sp2.soluble_interface                    && | ||||
|             sp1.gap_raft_object                     == sp2.gap_raft_object                      && | ||||
|             // BBS
 | ||||
| #if 0 | ||||
|             sp1.gap_object_support                  == sp2.gap_object_support                   && | ||||
|             sp1.gap_support_object                  == sp2.gap_support_object                   && | ||||
| #endif | ||||
|  |  | |||
|  | @ -379,7 +379,7 @@ PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object | |||
|     m_support_params.gap_xy = m_object_config->support_object_xy_distance.value; | ||||
|     bridge_flow /= object->num_printing_regions(); | ||||
| 
 | ||||
|     m_support_params.support_material_bottom_interface_flow = m_slicing_params.soluble_interface || ! g_config_thick_bridges ? | ||||
|     m_support_params.support_material_bottom_interface_flow = m_slicing_params.soluble_interface || ! m_object_config->thick_bridges ? | ||||
|         m_support_params.support_material_interface_flow.with_flow_ratio(bridge_flow) : | ||||
|         Flow::bridging_flow(bridge_flow * m_support_params.support_material_interface_flow.nozzle_diameter(), m_support_params.support_material_interface_flow.nozzle_diameter()); | ||||
| 
 | ||||
|  | @ -1339,7 +1339,7 @@ namespace SupportMaterialInternal { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static void remove_bridges_from_contactsxx( | ||||
|     static void remove_bridges_from_contacts( | ||||
|         const PrintConfig   &print_config,  | ||||
|         const Layer         &lower_layer, | ||||
|         const Polygons      &lower_layer_polygons, | ||||
|  | @ -1374,7 +1374,9 @@ namespace SupportMaterialInternal { | |||
|             // since we're dealing with bridges, we can't assume width is larger than spacing,
 | ||||
|             // so we take the largest value and also apply safety offset to be ensure no gaps
 | ||||
|             // are left in between
 | ||||
|             Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter, g_config_thick_bridges); | ||||
|             // BBS
 | ||||
|             const PrintObjectConfig& object_config = layerm.layer()->object()->config(); | ||||
|             Flow perimeter_bridge_flow = layerm.bridging_flow(frPerimeter, object_config.thick_bridges); | ||||
|             //FIXME one may want to use a maximum of bridging flow width and normal flow width, as the perimeters are calculated using the normal flow
 | ||||
|             // and then turned to bridging flow, thus their centerlines are derived from non-bridging flow and expanding them by a bridging flow
 | ||||
|             // may not expand them to the edge of their respective islands.
 | ||||
|  | @ -1509,7 +1511,7 @@ static inline Polygons detect_overhangs( | |||
|         M_PI * double(object_config.support_threshold_angle.value + 1) / 180. : // +1 makes the threshold inclusive
 | ||||
|         0.; | ||||
|     const coordf_t max_bridge_length = scale_(object_config.max_bridge_length.value); | ||||
|     const bool bridge_no_support = max_bridge_length > 0;// config.bridge_no_support.value;
 | ||||
|     const bool bridge_no_support = object_config.bridge_no_support.value; | ||||
| 
 | ||||
|     if (layer_id == 0)  | ||||
|     { | ||||
|  | @ -1667,7 +1669,8 @@ static inline Polygons detect_overhangs( | |||
| 
 | ||||
|             if (bridge_no_support) { | ||||
|                 //FIXME Expensive, potentially not precise enough. Misses gap fill extrusions, which bridge.
 | ||||
|                 PrintObject::remove_bridges_from_contacts(&lower_layer, &layer, fw, &diff_polygons, max_bridge_length); | ||||
|                 SupportMaterialInternal::remove_bridges_from_contacts( | ||||
|                     print_config, lower_layer, lower_layer_polygons, *layerm, fw, diff_polygons); | ||||
|             } | ||||
| 
 | ||||
|             if (diff_polygons.empty() || offset(diff_polygons, -0.1 * fw).empty()) | ||||
|  | @ -1861,7 +1864,7 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport | |||
| 
 | ||||
|         // Contact layer will be printed with a normal flow, but
 | ||||
|         // it will support layers printed with a bridging flow.
 | ||||
|         if (g_config_thick_bridges && SupportMaterialInternal::has_bridging_extrusions(layer)) { | ||||
|         if (object_config.thick_bridges && SupportMaterialInternal::has_bridging_extrusions(layer)) { | ||||
|             coordf_t bridging_height = 0.; | ||||
|             for (const LayerRegion* region : layer.regions()) | ||||
|                 bridging_height += region->region().bridging_height_avg(print_config); | ||||
|  | @ -2429,7 +2432,7 @@ static inline PrintObjectSupportMaterial::MyLayer* detect_bottom_contacts( | |||
|         layer.print_z + layer_new.height + slicing_params.gap_object_support; | ||||
|     layer_new.bottom_z = layer.print_z; | ||||
|     layer_new.idx_object_layer_below = layer_id; | ||||
|     layer_new.bridging = !slicing_params.soluble_interface && g_config_thick_bridges; | ||||
|     layer_new.bridging = !slicing_params.soluble_interface && object.config().thick_bridges; | ||||
|     //FIXME how much to inflate the bottom surface, as it is being extruded with a bridging flow? The following line uses a normal flow.
 | ||||
|     layer_new.polygons = expand(touching, float(support_params.support_material_flow.scaled_width()), SUPPORT_SURFACES_OFFSET_PARAMETERS); | ||||
| 
 | ||||
|  | @ -3234,7 +3237,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( | |||
|                         polygons_append(polygons_trimming, offset({ expoly }, trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS)); | ||||
|                     } | ||||
|                 } | ||||
|                 if (! m_slicing_params.soluble_interface && g_config_thick_bridges) { | ||||
|                 if (! m_slicing_params.soluble_interface && m_object_config->thick_bridges) { | ||||
|                     // Collect all bottom surfaces, which will be extruded with a bridging flow.
 | ||||
|                     for (; i < object.layers().size(); ++ i) { | ||||
|                         const Layer &object_layer = *object.layers()[i]; | ||||
|  | @ -4515,6 +4518,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( | |||
|                         angles[support_layer_id % angles.size()] : | ||||
|                         // Use interface angle for the interface layers.
 | ||||
|                         m_support_params.interface_angle + interface_angle_delta; | ||||
| 
 | ||||
|                 double density = interface_as_base ? m_support_params.support_density : m_support_params.interface_density; | ||||
|                 filler_interface->spacing = interface_as_base ? m_support_params.support_material_flow.spacing() : m_support_params.support_material_interface_flow.spacing(); | ||||
|                 filler_interface->link_max_length = coord_t(scale_(filler_interface->spacing * link_max_length_factor / density)); | ||||
|  |  | |||
|  | @ -9,15 +9,11 @@ | |||
| #include "SVG.hpp" | ||||
| #include "ShortestPath.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include <libnest2d/backends/libslic3r/geometries.hpp> | ||||
| 
 | ||||
| #define _L(s) Slic3r::I18N::translate(s) | ||||
| 
 | ||||
| #define SQUARE_SUPPORT 0 | ||||
| #if SQUARE_SUPPORT | ||||
| #define CIRCLE_RESOLUTION 4 // 100 //The number of vertices in each circle.
 | ||||
| #else | ||||
| #define CIRCLE_RESOLUTION 100 //The number of vertices in each circle.
 | ||||
| #endif | ||||
| 
 | ||||
| #define MAX_BRANCH_RADIUS 10.0 | ||||
| #define HEIGHT_TO_SWITCH_INFILL_DIRECTION 30 // change infill direction every 20mm
 | ||||
| #define DO_NOT_MOVER_UNDER_MM 5 // do not move contact points under 5mm
 | ||||
|  | @ -31,7 +27,7 @@ | |||
| #define TAU (2.0 * M_PI) | ||||
| #define NO_INDEX (std::numeric_limits<unsigned int>::max()) | ||||
| 
 | ||||
| //#define SUPPORT_TREE_DEBUG_TO_SVG
 | ||||
| #define SUPPORT_TREE_DEBUG_TO_SVG | ||||
| 
 | ||||
| namespace Slic3r | ||||
| { | ||||
|  | @ -225,14 +221,18 @@ static void draw_contours_and_nodes_to_svg | |||
|     bbox.max.x() = std::max(bbox.max.x(), (coord_t)scale_(10)); | ||||
|     bbox.max.y() = std::max(bbox.max.y(), (coord_t)scale_(10)); | ||||
| 
 | ||||
|     SVG svg(get_svg_filename(std::to_string(layer_nr), name_prefix), bbox); | ||||
|     SVG svg; | ||||
|     if(layer_nr>=0) | ||||
|         svg.open(get_svg_filename(std::to_string(layer_nr), name_prefix), bbox); | ||||
|     else | ||||
|         svg.open(name_prefix, bbox); | ||||
|     if (!svg.is_opened())        return; | ||||
| 
 | ||||
|     // draw grid
 | ||||
|     svg.draw_grid(bbox, "gray", coord_t(scale_(0.05))); | ||||
| 
 | ||||
|     // draw overhang areas
 | ||||
|     svg.draw(union_ex(overhangs), colors[0]); | ||||
|     svg.draw_outline(union_ex(overhangs), colors[0]); | ||||
|     svg.draw_outline(union_ex(overhangs_after_offset), colors[1]); | ||||
|     svg.draw_outline(outlines_below, colors[2]); | ||||
| 
 | ||||
|  | @ -661,6 +661,8 @@ void TreeSupport::detect_object_overhangs() | |||
| 
 | ||||
|     // Create Tree Support Layers
 | ||||
|     m_object->clear_tree_support_layers(); | ||||
|     m_object->clear_tree_support_preview_cache(); | ||||
| 
 | ||||
|     create_tree_support_layers(); | ||||
|     m_ts_data = m_object->alloc_tree_support_preview_cache(); | ||||
| 
 | ||||
|  | @ -932,7 +934,7 @@ void TreeSupport::detect_object_overhangs() | |||
| 
 | ||||
| 
 | ||||
|             if (bridge_no_support && overhang_areas.size()>0) { | ||||
|                 m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length); | ||||
|                 m_object->remove_bridges_from_contacts(lower_layer, layer, extrusion_width_scaled, &overhang_areas, max_bridge_length, true); | ||||
|             } | ||||
| 
 | ||||
|             TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers); | ||||
|  | @ -1081,9 +1083,6 @@ void TreeSupport::detect_object_overhangs() | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     total_overhang_area = 0; | ||||
|     max_overhang_area = 0; | ||||
|     total_overhang_layer_cnt = 0; | ||||
|     for (int layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) { | ||||
|         if (m_object->print()->canceled()) | ||||
|             break; | ||||
|  | @ -1095,6 +1094,10 @@ void TreeSupport::detect_object_overhangs() | |||
|             ts_layer->overhang_areas = diff_ex(ts_layer->overhang_areas, offset_ex(blocker, scale_(radius_sample_resolution))); | ||||
|         } | ||||
| 
 | ||||
|         for (auto &area : ts_layer->overhang_areas) { | ||||
|             ts_layer->overhang_types.emplace(&area, TreeSupportLayer::Detected); | ||||
|         } | ||||
| 
 | ||||
|         if (layer_nr < enforcers.size()) { | ||||
|             Polygons& enforcer = enforcers[layer_nr]; | ||||
|             // coconut: enforcer can't do offset2_ex, otherwise faces with angle near 90 degrees can't have enforcers, which
 | ||||
|  | @ -1102,15 +1105,9 @@ void TreeSupport::detect_object_overhangs() | |||
|             //enforcer = std::move(offset2_ex(enforcer, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled));
 | ||||
|             for (const Polygon& poly : enforcer) { | ||||
|                 ts_layer->overhang_areas.emplace_back(poly); | ||||
|                 ts_layer->overhang_types.emplace(&ts_layer->overhang_areas.back(), TreeSupportLayer::Enforced); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!ts_layer->overhang_areas.empty()) { | ||||
|             float a = area(ts_layer->overhang_areas); | ||||
|             total_overhang_area += a; | ||||
|             max_overhang_area = std::max(max_overhang_area, a); | ||||
|             total_overhang_layer_cnt++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| #ifdef SUPPORT_TREE_DEBUG_TO_SVG | ||||
|  | @ -1825,17 +1822,25 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no | |||
| { | ||||
|     const PrintObjectConfig &config = m_object->config(); | ||||
|     bool has_brim = m_object->print()->has_brim(); | ||||
|     bool has_infill = config.tree_support_with_infill.value; | ||||
|     int bottom_gap_layers = round(m_slicing_params.gap_object_support / m_slicing_params.layer_height); | ||||
|     const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2; | ||||
|     const coordf_t branch_radius_scaled = scale_(branch_radius); | ||||
|     Polygon branch_circle; //Pre-generate a circle with correct diameter so that we don't have to recompute those (co)sines every time.
 | ||||
| 
 | ||||
|     // Use square support if there are too many nodes per layer because circle support needs much longer time to compute
 | ||||
|     // Hower circle support can be printed faster, so we prefer circle for fewer nodes case.
 | ||||
|     const bool SQUARE_SUPPORT = avg_node_per_layer > 200;     | ||||
|     const int  CIRCLE_RESOLUTION = SQUARE_SUPPORT ? 4 : 100; // The number of vertices in each circle.
 | ||||
| 
 | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++) | ||||
|     { | ||||
| #if SQUARE_SUPPORT | ||||
|         double angle = (double)i / CIRCLE_RESOLUTION * TAU + TAU/8.0; | ||||
| #else | ||||
|         double angle = (double)i / CIRCLE_RESOLUTION * TAU; | ||||
| #endif | ||||
|         double angle; | ||||
|         if (SQUARE_SUPPORT) | ||||
|             angle = (double) i / CIRCLE_RESOLUTION * TAU + PI / 4.0 + nodes_angle; | ||||
|         else | ||||
|             angle = (double) i / CIRCLE_RESOLUTION * TAU; | ||||
|         branch_circle.append(Point(cos(angle) * branch_radius_scaled, sin(angle) * branch_radius_scaled)); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1850,7 +1855,6 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no | |||
|     } | ||||
| 
 | ||||
|     // generate areas
 | ||||
|     const coordf_t circle_side_length = 2 * branch_radius * sin(M_PI / CIRCLE_RESOLUTION); //Side length of a regular polygon.
 | ||||
|     const coordf_t layer_height = config.layer_height.value; | ||||
|     const size_t   top_interface_layers = config.support_interface_top_layers.value; | ||||
|     const size_t   bottom_interface_layers = config.support_interface_bottom_layers.value; | ||||
|  | @ -2024,16 +2028,12 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no | |||
|                 base_areas = std::move(diff_ex(base_areas, roof_areas)); | ||||
|                 base_areas = std::move(diff_ex(base_areas, roof_1st_layer)); | ||||
| 
 | ||||
| #if SQUARE_SUPPORT | ||||
|                 if (m_object->print()->config().enable_arc_fitting.value == false) { | ||||
|                     // simplify support contours if arc fitting is disabled
 | ||||
|                 if (SQUARE_SUPPORT) { | ||||
|                     // simplify support contours
 | ||||
|                     ExPolygons base_areas_simplified; | ||||
|                     for (auto& area : base_areas) { | ||||
|                         area.simplify(scale_(line_width / 2), &base_areas_simplified, SimplifyMethodDP); | ||||
|                     } | ||||
|                     for (auto &area : base_areas) { area.simplify(scale_(line_width / 2), &base_areas_simplified, SimplifyMethodDP); } | ||||
|                     base_areas = std::move(base_areas_simplified); | ||||
|                 } | ||||
| #endif | ||||
|                 //Subtract support floors. We can only compute floor_areas here instead of with roof_areas,
 | ||||
|                 // or we'll get much wider floor than necessary.
 | ||||
|                 if (bottom_interface_layers + bottom_gap_layers > 0) | ||||
|  | @ -2073,15 +2073,13 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no | |||
|                                                        }), | ||||
|                                         expoly->holes.end()); | ||||
|                 } | ||||
| #ifdef SUPPORT_TREE_DEBUG_TO_SVG | ||||
|                 draw_contours_and_nodes_to_svg(layer_nr, base_areas, roof_areas, roof_1st_layer, {}, {}, "circles", { "base","roof","roof1st" }); | ||||
| #endif | ||||
| 
 | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
| #if 1 | ||||
|         // move the holes to contour so they can be well supported
 | ||||
| 
 | ||||
|     if (!has_infill) { | ||||
|         // check if poly's contour intersects with expoly's contour
 | ||||
|         auto intersects_contour = [](Polygon poly, ExPolygon expoly, Point &pt_on_poly, Point &pt_on_expoly, Point &pt_far_on_poly, float dist_thresh = 0.01) { | ||||
|             float min_dist = std::numeric_limits<float>::max(); | ||||
|  | @ -2099,18 +2097,15 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no | |||
|                         max_dist       = dist2; | ||||
|                         pt_far_on_poly = from; | ||||
|                     } | ||||
|                     if (dist2 < dist_thresh) {  | ||||
|                         return true; | ||||
|                     } | ||||
|                     if (dist2 < dist_thresh) { return true; } | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         }; | ||||
| 
 | ||||
|         std::map<const Polygon *, int> holeDepth; | ||||
|         std::map<const Polygon *, Point> holeDiretions; | ||||
|         std::map<const Polygon *, Point> holeFarPoints; | ||||
|         for (int layer_nr = m_object->layer_count()-1; layer_nr >0; layer_nr--) { | ||||
|         // polygon pointer: depth, direction, farPoint
 | ||||
|         std::map<const Polygon *, std::tuple<int, Point, Point>> holePropagationInfos; | ||||
|         for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) { | ||||
|             if (print->canceled()) break; | ||||
|             m_object->print()->set_status(66, (boost::format(_L("Support: fix holes at layer %d")) % layer_nr).str()); | ||||
| 
 | ||||
|  | @ -2127,47 +2122,88 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no | |||
|             for (layer_nr_lower; layer_nr_lower >= 0; layer_nr_lower--) { | ||||
|                 if (!m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups.empty()) break; | ||||
|             } | ||||
|             auto & area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups; | ||||
|             auto &area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups; | ||||
| 
 | ||||
|             for (const auto& area_group:ts_layer->area_groups){ | ||||
|                 if (area_group.second == 1 || area_group.second == 2) continue; | ||||
|                 const auto base_area = area_group.first; | ||||
|                 for (const auto &hole : base_area->holes) { | ||||
|             for (const auto &area_group : ts_layer->area_groups) { | ||||
|                 if (area_group.second != TreeSupportLayer::BaseType) continue; | ||||
|                 const auto area = area_group.first; | ||||
|                 for (const auto &hole : area->holes) { | ||||
|                     // auto hole_bbox = get_extents(hole).polygon();
 | ||||
|                     for (auto & area_group_lower: area_groups_lower) { | ||||
|                         if (area_group.second == 1 || area_group.second == 2) continue; | ||||
|                     for (auto &area_group_lower : area_groups_lower) { | ||||
|                         if (area_group.second != TreeSupportLayer::BaseType) continue; | ||||
|                         auto &base_area_lower = *area_group_lower.first; | ||||
|                         Point pt_on_poly, pt_on_expoly, pt_far_on_poly; | ||||
|                         // if a hole doesn't intersect with lower layer's contours, add a hole to lower layer and move it slightly to the contour
 | ||||
|                         if (base_area_lower.contour.contains(hole.points.front()) && !intersects_contour(hole, base_area_lower, pt_on_poly, pt_on_expoly, pt_far_on_poly)) { | ||||
|                             Polygon hole_lower = hole; | ||||
|                             Point   direction  = normal(pt_on_expoly - pt_on_poly, line_width_scaled/2); | ||||
|                             Point   direction  = normal(pt_on_expoly - pt_on_poly, line_width_scaled / 2); | ||||
|                             hole_lower.translate(direction); | ||||
|                             // note to expand a hole, we need to do negative offset
 | ||||
|                             auto hole_expanded = offset(hole_lower, -line_width_scaled / 4, ClipperLib::JoinType::jtSquare); | ||||
|                             if (!hole_expanded.empty()) { | ||||
|                                 base_area_lower.holes.push_back(std::move(hole_expanded[0])); | ||||
|                                 holeDepth.insert({&base_area_lower.holes.back(), 15}); | ||||
|                                 holeDiretions.insert({&base_area_lower.holes.back(), direction}); | ||||
|                                 holeFarPoints.insert({&base_area_lower.holes.back(), pt_far_on_poly}); | ||||
|                                 holePropagationInfos.insert({&base_area_lower.holes.back(), {25, direction, pt_far_on_poly}}); | ||||
|                             } | ||||
|                             break; | ||||
|                         } else if (holeDepth.find(&hole) != holeDepth.end() && holeDepth[&hole] > 0 && base_area_lower.contour.contains(holeFarPoints[&hole])) { | ||||
|                         } else if (holePropagationInfos.find(&hole) != holePropagationInfos.end() && std::get<0>(holePropagationInfos[&hole]) > 0 && | ||||
|                                    base_area_lower.contour.contains(std::get<2>(holePropagationInfos[&hole]))) { | ||||
|                             Polygon hole_lower = hole; | ||||
|                             hole_lower.translate(holeDiretions[&hole]); | ||||
|                             Point farPoint = holeFarPoints[&hole] + holeDiretions[&hole]; | ||||
|                             { | ||||
|                                 base_area_lower.holes.push_back(std::move(hole_lower)); | ||||
|                                 holeDepth.insert({&base_area_lower.holes.back(), holeDepth[&hole]-1}); | ||||
|                                 holeDiretions.insert({&base_area_lower.holes.back(), holeDiretions[&hole]}); | ||||
|                                 holeFarPoints.insert({&base_area_lower.holes.back(), farPoint}); | ||||
|                             auto && direction  = std::get<1>(holePropagationInfos[&hole]); | ||||
|                             hole_lower.translate(direction); | ||||
|                             // note to shrink a hole, we need to do positive offset
 | ||||
|                             auto  hole_expanded = offset(hole_lower, line_width_scaled / 2, ClipperLib::JoinType::jtSquare); | ||||
|                             Point farPoint      = std::get<2>(holePropagationInfos[&hole]) + direction * 2; | ||||
|                             if (!hole_expanded.empty()) { | ||||
|                                 base_area_lower.holes.push_back(std::move(hole_expanded[0])); | ||||
|                                 holePropagationInfos.insert({&base_area_lower.holes.back(), {std::get<0>(holePropagationInfos[&hole]) - 1, direction, farPoint}}); | ||||
|                             } | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     { | ||||
|                         // if roof1 interface is inside a hole, need to expand the interface
 | ||||
|                         for (auto &roof1 : ts_layer->roof_1st_layer) { | ||||
|                             //if (hole.contains(roof1.contour.points.front()) && hole.contains(roof1.contour.bounding_box().center())) 
 | ||||
|                             bool is_inside_hole = std::all_of(roof1.contour.points.begin(), roof1.contour.points.end(), [&hole](Point &pt) { return hole.contains(pt); }); | ||||
|                             if (is_inside_hole) { | ||||
|                                 Polygon hole_reoriented = hole; | ||||
|                                 if (roof1.contour.is_counter_clockwise()) | ||||
|                                     hole_reoriented.make_counter_clockwise(); | ||||
|                                 else if (roof1.contour.is_clockwise()) | ||||
|                                     hole_reoriented.make_clockwise(); | ||||
|                                 auto tmp = union_({roof1.contour}, {hole_reoriented}); | ||||
|                                 if (!tmp.empty()) roof1.contour = tmp[0]; | ||||
| 
 | ||||
|                                 // make sure 1) roof1 and object 2) roof1 and roof, won't intersect
 | ||||
|                                 // Note: We can't replace roof1 directly, as we have recorded its address.
 | ||||
|                                 //       So instead we need to replace its members one by one.
 | ||||
|                                 auto tmp1 = diff_ex(roof1, m_ts_data->get_collision((layer_nr == 0 && has_brim) ? config.brim_object_gap : m_ts_data->m_xy_distance, layer_nr)); | ||||
|                                 tmp1 = diff_ex(tmp1, ts_layer->roof_areas); | ||||
|                                 if (!tmp1.empty()) { | ||||
|                                     roof1.contour = std::move(tmp1[0].contour); | ||||
|                                     roof1.holes   = std::move(tmp1[0].holes); | ||||
|                                 } | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SUPPORT_TREE_DEBUG_TO_SVG | ||||
|         for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) { | ||||
|             TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers); | ||||
|             ExPolygons& base_areas = ts_layer->base_areas; | ||||
|             ExPolygons& roof_areas = ts_layer->roof_areas; | ||||
|             ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer; | ||||
|             ExPolygons& floor_areas = ts_layer->floor_areas; | ||||
|             if (base_areas.empty() && roof_areas.empty() && roof_1st_layer.empty()) continue; | ||||
|             char fname[10]; sprintf(fname, "%d_%.2f", layer_nr, ts_layer->print_z); | ||||
|             draw_contours_and_nodes_to_svg(-1, base_areas, roof_areas, roof_1st_layer, {}, {}, get_svg_filename(fname, "circles"), {"base", "roof", "roof1st"}); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
|         TreeSupportLayerPtrs& ts_layers = m_object->tree_support_layers(); | ||||
|  | @ -2257,6 +2293,7 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes) | |||
|                 next_node->distance_to_top++; | ||||
|                 next_node->support_roof_layers_below--; | ||||
|                 next_node->print_z -= m_object->get_layer(layer_nr)->height; | ||||
|                 next_node->to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[layer_nr], next_node->position); | ||||
|                 contact_nodes[layer_nr - 1].emplace_back(next_node); | ||||
|             } | ||||
|         } | ||||
|  | @ -2290,10 +2327,6 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes) | |||
|         for (Node* p_node : layer_contact_nodes) | ||||
|         { | ||||
|             const Node& node = *p_node; | ||||
|             if (node.type == ePolygon) { | ||||
|                 // polygon node do not merge or move
 | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if (support_on_buildplate_only && !node.to_buildplate) //Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported.
 | ||||
|             { | ||||
|  | @ -2305,6 +2338,10 @@ void TreeSupport::drop_nodes(std::vector<std::vector<Node*>>& contact_nodes) | |||
|                 nodes_per_part[0][node.position] = p_node; | ||||
|                 continue; | ||||
|             } | ||||
|             if (node.type == ePolygon) { | ||||
|                 // polygon node do not merge or move
 | ||||
|                 continue; | ||||
|             } | ||||
|             /* Find which part this node is located in and group the nodes in
 | ||||
|              * the same part together. Since nodes have a radius and the | ||||
|              * avoidance areas are offset by that radius, the set of parts may | ||||
|  | @ -2720,7 +2757,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N | |||
|     coordf_t z_distance_top = m_slicing_params.gap_support_object; | ||||
|     // BBS: add extra distance if thick bridge is enabled
 | ||||
|     // Note: normal support uses print_z, but tree support uses integer layers, so we need to subtract layer_height
 | ||||
|     if (!m_slicing_params.soluble_interface && g_config_thick_bridges) { | ||||
|     if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) { | ||||
|         z_distance_top += m_object->layers()[0]->regions()[0]->region().bridging_height_avg(m_object->print()->config()) - layer_height; | ||||
|     } | ||||
|     const size_t z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1; //Support must always be 1 layer below overhang.
 | ||||
|  | @ -2729,17 +2766,20 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N | |||
|     coordf_t  thresh_angle           = config.support_threshold_angle.value < EPSILON ? 30.f : config.support_threshold_angle.value; | ||||
|     coordf_t  half_overhang_distance = scale_(tan(thresh_angle * M_PI / 180.0) * layer_height / 2); | ||||
| 
 | ||||
|     m_highest_overhang_layer = 0; | ||||
|     // fix bug of generating support for very thin objects
 | ||||
|     if (m_object->layers().size() <= z_distance_top_layers + 1) | ||||
|         return; | ||||
| 
 | ||||
|     m_highest_overhang_layer = 0; | ||||
|     int      nonempty_layers = 0; | ||||
|     std::vector<Slic3r::Vec3f> all_nodes; | ||||
|     for (size_t layer_nr = 1; layer_nr < m_object->layers().size() - z_distance_top_layers; layer_nr++) | ||||
|     { | ||||
|         if (m_object->print()->canceled()) | ||||
|             break; | ||||
| 
 | ||||
|         const ExPolygons &overhang = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers)->overhang_areas; | ||||
|         auto              ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers); | ||||
|         const ExPolygons &overhang = ts_layer->overhang_areas; | ||||
|         auto &          curr_nodes = contact_nodes[layer_nr]; | ||||
|         if (overhang.empty()) | ||||
|             continue; | ||||
| 
 | ||||
|  | @ -2757,7 +2797,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N | |||
|                 Node *contact_node     = new Node(candidate, 0, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height); | ||||
|                 contact_node->type = ePolygon; | ||||
|                 contact_node->overhang = &overhang_part; | ||||
|                 contact_nodes[layer_nr].emplace_back(contact_node); | ||||
|                 curr_nodes.emplace_back(contact_node); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|  | @ -2783,7 +2823,7 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N | |||
|                             constexpr size_t distance_to_top = 0; | ||||
|                             constexpr bool to_buildplate = true; | ||||
|                             Node* contact_node = new Node(candidate, distance_to_top, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, to_buildplate, Node::NO_PARENT,print_z,height); | ||||
|                             contact_nodes[layer_nr].emplace_back(contact_node); | ||||
|                             curr_nodes.emplace_back(contact_node); | ||||
|                             added = true; | ||||
|                         } | ||||
|                     } | ||||
|  | @ -2793,38 +2833,81 @@ void TreeSupport::generate_contact_points(std::vector<std::vector<TreeSupport::N | |||
|             if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
 | ||||
|             { | ||||
|                 auto bbox = overhang_part.contour.bounding_box(); | ||||
|                 Points candidates = { bbox.min, bounding_box_middle(bbox), bbox.max }; | ||||
|                 Points candidates; | ||||
|                 if (ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Detected) | ||||
|                     candidates = {bbox.min, bounding_box_middle(bbox), bbox.max}; | ||||
|                 else | ||||
|                     candidates = {bounding_box_middle(bbox)}; | ||||
| 
 | ||||
|                 for (Point candidate : candidates) { | ||||
|                     if (!overhang_part.contains(candidate)) | ||||
|                         move_inside_expoly(overhang_part, candidate); | ||||
|                     constexpr size_t distance_to_top = 0; | ||||
|                     constexpr bool   to_buildplate   = true; | ||||
|                     Node *           contact_node    = new Node(candidate, distance_to_top, layer_nr % 2, support_roof_layers, to_buildplate, Node::NO_PARENT, print_z, height); | ||||
|                     contact_nodes[layer_nr].emplace_back(contact_node); | ||||
|                     curr_nodes.emplace_back(contact_node); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // add points at corners
 | ||||
|             auto& points = overhang_part.contour.points; | ||||
|             for (int i=0;i<points.size();i++) | ||||
|             { | ||||
|                 auto pt = points[i]; | ||||
|                 auto v1 = (pt - points[(i - 1 + points.size()) % points.size()]).normalized(); | ||||
|                 auto v2 = (pt - points[(i + 1) % points.size()]).normalized(); | ||||
|                 if (v1.dot(v2) > -0.7) { | ||||
|                     Node* contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height); | ||||
|                     contact_nodes[layer_nr].emplace_back(contact_node); | ||||
|             if (ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Detected) { | ||||
|                 // add points at corners
 | ||||
|                 auto &points = overhang_part.contour.points; | ||||
|                 for (int i = 0; i < points.size(); i++) { | ||||
|                     auto pt = points[i]; | ||||
|                     auto v1 = (pt - points[(i - 1 + points.size()) % points.size()]).normalized(); | ||||
|                     auto v2 = (pt - points[(i + 1) % points.size()]).normalized(); | ||||
|                     if (v1.dot(v2) > -0.7) { | ||||
|                         Node *contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height); | ||||
|                         curr_nodes.emplace_back(contact_node); | ||||
|                     } | ||||
|                 } | ||||
|             } else if(ts_layer->overhang_types[&overhang_part] == TreeSupportLayer::Enforced){ | ||||
|                 // remove close points in Enforcers
 | ||||
|                 auto above_nodes = contact_nodes[layer_nr - 1]; | ||||
|                 if (!curr_nodes.empty() && !above_nodes.empty()) { | ||||
|                     for (auto it = curr_nodes.begin(); it != curr_nodes.end();) { | ||||
|                         bool is_duplicate = false; | ||||
|                         Slic3r::Vec3f curr_pt((*it)->position(0), (*it)->position(1), scale_((*it)->print_z)); | ||||
|                         for (auto &pt : all_nodes) { | ||||
|                             auto dif = curr_pt - pt; | ||||
|                             if (dif.norm() < scale_(2)) { | ||||
|                                 delete (*it); | ||||
|                                 it           = curr_nodes.erase(it); | ||||
|                                 is_duplicate = true; | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                         if (!is_duplicate) it++; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|          | ||||
|         } | ||||
| 
 | ||||
|         if (!curr_nodes.empty()) nonempty_layers++; | ||||
|         for (auto node : curr_nodes) { all_nodes.emplace_back(node->position(0), node->position(1), scale_(node->print_z)); } | ||||
| #ifdef SUPPORT_TREE_DEBUG_TO_SVG | ||||
|         draw_contours_and_nodes_to_svg(layer_nr, overhang, m_ts_data->m_layer_outlines_below[layer_nr], {}, | ||||
|             contact_nodes[layer_nr], {}, "init_contact_points", { "overhang","outlines","" }); | ||||
| #endif | ||||
|     } | ||||
|     int nNodes = all_nodes.size(); | ||||
|     avg_node_per_layer = nodes_angle = 0; | ||||
|     if (nNodes > 0) { | ||||
|         avg_node_per_layer = nNodes / nonempty_layers; | ||||
|         // get orientation of nodes by line fitting
 | ||||
|         // line: y=kx+b, where
 | ||||
|         //       k=tan(nodes_angle)=(n\sum{xy}-\sum{x}\sum{y})/(n\sum{x^2}-\sum{x}^2)
 | ||||
|         float mx = 0, my = 0, mxy = 0, mx2 = 0; | ||||
|         for (auto &pt : all_nodes) { | ||||
|             float x = unscale_(pt(0)); | ||||
|             float y = unscale_(pt(1)); | ||||
|             mx += x; | ||||
|             my += y; | ||||
|             mxy += x * y; | ||||
|             mx2 += x * x; | ||||
|         } | ||||
|         nodes_angle = atan2(nNodes * mxy - mx * my, nNodes * mx2 - SQ(mx)); | ||||
|          | ||||
|         BOOST_LOG_TRIVIAL(info) << "avg_node_per_layer=" << avg_node_per_layer << ", nodes_angle=" << nodes_angle; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void TreeSupport::insert_dropped_node(std::vector<Node*>& nodes_layer, Node* p_node) | ||||
|  |  | |||
|  | @ -340,9 +340,8 @@ public: | |||
|         bool          with_sheath; | ||||
|     }; | ||||
| 
 | ||||
|     float           total_overhang_area; | ||||
|     float           max_overhang_area; | ||||
|     size_t          total_overhang_layer_cnt; | ||||
|     int  avg_node_per_layer = 0; | ||||
|     float nodes_angle       = 0; | ||||
|     bool            has_sharp_tail; | ||||
| private: | ||||
|     /*!
 | ||||
|  |  | |||
|  | @ -497,15 +497,10 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& trafod, | |||
| 
 | ||||
| TriangleMesh TriangleMesh::convex_hull_3d() const | ||||
| { | ||||
|     // BBS: don't compute convex hull for objects like a single sheet
 | ||||
|     if (this->m_stats.volume>0.001) { | ||||
|         TriangleMesh mesh(its_convex_hull(this->its)); | ||||
|         // Quite often qhull produces non-manifold mesh.
 | ||||
|         // assert(mesh.stats().manifold());
 | ||||
|         return mesh; | ||||
|     } | ||||
|     else | ||||
|         return TriangleMesh(); | ||||
|     TriangleMesh mesh(its_convex_hull(this->its)); | ||||
|     // Quite often qhull produces non-manifold mesh.
 | ||||
|     // assert(mesh.stats().manifold());
 | ||||
|     return mesh; | ||||
| } | ||||
| 
 | ||||
| std::vector<ExPolygons> TriangleMesh::slice(const std::vector<double> &z) const | ||||
|  |  | |||
|  | @ -84,6 +84,124 @@ static ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline& thi | |||
|     return paths; | ||||
| } | ||||
| 
 | ||||
| //BBS: new function to filter width to avoid too fragmented segments
 | ||||
| static ExtrusionPaths thick_polyline_to_extrusion_paths_2(const ThickPolyline& thick_polyline, ExtrusionRole role, const Flow& flow, const float tolerance) | ||||
| { | ||||
|     ExtrusionPaths paths; | ||||
|     ExtrusionPath path(role); | ||||
|     ThickLines lines = thick_polyline.thicklines(); | ||||
| 
 | ||||
|     size_t start_index = 0; | ||||
|     double max_width, min_width; | ||||
| 
 | ||||
|     for (int i = 0; i < (int)lines.size(); ++i) { | ||||
|         const ThickLine& line = lines[i]; | ||||
| 
 | ||||
|         if (i == 0) { | ||||
|             max_width = line.a_width; | ||||
|             min_width = line.a_width; | ||||
|         } | ||||
| 
 | ||||
|         const coordf_t line_len = line.length(); | ||||
|         if (line_len < SCALED_EPSILON) continue; | ||||
| 
 | ||||
|         double thickness_delta = std::max(fabs(max_width - line.b_width), fabs(min_width - line.b_width)); | ||||
|         //BBS: has large difference in width
 | ||||
|         if (thickness_delta > tolerance) { | ||||
|             //BBS: 1 generate path from start_index to i(not included)
 | ||||
|             if (start_index != i){ | ||||
|                 path = ExtrusionPath(role); | ||||
|                 double length = lines[start_index].length(); | ||||
|                 double sum = lines[start_index].length() * lines[start_index].a_width; | ||||
|                 path.polyline.append(lines[start_index].a); | ||||
|                 for (int idx = start_index + 1; idx < i; idx++) { | ||||
|                     length += lines[idx].length(); | ||||
|                     sum += lines[idx].length() * lines[idx].a_width; | ||||
|                     path.polyline.append(lines[idx].a); | ||||
|                 } | ||||
|                 path.polyline.append(lines[i].a); | ||||
|                 if (length > SCALED_EPSILON) { | ||||
|                     double w = sum / length; | ||||
|                     Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI)); | ||||
|                     path.mm3_per_mm = new_flow.mm3_per_mm(); | ||||
|                     path.width = new_flow.width(); | ||||
|                     path.height = new_flow.height(); | ||||
|                     paths.emplace_back(std::move(path)); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             start_index = i; | ||||
|             max_width = line.a_width; | ||||
|             min_width = line.a_width; | ||||
| 
 | ||||
|             //BBS: 2 handle the i-th segment
 | ||||
|             thickness_delta = fabs(line.a_width - line.b_width); | ||||
|             if (thickness_delta > tolerance){ | ||||
|                 const unsigned int segments = (unsigned int)ceil(thickness_delta / tolerance); | ||||
|                 const coordf_t seg_len = line_len / segments; | ||||
|                 Points pp; | ||||
|                 std::vector<coordf_t> width; | ||||
|                 { | ||||
|                     pp.push_back(line.a); | ||||
|                     width.push_back(line.a_width); | ||||
|                     for (size_t j = 1; j < segments; ++j) { | ||||
|                         pp.push_back((line.a.cast<double>() + (line.b - line.a).cast<double>().normalized() * (j * seg_len)).cast<coord_t>()); | ||||
| 
 | ||||
|                         coordf_t w = line.a_width + (j * seg_len) * (line.b_width - line.a_width) / line_len; | ||||
|                         width.push_back(w); | ||||
|                         width.push_back(w); | ||||
|                     } | ||||
|                     pp.push_back(line.b); | ||||
|                     width.push_back(line.b_width); | ||||
| 
 | ||||
|                     assert(pp.size() == segments + 1u); | ||||
|                     assert(width.size() == segments * 2); | ||||
|                 } | ||||
| 
 | ||||
|                 // delete this line and insert new ones
 | ||||
|                 lines.erase(lines.begin() + i); | ||||
|                 for (size_t j = 0; j < segments; ++j) { | ||||
|                     ThickLine new_line(pp[j], pp[j + 1]); | ||||
|                     new_line.a_width = width[2 * j]; | ||||
|                     new_line.b_width = width[2 * j + 1]; | ||||
|                     lines.insert(lines.begin() + i + j, new_line); | ||||
|                 } | ||||
|                 --i; | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|         //BBS: just update the max and min width and continue
 | ||||
|         else { | ||||
|             max_width = std::max(max_width, std::max(line.a_width, line.b_width)); | ||||
|             min_width = std::min(min_width, std::min(line.a_width, line.b_width)); | ||||
|         } | ||||
|     } | ||||
|     //BBS: handle the remaining segment
 | ||||
|     size_t final_size = lines.size(); | ||||
|     if (start_index < final_size) { | ||||
|         path = ExtrusionPath(role); | ||||
|         double length = lines[start_index].length(); | ||||
|         double sum = lines[start_index].length() * lines[start_index].a_width; | ||||
|         path.polyline.append(lines[start_index].a); | ||||
|         for (int idx = start_index + 1; idx < final_size; idx++) { | ||||
|             length += lines[idx].length(); | ||||
|             sum += lines[idx].length() * lines[idx].a_width; | ||||
|             path.polyline.append(lines[idx].a); | ||||
|         } | ||||
|         path.polyline.append(lines[final_size - 1].b); | ||||
|         if (length > SCALED_EPSILON) { | ||||
|             double w = sum / length; | ||||
|             Flow new_flow = flow.with_width(unscale<float>(w) + flow.height() * float(1. - 0.25 * PI)); | ||||
|             path.mm3_per_mm = new_flow.mm3_per_mm(); | ||||
|             path.width = new_flow.width(); | ||||
|             path.height = new_flow.height(); | ||||
|             paths.emplace_back(std::move(path)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return paths; | ||||
| } | ||||
| 
 | ||||
| void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const Flow& flow, std::vector<ExtrusionEntity*>& out) | ||||
| { | ||||
|     // This value determines granularity of adaptive width, as G-code does not allow
 | ||||
|  | @ -91,7 +209,7 @@ void variable_width(const ThickPolylines& polylines, ExtrusionRole role, const F | |||
|     // of segments, and any pruning shall be performed before we apply this tolerance.
 | ||||
|     const float tolerance = float(scale_(0.05)); | ||||
|     for (const ThickPolyline& p : polylines) { | ||||
|         ExtrusionPaths paths = thick_polyline_to_extrusion_paths(p, role, flow, tolerance); | ||||
|         ExtrusionPaths paths = thick_polyline_to_extrusion_paths_2(p, role, flow, tolerance); | ||||
|         // Append paths to collection.
 | ||||
|         if (!paths.empty()) { | ||||
|             if (paths.front().first_point() == paths.back().last_point()) | ||||
|  |  | |||
|  | @ -84,7 +84,6 @@ static constexpr bool RELATIVE_E_AXIS = 1; | |||
| #endif /* UNUSED */ | ||||
| 
 | ||||
| //BBS: some global const config which user can not change, but developer can
 | ||||
| static constexpr bool g_config_thick_bridges = true; | ||||
| static constexpr bool g_config_support_sharp_tails = true; | ||||
| static constexpr bool g_config_remove_small_overhangs = true; | ||||
| static constexpr float g_config_tree_support_collision_resolution = 0.2; | ||||
|  |  | |||
|  | @ -11,6 +11,10 @@ | |||
| #include "Time.hpp" | ||||
| #include "libslic3r.h" | ||||
| 
 | ||||
| #ifdef __APPLE__ | ||||
| #include "MacUtils.hpp" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 	#include <windows.h> | ||||
| 	#include <psapi.h> | ||||
|  | @ -292,12 +296,21 @@ namespace keywords = boost::log::keywords; | |||
| namespace attrs = boost::log::attributes; | ||||
| void set_log_path_and_level(const std::string& file, unsigned int level) | ||||
| { | ||||
| #ifdef __APPLE__ | ||||
| 	//currently on old macos, the boost::log::add_file_log will crash
 | ||||
| 	//TODO: need to be fixed
 | ||||
| 	if (!is_macos_support_boost_add_file_log()) { | ||||
| 		return; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	//BBS log file at C:\\Users\\[yourname]\\AppData\\Roaming\\BambuStudio\\log\\[log_filename].log
 | ||||
| 	auto log_folder = boost::filesystem::path(g_data_dir) / "log"; | ||||
| 	if (!boost::filesystem::exists(log_folder)) { | ||||
| 		boost::filesystem::create_directory(log_folder); | ||||
| 	} | ||||
| 	auto full_path = (log_folder / file).make_preferred(); | ||||
| 
 | ||||
| 	g_log_sink = boost::log::add_file_log( | ||||
| 		keywords::file_name = full_path.string() + ".%N", | ||||
| 		keywords::rotation_size = 100 * 1024 * 1024, | ||||
|  | @ -309,6 +322,7 @@ void set_log_path_and_level(const std::string& file, unsigned int level) | |||
| 			<< ":" << expr::smessage | ||||
| 			) | ||||
| 	); | ||||
| 
 | ||||
| 	logging::add_common_attributes(); | ||||
| 
 | ||||
| 	set_logging_level(level); | ||||
|  |  | |||
|  | @ -221,8 +221,8 @@ set(SLIC3R_GUI_SOURCES | |||
|     GUI/Monitor.hpp | ||||
|     GUI/WebViewDialog.cpp | ||||
|     GUI/WebViewDialog.hpp | ||||
|     GUI/WebDailytipDialog.hpp | ||||
|     GUI/WebDailytipDialog.cpp | ||||
|     GUI/WebDownPluginDlg.hpp | ||||
|     GUI/WebDownPluginDlg.cpp | ||||
|     GUI/WebGuideDialog.hpp | ||||
|     GUI/WebGuideDialog.cpp | ||||
|     GUI/WebUserLoginDialog.cpp | ||||
|  | @ -268,12 +268,16 @@ set(SLIC3R_GUI_SOURCES | |||
|     GUI/ConfigWizard_private.hpp | ||||
|     GUI/MsgDialog.cpp | ||||
|     GUI/MsgDialog.hpp | ||||
|     GUI/DownloadProgressDialog.hpp | ||||
|     GUI/DownloadProgressDialog.cpp | ||||
|     GUI/UpdateDialogs.cpp | ||||
|     GUI/UpdateDialogs.hpp | ||||
|     GUI/Jobs/Job.hpp | ||||
|     GUI/Jobs/Job.cpp | ||||
|     GUI/Jobs/PlaterJob.hpp | ||||
|     GUI/Jobs/PlaterJob.cpp | ||||
|     GUI/Jobs/UpgradeNetworkJob.hpp | ||||
|     GUI/Jobs/UpgradeNetworkJob.cpp | ||||
|     GUI/Jobs/ArrangeJob.hpp | ||||
|     GUI/Jobs/ArrangeJob.cpp | ||||
|     GUI/Jobs/OrientJob.hpp | ||||
|  |  | |||
|  | @ -4,9 +4,14 @@ | |||
| #include "I18N.hpp" | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| static bool show_flag; | ||||
| 
 | ||||
| AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id): wxPopupTransientWindow(parent, id) | ||||
| { | ||||
| #ifdef __APPLE__ | ||||
| #define COMBOBOX_FILAMENT (m_comboBox_filament_mac) | ||||
| #else | ||||
| #define COMBOBOX_FILAMENT (m_comboBox_filament) | ||||
| #endif | ||||
| AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id) : wxPopupTransientWindow(parent, wxPU_CONTAINS_CONTROLS) { | ||||
|     create(); | ||||
| } | ||||
| 
 | ||||
|  | @ -28,9 +33,13 @@ void AMSMaterialsSetting::create() | |||
| 
 | ||||
|     m_sizer_filament->Add(0, 0, 0, wxEXPAND, 0); | ||||
| 
 | ||||
| #ifdef __APPLE__ | ||||
|     m_comboBox_filament_mac = new wxComboBox(m_panel_body, wxID_ANY, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_COMBOX_WIDTH, 0, nullptr, wxCB_READONLY); | ||||
| #else | ||||
|     m_comboBox_filament = new ::ComboBox(m_panel_body, wxID_ANY, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_COMBOX_WIDTH, 0, nullptr, wxCB_READONLY); | ||||
|     m_sizer_filament->Add(m_comboBox_filament, 0, wxALIGN_CENTER, 0); | ||||
| #endif | ||||
| 
 | ||||
|     m_sizer_filament->Add(COMBOBOX_FILAMENT, 1, wxALIGN_CENTER, 0); | ||||
|     wxBoxSizer *m_sizer_colour = new wxBoxSizer(wxHORIZONTAL); | ||||
| 
 | ||||
|     m_title_colour = new wxStaticText(m_panel_body, wxID_ANY, _L("Colour"), wxDefaultPosition, wxSize(AMS_MATERIALS_SETTING_LABEL_WIDTH, -1), 0); | ||||
|  | @ -77,18 +86,18 @@ void AMSMaterialsSetting::create() | |||
| 
 | ||||
|     wxBoxSizer *sizer_other           = new wxBoxSizer(wxVERTICAL); | ||||
|     wxBoxSizer *sizer_tempinput       = new wxBoxSizer(wxHORIZONTAL); | ||||
|     | ||||
| 
 | ||||
|     m_input_nozzle_max = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE, | ||||
|         wxTE_CENTRE | wxTE_PROCESS_ENTER); | ||||
|     m_input_nozzle_max = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); | ||||
|     m_input_nozzle_min = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE, wxTE_CENTRE | wxTE_PROCESS_ENTER); | ||||
|     m_input_nozzle_max->Enable(false); | ||||
|     m_input_nozzle_min->Enable(false); | ||||
| 
 | ||||
|     m_input_nozzle_max->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); | ||||
|     m_input_nozzle_max->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20))); | ||||
|     auto bitmap_max_degree = new wxStaticBitmap(m_panel_body, -1, create_scaled_bitmap("degree", nullptr, 16), wxDefaultPosition, wxDefaultSize); | ||||
| 
 | ||||
|     m_input_nozzle_min = new ::TextInput(m_panel_body, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, AMS_MATERIALS_SETTING_INPUT_SIZE, | ||||
|                                          wxTE_CENTRE | wxTE_PROCESS_ENTER); | ||||
|     m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20))); | ||||
|     m_input_nozzle_min->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); | ||||
|     m_input_nozzle_min->GetTextCtrl()->SetSize(wxSize(-1, FromDIP(20))); | ||||
| 
 | ||||
|     auto bitmap_max_degree = new wxStaticBitmap(m_panel_body, -1, create_scaled_bitmap("degree", nullptr, 16), wxDefaultPosition, wxDefaultSize); | ||||
|     auto bitmap_min_degree = new wxStaticBitmap(m_panel_body, -1, create_scaled_bitmap("degree", nullptr, 16), wxDefaultPosition, wxDefaultSize); | ||||
| 
 | ||||
|     sizer_tempinput->Add(m_input_nozzle_max, 1, wxALIGN_CENTER, 0); | ||||
|  | @ -125,7 +134,7 @@ void AMSMaterialsSetting::create() | |||
|     warning_text->SetMinSize(wxSize(AMS_MATERIALS_SETTING_BODY_WIDTH, -1)); | ||||
|     warning_text->Hide(); | ||||
| 
 | ||||
|     m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent &e) { | ||||
|      m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent &e) { | ||||
|         warning_text->Hide(); | ||||
|         Layout(); | ||||
|         Fit(); | ||||
|  | @ -135,22 +144,22 @@ void AMSMaterialsSetting::create() | |||
|         input_min_finish(); | ||||
|         e.Skip(); | ||||
|     }); | ||||
|     m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &e) { | ||||
|      m_input_nozzle_min->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &e) { | ||||
|         input_min_finish(); | ||||
|         e.Skip(); | ||||
|     }); | ||||
| 
 | ||||
|     m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent& e) { | ||||
|      m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent &e) { | ||||
|         warning_text->Hide(); | ||||
|         Layout(); | ||||
|         Fit(); | ||||
|         e.Skip(); | ||||
|         }); | ||||
|     m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent& e) { | ||||
|      m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent &e) { | ||||
|         input_max_finish(); | ||||
|         e.Skip(); | ||||
|         }); | ||||
|     m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) { | ||||
|      m_input_nozzle_max->GetTextCtrl()->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &e) { | ||||
|         input_max_finish(); | ||||
|         e.Skip(); | ||||
|         }); | ||||
|  | @ -170,13 +179,6 @@ void AMSMaterialsSetting::create() | |||
|     m_button_confirm->Bind(wxEVT_LEFT_DOWN, &AMSMaterialsSetting::on_select_ok, this); | ||||
|     m_sizer_button->Add(m_button_confirm, 0, wxALIGN_CENTER, 0); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     StateColor btn_bg_white(std::pair<wxColour, int>(wxColour(206, 206, 206), StateColor::Pressed), | ||||
|                             std::pair<wxColour, int>(wxColour(238, 238, 238), StateColor::Hovered), | ||||
|                             std::pair<wxColour, int>(*wxWHITE, StateColor::Normal)); | ||||
|     StateColor btn_bd_white(std::pair<wxColour, int>(*wxWHITE, StateColor::Disabled), std::pair<wxColour, int>(wxColour(38, 46, 48), StateColor::Enabled)); | ||||
| 
 | ||||
|     m_sizer_body->Add(m_sizer_filament, 0, wxEXPAND, 0); | ||||
|     m_sizer_body->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(16)); | ||||
|     m_sizer_body->Add(m_sizer_colour, 0, wxEXPAND, 0); | ||||
|  | @ -200,7 +202,7 @@ void AMSMaterialsSetting::create() | |||
|     this->Centre(wxBOTH); | ||||
| 
 | ||||
|      Bind(wxEVT_PAINT, &AMSMaterialsSetting::paintEvent, this); | ||||
|     m_comboBox_filament->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this); | ||||
|      COMBOBOX_FILAMENT->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this); | ||||
| } | ||||
| 
 | ||||
| void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt)  | ||||
|  | @ -214,13 +216,13 @@ void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt) | |||
| 
 | ||||
| AMSMaterialsSetting::~AMSMaterialsSetting() | ||||
| { | ||||
|     m_comboBox_filament->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this); | ||||
|     COMBOBOX_FILAMENT->Disconnect(wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(AMSMaterialsSetting::on_select_filament), NULL, this); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void AMSMaterialsSetting::input_min_finish()  | ||||
| { | ||||
|     if (m_input_nozzle_min->GetTextCtrl()->GetValue().empty())return; | ||||
|     if (m_input_nozzle_min->GetTextCtrl()->GetValue().empty()) return; | ||||
| 
 | ||||
|     auto val = std::atoi(m_input_nozzle_min->GetTextCtrl()->GetValue().c_str()); | ||||
| 
 | ||||
|  | @ -235,7 +237,7 @@ void AMSMaterialsSetting::input_min_finish() | |||
| 
 | ||||
| void AMSMaterialsSetting::input_max_finish() | ||||
| { | ||||
|     if (m_input_nozzle_max->GetTextCtrl()->GetValue().empty())return; | ||||
|     if (m_input_nozzle_max->GetTextCtrl()->GetValue().empty()) return; | ||||
| 
 | ||||
|     auto val = std::atoi(m_input_nozzle_max->GetTextCtrl()->GetValue().c_str()); | ||||
| 
 | ||||
|  | @ -279,8 +281,8 @@ void AMSMaterialsSetting::enable_confirm_button(bool en) | |||
| 
 | ||||
| void AMSMaterialsSetting::on_select_ok(wxMouseEvent &event) | ||||
| { | ||||
|     wxString nozzle_temp_min  = m_input_nozzle_min->GetTextCtrl()->GetValue(); | ||||
|     auto filament         = m_comboBox_filament->GetValue(); | ||||
|     wxString nozzle_temp_min = m_input_nozzle_min->GetTextCtrl()->GetValue(); | ||||
|     auto     filament        = COMBOBOX_FILAMENT->GetValue(); | ||||
| 
 | ||||
|     wxString nozzle_temp_max = m_input_nozzle_max->GetTextCtrl()->GetValue(); | ||||
| 
 | ||||
|  | @ -295,7 +297,7 @@ void AMSMaterialsSetting::on_select_ok(wxMouseEvent &event) | |||
|     PresetBundle *preset_bundle = wxGetApp().preset_bundle; | ||||
|     if (preset_bundle) { | ||||
|         for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { | ||||
|             if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) { | ||||
|             if (it->alias.compare(COMBOBOX_FILAMENT->GetValue().ToStdString()) == 0) { | ||||
|                 ams_filament_id = it->filament_id; | ||||
|             } | ||||
|         } | ||||
|  | @ -313,19 +315,12 @@ void AMSMaterialsSetting::on_select_ok(wxMouseEvent &event) | |||
| 
 | ||||
| void AMSMaterialsSetting::set_color(wxColour color) | ||||
| { | ||||
|     m_clrData = new wxColourData(); | ||||
|     m_clrData->SetColour(color); | ||||
| } | ||||
| 
 | ||||
| static bool show_flag; | ||||
| void AMSMaterialsSetting::on_clr_picker(wxCommandEvent & event) { | ||||
| 
 | ||||
| void AMSMaterialsSetting::on_clr_picker(wxCommandEvent & event)  | ||||
| { | ||||
|     auto clr_dialog = new wxColourDialog(this, m_clrData); | ||||
|      | ||||
|     clr_dialog->Bind(wxEVT_ACTIVATE, [this](wxActivateEvent &e) { | ||||
|         int a ; | ||||
|         }); | ||||
| 
 | ||||
|     show_flag = true; | ||||
|     if (clr_dialog->ShowModal() == wxID_OK) { | ||||
|         m_clrData = &(clr_dialog->GetColourData()); | ||||
|  | @ -338,12 +333,14 @@ void AMSMaterialsSetting::Dismiss() | |||
|     if (show_flag)  | ||||
|     { | ||||
|         show_flag = false; | ||||
|     } | ||||
|     else  | ||||
|     } else  | ||||
|     { | ||||
|     wxPopupTransientWindow::Dismiss(); | ||||
| #ifdef __APPLE__ | ||||
| 
 | ||||
| #else | ||||
|         wxPopupTransientWindow::Dismiss(); | ||||
| #endif | ||||
|     } | ||||
|      | ||||
| } | ||||
| 
 | ||||
| bool AMSMaterialsSetting::Show(bool show)  | ||||
|  | @ -360,12 +357,14 @@ void AMSMaterialsSetting::Popup(bool show, bool third, wxString filament, wxColo | |||
| { | ||||
|     if (!m_is_third) { | ||||
|         m_panel_SN->Show(); | ||||
|         m_comboBox_filament->SetValue(filament); | ||||
|         COMBOBOX_FILAMENT->SetValue(filament); | ||||
|         m_sn_number->SetLabelText(sn); | ||||
|         m_input_nozzle_min->GetTextCtrl()->SetValue(tep); | ||||
|         m_clrData->SetColour(colour); | ||||
|         m_comboBox_filament->Disable(); | ||||
|         COMBOBOX_FILAMENT->Disable(); | ||||
| 
 | ||||
|         m_input_nozzle_min->Disable(); | ||||
| 
 | ||||
|         wxPopupTransientWindow::Popup(); | ||||
|         Layout(); | ||||
|         return; | ||||
|  | @ -438,13 +437,13 @@ void AMSMaterialsSetting::Popup(bool show, bool third, wxString filament, wxColo | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         m_comboBox_filament->Set(filament_items); | ||||
|         COMBOBOX_FILAMENT->Set(filament_items); | ||||
|         if (selection_idx >= 0 && selection_idx < filament_items.size()) { | ||||
|             m_comboBox_filament->SetSelection(selection_idx); | ||||
|             COMBOBOX_FILAMENT->SetSelection(selection_idx); | ||||
|             post_select_event(); | ||||
|         } | ||||
|         else { | ||||
|             m_comboBox_filament->SetSelection(selection_idx); | ||||
|             COMBOBOX_FILAMENT->SetSelection(selection_idx); | ||||
|             post_select_event(); | ||||
|         } | ||||
|     } | ||||
|  | @ -453,8 +452,8 @@ void AMSMaterialsSetting::Popup(bool show, bool third, wxString filament, wxColo | |||
| 
 | ||||
| void AMSMaterialsSetting::post_select_event() { | ||||
|     wxCommandEvent event(wxEVT_COMBOBOX); | ||||
|     event.SetEventObject(m_comboBox_filament); | ||||
|     wxPostEvent(m_comboBox_filament, event); | ||||
|     event.SetEventObject(COMBOBOX_FILAMENT); | ||||
|     wxPostEvent(COMBOBOX_FILAMENT, event); | ||||
| } | ||||
| 
 | ||||
| void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) | ||||
|  | @ -464,7 +463,7 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) | |||
|     if (preset_bundle) { | ||||
|         for (auto it = preset_bundle->filaments.begin(); it != preset_bundle->filaments.end(); it++) { | ||||
|             auto a = it->alias; | ||||
|             if (it->alias.compare(m_comboBox_filament->GetValue().ToStdString()) == 0) { | ||||
|             if (it->alias.compare(COMBOBOX_FILAMENT->GetValue().ToStdString()) == 0) { | ||||
|                 // ) if nozzle_temperature_range is found
 | ||||
|                 ConfigOption* opt_min = it->config.option("nozzle_temperature_range_low"); | ||||
|                 if (opt_min) { | ||||
|  | @ -498,10 +497,24 @@ void AMSMaterialsSetting::on_select_filament(wxCommandEvent &evt) | |||
|         } | ||||
|     } | ||||
|     if (m_input_nozzle_min->GetTextCtrl()->GetValue().IsEmpty()) { | ||||
|         m_input_nozzle_min->GetTextCtrl()->SetValue("220"); | ||||
|          m_input_nozzle_min->GetTextCtrl()->SetValue("220"); | ||||
|     } | ||||
|     if (m_input_nozzle_max->GetTextCtrl()->GetValue().IsEmpty()) { | ||||
|         m_input_nozzle_max->GetTextCtrl()->SetValue("220"); | ||||
|          m_input_nozzle_max->GetTextCtrl()->SetValue("220"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool AMSMaterialsSetting::ProcessLeftDown(wxMouseEvent &evt) | ||||
| { | ||||
|     wxPoint mouse_pos    = ClientToScreen(evt.GetPosition()); | ||||
|     wxPoint top_left     = this->ClientToScreen(wxPoint(0, 0)); | ||||
|     wxPoint range        = wxPoint(this->GetRect().width, this->GetRect().height); | ||||
|     wxPoint bottom_right = top_left + range; | ||||
|     if (mouse_pos.x > top_left.x && mouse_pos.y > top_left.y && mouse_pos.x < bottom_right.x && mouse_pos.y < bottom_right.y) { | ||||
|         return true; | ||||
|     } else { | ||||
|         wxPopupTransientWindow::Dismiss(); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,13 +39,13 @@ public: | |||
|     void input_max_finish(); | ||||
|     void update(); | ||||
|     void enable_confirm_button(bool en); | ||||
|     void on_select_cancel(wxMouseEvent &event); | ||||
|     void Dismiss() override; | ||||
|     bool Show(bool show) override; | ||||
|     void Popup(bool show, bool third = true, wxString filament = wxEmptyString, wxColour colour = *wxWHITE, wxString sn = wxEmptyString, wxString tep = wxEmptyString); | ||||
| 
 | ||||
| 	void post_select_event(); | ||||
|     void on_select_ok(wxMouseEvent &event); | ||||
| 
 | ||||
|     void set_color(wxColour color); | ||||
| 
 | ||||
|     void on_clr_picker(wxCommandEvent &event); | ||||
|  | @ -67,6 +67,8 @@ protected: | |||
|     //void on_dpi_changed(const wxRect &suggested_rect) override;
 | ||||
|     void on_select_filament(wxCommandEvent& evt); | ||||
| 
 | ||||
|     bool ProcessLeftDown(wxMouseEvent &evt); | ||||
| 
 | ||||
| protected: | ||||
|     StateColor          m_btn_bg_green; | ||||
|     wxPanel *           m_panel_SN; | ||||
|  | @ -82,6 +84,9 @@ protected: | |||
|     TextInput *         m_input_nozzle_min; | ||||
|     TextInput*          m_input_nozzle_max; | ||||
|     Button *            m_button_confirm; | ||||
| #ifdef __APPLE__ | ||||
|     wxComboBox *m_comboBox_filament_mac; | ||||
| #endif | ||||
|     wxColourData *      m_clrData; | ||||
| 
 | ||||
| }; | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ CopyrightsDialog::CopyrightsDialog() | |||
| 
 | ||||
|     SetSizer(sizer); | ||||
|     sizer->SetSizeHints(this); | ||||
| 
 | ||||
|     CenterOnParent(); | ||||
| } | ||||
| 
 | ||||
| void CopyrightsDialog::fill_entries() | ||||
|  | @ -88,6 +88,7 @@ void CopyrightsDialog::fill_entries() | |||
|     m_entries = { | ||||
|         { "Admesh",                                         "",      "https://admesh.readthedocs.io/" }, | ||||
|         { "Anti-Grain Geometry",                            "",      "http://antigrain.com" }, | ||||
|         { "ArcWelderLib",                                   "",      "https://plugins.octoprint.org/plugins/arc_welder" }, | ||||
|         { "Boost",                                          "",      "http://www.boost.org" }, | ||||
|         { "Cereal",                                         "",      "http://uscilab.github.io/cereal" }, | ||||
|         { "CGAL",                                           "",      "https://www.cgal.org" }, | ||||
|  | @ -115,6 +116,7 @@ void CopyrightsDialog::fill_entries() | |||
|         { "Real-Time DXT1/DXT5 C compression library",      "",      "https://github.com/Cyan4973/RygsDXTc" }, | ||||
|         { "SemVer",                                         "",      "https://semver.org" }, | ||||
|         { "Shinyprofiler",                                  "",      "https://code.google.com/p/shinyprofiler" }, | ||||
|         { "SuperSlicer",                                    "",      "https://github.com/supermerill/SuperSlicer" }, | ||||
|         { "TBB",                                            "",      "https://www.intel.cn/content/www/cn/zh/developer/tools/oneapi/onetbb.html" }, | ||||
|         { "wxWidgets",                                      "",      "https://www.wxwidgets.org" }, | ||||
|         { "zlib",                                           "",      "http://zlib.net" }, | ||||
|  | @ -219,7 +221,7 @@ AboutDialog::AboutDialog() | |||
|     std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); | ||||
|     SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); | ||||
| 
 | ||||
|     wxPanel *m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(430), FromDIP(237)), wxTAB_TRAVERSAL); | ||||
|     wxPanel *m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(237)), wxTAB_TRAVERSAL); | ||||
| 
 | ||||
|     wxBoxSizer *panel_versizer = new wxBoxSizer(wxVERTICAL); | ||||
|     wxBoxSizer *vesizer  = new wxBoxSizer(wxVERTICAL); | ||||
|  | @ -233,7 +235,7 @@ AboutDialog::AboutDialog() | |||
|     main_sizer->Add(ver_sizer, 0, wxEXPAND | wxALL, 0); | ||||
| 
 | ||||
|     // logo
 | ||||
|     m_logo_bitmap = ScalableBitmap(this, "BambuStudio_about", 240); | ||||
|     m_logo_bitmap = ScalableBitmap(this, "BambuStudio_about", 250); | ||||
|     m_logo = new wxStaticBitmap(this, wxID_ANY, m_logo_bitmap.bmp(), wxDefaultPosition,wxDefaultSize, 0); | ||||
|     m_logo->SetSizer(vesizer); | ||||
| 
 | ||||
|  | @ -250,20 +252,70 @@ AboutDialog::AboutDialog() | |||
|         #else | ||||
|             version_font.SetPointSize(11); | ||||
|         #endif | ||||
|         version_font.SetPointSize(12); | ||||
|         version_font.SetPointSize(FromDIP(16)); | ||||
|         version->SetFont(version_font); | ||||
|         version->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)); | ||||
|         version->SetForegroundColour(wxColour(255, 255, 255)); | ||||
|         version->SetBackgroundColour(wxColour(0, 174, 66)); | ||||
|         vesizer->Add(version, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, FromDIP(5)); | ||||
|         vesizer->Add(0, 0, 1, wxEXPAND, FromDIP(5)); | ||||
|     } | ||||
| 
 | ||||
|     wxStaticText *html_text = new wxStaticText(this, wxID_ANY, "Copyright(C) 2021-2022 Bambu Lab", wxDefaultPosition, wxDefaultSize); | ||||
|     ver_sizer->Add(0, 0, 0, wxTOP, FromDIP(38)); | ||||
|     html_text->SetForegroundColour(wxColour(107, 107, 107)); | ||||
|     ver_sizer->Add(html_text, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 0); | ||||
|     wxBoxSizer *text_sizer_horiz = new wxBoxSizer(wxHORIZONTAL); | ||||
|     wxBoxSizer *text_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|     text_sizer_horiz->Add( 0, 0, 0, wxLEFT, FromDIP(23)); | ||||
| 
 | ||||
|     std::vector<wxString> text_list; | ||||
|     text_list.push_back(_L("Bambu Studio is based on PrusaSlicer by PrusaResearch and SuperSlicer by Merill(supermerill).")); | ||||
|     text_list.push_back(_L("PrusaSlicer is originally based on Slic3r by Alessandro Ranellucci.")); | ||||
|     text_list.push_back(_L("Slic3r was created by Alessandro Ranellucci with the help of many other contributors.")); | ||||
|     text_list.push_back(_L("Bambu Studio also referenced some ideas from Cura by Ultimaker.")); | ||||
|     text_list.push_back(_L("There many parts of the software that come from community contributions, so we're unable to list them one-by-one, and instead, they'll be attributed in the corresponding code comments.")); | ||||
| 
 | ||||
|     text_sizer->Add( 0, 0, 0, wxTOP, FromDIP(33)); | ||||
|     bool is_zh = wxGetApp().app_config->get("language") == "zh_CN"; | ||||
|     for (int i = 0; i < text_list.size(); i++) | ||||
|     { | ||||
|         auto staticText = new wxStaticText( this, wxID_ANY, wxEmptyString,wxDefaultPosition,wxSize(FromDIP(520), -1), wxALIGN_LEFT ); | ||||
|         staticText->SetForegroundColour(wxColour(107, 107, 107)); | ||||
|         staticText->SetMinSize(wxSize(FromDIP(520), -1)); | ||||
|         staticText->SetFont(Label::Body_12); | ||||
|         if (is_zh) { | ||||
|             wxString find_txt = ""; | ||||
|             wxString count_txt = ""; | ||||
|             for (auto  o = 0; o < text_list[i].length(); o++) { | ||||
|                 auto size = staticText->GetTextExtent(count_txt); | ||||
|                 if (size.x < FromDIP(506)) { | ||||
|                     find_txt += text_list[i][o]; | ||||
|                     count_txt += text_list[i][o]; | ||||
|                 } else { | ||||
|                     find_txt += std::string("\n") + text_list[i][o]; | ||||
|                     count_txt = text_list[i][o]; | ||||
|                 } | ||||
|             } | ||||
|             staticText->SetLabel(find_txt); | ||||
|         } else { | ||||
|             staticText->SetLabel(text_list[i]); | ||||
|             staticText->Wrap(FromDIP(520)); | ||||
|         } | ||||
| 
 | ||||
|         text_sizer->Add( staticText, 0, wxUP | wxDOWN, FromDIP(3)); | ||||
|     } | ||||
| 
 | ||||
|     text_sizer_horiz->Add(text_sizer, 1, wxALL,0); | ||||
|     ver_sizer->Add(text_sizer_horiz, 0, wxALL,0); | ||||
|     ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(43)); | ||||
| 
 | ||||
|     wxBoxSizer *copyright_ver_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|     wxBoxSizer *copyright_hor_sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 
 | ||||
|     copyright_hor_sizer->Add(copyright_ver_sizer, 0, wxALL,5); | ||||
|     copyright_hor_sizer->Add( 0, 0, 0, wxLEFT, FromDIP(120)); | ||||
| 
 | ||||
|     wxStaticText *html_text = new wxStaticText(this, wxID_ANY, "Copyright(C) 2021-2022 Bambu Lab", wxDefaultPosition, wxDefaultSize); | ||||
|     html_text->SetForegroundColour(wxColour(107, 107, 107)); | ||||
| 
 | ||||
|     copyright_ver_sizer->Add(html_text, 0, wxALL , 0); | ||||
| 
 | ||||
|     // text
 | ||||
|     m_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER /*NEVER*/); | ||||
|       { | ||||
|           wxFont font = get_default_font(this); | ||||
|  | @ -276,12 +328,12 @@ AboutDialog::AboutDialog() | |||
|               (boost::format( | ||||
|               "<html>" | ||||
|               "<body>" | ||||
|               "<p style=\"text-align:center\"><a  href=\"www.bambulab.com\">www.bambulab.com</ a></p>" | ||||
|               "<p style=\"text-align:left\"><a  href=\"www.bambulab.com\">www.bambulab.com</ a></p>" | ||||
|               "</body>" | ||||
|               "</html>") | ||||
|             ).str()); | ||||
|           m_html->SetPage(text); | ||||
|           ver_sizer->Add(m_html, 0, wxEXPAND, 0); | ||||
|           copyright_ver_sizer->Add(m_html, 0, wxEXPAND, 0); | ||||
|           m_html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this); | ||||
|       } | ||||
|     //Add "Portions copyright" button
 | ||||
|  | @ -298,14 +350,21 @@ AboutDialog::AboutDialog() | |||
|     button_portions->SetCornerRadius(FromDIP(12)); | ||||
|     button_portions->SetMinSize(wxSize(FromDIP(120), FromDIP(24))); | ||||
| 
 | ||||
|     ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(22)); | ||||
|     ver_sizer->Add(button_portions, 0, wxALIGN_CENTER_HORIZONTAL|wxALL,0); | ||||
|     ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(38)); | ||||
|     wxBoxSizer *copyright_button_ver = new wxBoxSizer(wxVERTICAL); | ||||
|     copyright_button_ver->Add( 0, 0, 0, wxTOP, FromDIP(10)); | ||||
|     copyright_button_ver->Add(button_portions, 0, wxALL,0); | ||||
| 
 | ||||
|     copyright_hor_sizer->Add(copyright_button_ver, 0, wxALL,0); | ||||
|     copyright_hor_sizer->Add( 0, 0, 0, wxRIGHT, FromDIP(13)); | ||||
| 
 | ||||
|     ver_sizer->Add(copyright_hor_sizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL,0); | ||||
|     ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(30)); | ||||
|     button_portions->Bind(wxEVT_BUTTON, &AboutDialog::onCopyrightBtn, this); | ||||
| 
 | ||||
|     m_panel->Layout(); | ||||
| 	SetSizer(main_sizer); | ||||
| 	main_sizer->SetSizeHints(this); | ||||
|     Layout(); | ||||
|     Fit(); | ||||
|     CenterOnParent(); | ||||
| } | ||||
| 
 | ||||
| void AboutDialog::on_dpi_changed(const wxRect &suggested_rect) | ||||
|  |  | |||
|  | @ -48,11 +48,12 @@ wxDEFINE_EVENT(EVT_SET_FINISH_MAPPING, wxCommandEvent); | |||
| 
 | ||||
| void MaterialItem::msw_rescale() {} | ||||
| 
 | ||||
| void MaterialItem::set_ams_info(wxColour col, wxString txt)  | ||||
| void MaterialItem::set_ams_info(wxColour col, wxString txt) | ||||
| { | ||||
|     m_ams_coloul = col; | ||||
|     m_ams_name = txt; | ||||
|     Refresh(); | ||||
|     auto need_refresh = false; | ||||
|     if (m_ams_coloul != col) { m_ams_coloul = col; need_refresh = true;} | ||||
|     if (m_ams_name != txt) {m_ams_name   = txt;need_refresh = true;} | ||||
|     if (need_refresh) { Refresh();} | ||||
| } | ||||
| 
 | ||||
| void MaterialItem::on_selected() | ||||
|  | @ -74,17 +75,22 @@ void MaterialItem::on_warning() | |||
| 
 | ||||
| void MaterialItem::on_normal() | ||||
| { | ||||
|     m_selected = false; | ||||
|     m_warning = false; | ||||
|     Refresh(); | ||||
|     if (m_selected || m_warning) { | ||||
|         m_selected = false; | ||||
|         m_warning  = false; | ||||
|         Refresh(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void MaterialItem::paintEvent(wxPaintEvent &evt)  | ||||
| {   | ||||
|     wxPaintDC dc(this); | ||||
|     render(dc); | ||||
| 
 | ||||
|     //PrepareDC(buffdc);
 | ||||
|     //PrepareDC(dc);
 | ||||
|      | ||||
| } | ||||
| 
 | ||||
| void MaterialItem::render(wxDC &dc)  | ||||
|  | @ -107,29 +113,33 @@ void MaterialItem::render(wxDC &dc) | |||
|     doRender(dc); | ||||
| #endif | ||||
| 
 | ||||
|      //materials name
 | ||||
|      dc.SetFont(::Label::Body_13); | ||||
|     // materials name
 | ||||
|     dc.SetFont(::Label::Body_13); | ||||
| 
 | ||||
|      auto material_name_colour = m_material_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26,0x2E,0x30); | ||||
|      dc.SetTextForeground(material_name_colour); | ||||
|     auto material_name_colour = m_material_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26, 0x2E, 0x30); | ||||
|     dc.SetTextForeground(material_name_colour); | ||||
| 
 | ||||
|      auto material_txt_size = dc.GetTextExtent(m_material_name); | ||||
|      dc.DrawText(m_material_name, wxPoint((MATERIAL_ITEM_SIZE.x - material_txt_size.x) / 2, FromDIP(3))); | ||||
|     if (dc.GetTextExtent(m_material_name).x > GetSize().x - 10) { | ||||
|         dc.SetFont(::Label::Body_10); | ||||
| 
 | ||||
|      //mapping num
 | ||||
|      dc.SetFont(::Label::Body_10); | ||||
|      dc.SetTextForeground(m_ams_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26,0x2E,0x30)); | ||||
|     } | ||||
| 
 | ||||
|     auto material_txt_size = dc.GetTextExtent(m_material_name); | ||||
|     dc.DrawText(m_material_name, wxPoint((MATERIAL_ITEM_SIZE.x - material_txt_size.x) / 2, (FromDIP(22) - material_txt_size.y) / 2)); | ||||
| 
 | ||||
|      wxString mapping_txt = wxEmptyString; | ||||
|      if (m_ams_name.empty()) { | ||||
|          mapping_txt = "-"; | ||||
|      }else{ | ||||
|          mapping_txt = m_ams_name; | ||||
|      } | ||||
|       | ||||
|      auto mapping_txt_size = dc.GetTextExtent(mapping_txt); | ||||
|      dc.DrawText(mapping_txt, wxPoint((MATERIAL_ITEM_SIZE.x - mapping_txt_size.x) / 2, FromDIP(2) + material_txt_size.y )); | ||||
|     // mapping num
 | ||||
|     dc.SetFont(::Label::Body_10); | ||||
|     dc.SetTextForeground(m_ams_coloul.GetLuminance() < 0.5 ? *wxWHITE : wxColour(0x26, 0x2E, 0x30)); | ||||
| 
 | ||||
|     wxString mapping_txt = wxEmptyString; | ||||
|     if (m_ams_name.empty()) { | ||||
|         mapping_txt = "-"; | ||||
|     } else { | ||||
|         mapping_txt = m_ams_name; | ||||
|     } | ||||
| 
 | ||||
|     auto mapping_txt_size = dc.GetTextExtent(mapping_txt); | ||||
|     dc.DrawText(mapping_txt, wxPoint((MATERIAL_ITEM_SIZE.x - mapping_txt_size.x) / 2, FromDIP(20) + (FromDIP(14) - mapping_txt_size.y) / 2)); | ||||
| } | ||||
| 
 | ||||
| void MaterialItem::doRender(wxDC &dc)  | ||||
|  | @ -137,36 +147,33 @@ void MaterialItem::doRender(wxDC &dc) | |||
|     //top
 | ||||
|     dc.SetPen(*wxTRANSPARENT_PEN); | ||||
|     dc.SetBrush(wxBrush(m_material_coloul)); | ||||
|     dc.DrawRoundedRectangle(FromDIP(3), FromDIP(3), MATERIAL_ITEM_SIZE.x - FromDIP(6), MATERIAL_ITEM_SIZE.y / 2, 5); | ||||
|     dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(18), 5); | ||||
|      | ||||
|     //bottom
 | ||||
|     dc.SetPen(*wxTRANSPARENT_PEN); | ||||
|     dc.SetBrush(wxBrush(wxColour(m_ams_coloul))); | ||||
|     dc.DrawRoundedRectangle(FromDIP(3), MATERIAL_ITEM_SIZE.y / 2 - FromDIP(2), MATERIAL_ITEM_SIZE.x - FromDIP(6), MATERIAL_ITEM_SIZE.y / 2, 5); | ||||
|     dc.DrawRoundedRectangle(FromDIP(1), FromDIP(18), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(16), 5); | ||||
| 
 | ||||
|     //middle
 | ||||
|     ////middle
 | ||||
|     dc.SetPen(*wxTRANSPARENT_PEN); | ||||
|     dc.SetBrush(wxBrush(m_material_coloul)); | ||||
|     dc.DrawRectangle(FromDIP(3), FromDIP(10), MATERIAL_ITEM_SIZE.x - FromDIP(6), FromDIP(8)); | ||||
|     dc.DrawRectangle(FromDIP(1), FromDIP(11), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(8)); | ||||
| 
 | ||||
|     //border
 | ||||
|     if (m_material_coloul == *wxWHITE) { | ||||
|     dc.SetPen(*wxTRANSPARENT_PEN); | ||||
|     dc.SetBrush(wxBrush(m_ams_coloul)); | ||||
|     dc.DrawRectangle(FromDIP(1), FromDIP(18), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(8)); | ||||
| 
 | ||||
|     ////border
 | ||||
|     if (m_material_coloul == *wxWHITE || m_ams_coloul == *wxWHITE) { | ||||
|         dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); | ||||
|         dc.SetBrush(*wxTRANSPARENT_BRUSH); | ||||
|         dc.DrawRoundedRectangle(3, 3, MATERIAL_ITEM_SIZE.x -6, MATERIAL_ITEM_SIZE.y - 6, 5); | ||||
|         dc.DrawRoundedRectangle(0, 0, MATERIAL_ITEM_SIZE.x, MATERIAL_ITEM_SIZE.y, 5); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     if (m_selected) { | ||||
|         dc.SetPen(wxColour(0x00, 0xAE, 0x42)); | ||||
|         dc.SetBrush(*wxTRANSPARENT_BRUSH); | ||||
|         dc.DrawRoundedRectangle(1, 1, MATERIAL_ITEM_SIZE.x - 2, MATERIAL_ITEM_SIZE.y - 2, 5); | ||||
|     } | ||||
| 
 | ||||
|     if (m_warning) { | ||||
|         dc.SetPen(wxColour(0xFF, 0x6F, 0x00)); | ||||
|         dc.SetBrush(*wxTRANSPARENT_BRUSH); | ||||
|         dc.DrawRoundedRectangle(1, 1, MATERIAL_ITEM_SIZE.x - 2, MATERIAL_ITEM_SIZE.y - 2, 5); | ||||
|         dc.DrawRoundedRectangle(0, 0, MATERIAL_ITEM_SIZE.x, MATERIAL_ITEM_SIZE.y, 5); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -186,10 +193,6 @@ void MaterialItem::doRender(wxDC &dc) | |||
|      Layout(); | ||||
|  } | ||||
| 
 | ||||
| void AmsMapingPopup::Popup(wxWindow *focus /*= NULL*/) | ||||
| { | ||||
|     wxPopupTransientWindow::Popup(); | ||||
| } | ||||
| 
 | ||||
| void AmsMapingPopup::update_materials_list(std::vector<std::string> list)  | ||||
| {  | ||||
|  | @ -210,6 +213,11 @@ bool AmsMapingPopup::is_match_material(int id, std::string material) | |||
| 
 | ||||
| void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList)  | ||||
| {  | ||||
|     if (m_amsmapping_sizer_list.size() > 0) { | ||||
|         for (wxBoxSizer *bz : m_amsmapping_sizer_list) { bz->Clear(true); } | ||||
|         m_amsmapping_sizer_list.clear(); | ||||
|     } | ||||
|     | ||||
|     std::map<std::string, Ams *>::iterator ams_iter; | ||||
| 
 | ||||
|     BOOST_LOG_TRIVIAL(trace) << "ams_mapping total count " << amsList.size(); | ||||
|  | @ -229,8 +237,6 @@ void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList) | |||
| 
 | ||||
|             td.id = ams_indx * AMS_TOTAL_COUNT + atoi(tray_data->id.c_str()); | ||||
| 
 | ||||
|             BOOST_LOG_TRIVIAL(trace) << "ams_mapping ams data ==type==" << tray_data->type << "==colour=="<<tray_data->color << "==trayid=="<<tray_data->id.c_str() << "==ftrayid=="<<td.id; | ||||
| 
 | ||||
|             if (!tray_data->is_exists) { | ||||
|                 td.type = EMPTY; | ||||
|             } else { | ||||
|  | @ -254,9 +260,7 @@ void AmsMapingPopup::update_ams_data(std::map<std::string, Ams*> amsList) | |||
| 
 | ||||
| void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data) | ||||
| {  | ||||
|     wxBoxSizer *sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL); | ||||
|      | ||||
| 
 | ||||
|     auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL); | ||||
|     for (auto i = 0; i < tray_data.size(); i++) { | ||||
|         wxBoxSizer *sizer_mapping_item   = new wxBoxSizer(wxVERTICAL); | ||||
| 
 | ||||
|  | @ -299,7 +303,7 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data) | |||
|                 if (!is_match_material(tray_data[i].id, tray_data[i].name)) return; | ||||
|                 wxCommandEvent event(EVT_SET_FINISH_MAPPING); | ||||
|                 event.SetInt(tray_data[i].id); | ||||
|                 wxString param = wxString::Format("%d|%d|%d|%02d", tray_data[i].colour.Red(), tray_data[i].colour.Green(), tray_data[i].colour.Blue(), tray_data[i].id + 1); | ||||
|                 wxString param = wxString::Format("%d|%d|%d|%02d|%d", tray_data[i].colour.Red(), tray_data[i].colour.Green(), tray_data[i].colour.Blue(), tray_data[i].id + 1, m_current_filament_id); | ||||
|                 event.SetString(param); | ||||
|                 event.SetEventObject(this->GetParent()); | ||||
|                 wxPostEvent(this->GetParent(), event); | ||||
|  | @ -317,7 +321,7 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data) | |||
|             m_filament_name->Bind(wxEVT_BUTTON, [this, tray_data, i](wxCommandEvent &e) { | ||||
|                 wxCommandEvent event(EVT_SET_FINISH_MAPPING); | ||||
|                 event.SetInt(tray_data[i].id); | ||||
|                 wxString param = wxString::Format("%d|%d|%d|%02d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1); | ||||
|                 wxString param = wxString::Format("%d|%d|%d|%02d|%d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1, m_current_filament_id); | ||||
|                 event.SetString(param); | ||||
|                 event.SetEventObject(this->GetParent()); | ||||
|                 wxPostEvent(this->GetParent(), event); | ||||
|  | @ -334,7 +338,7 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data) | |||
|              m_filament_name->Bind(wxEVT_BUTTON, [this, tray_data, i](wxCommandEvent &e) { | ||||
|                 wxCommandEvent event(EVT_SET_FINISH_MAPPING); | ||||
|                 event.SetInt(tray_data[i].id); | ||||
|                 wxString param = wxString::Format("%d|%d|%d|%02d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1); | ||||
|                 wxString param = wxString::Format("%d|%d|%d|%02d|%d", 0x6B, 0x6B, 0x6B, tray_data[i].id + 1, m_current_filament_id); | ||||
|                 event.SetString(param); | ||||
|                 event.SetEventObject(this->GetParent()); | ||||
|                 wxPostEvent(this->GetParent(), event); | ||||
|  | @ -342,17 +346,17 @@ void AmsMapingPopup::add_ams_mapping(std::vector<TrayData> tray_data) | |||
|             }); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         sizer_mapping_item->Add(number, 0, wxALIGN_CENTER_HORIZONTAL, 0); | ||||
|         sizer_mapping_item->Add(m_filament_name, 0, wxALIGN_CENTER_HORIZONTAL, 0); | ||||
|         sizer_mapping_list->Add(sizer_mapping_item, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, FromDIP(5)); | ||||
|         m_amsmapping_sizer_list.push_back(sizer_mapping_list); | ||||
|     } | ||||
|     m_sizer_main->Add(sizer_mapping_list, 0, wxALIGN_CENTER_HORIZONTAL, 0); | ||||
| } | ||||
| 
 | ||||
| void AmsMapingPopup::OnDismiss() | ||||
| { | ||||
|     delete this; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool AmsMapingPopup::ProcessLeftDown(wxMouseEvent &event)  | ||||
|  |  | |||
|  | @ -39,7 +39,8 @@ | |||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| #define MATERIAL_ITEM_SIZE wxSize(FromDIP(42), FromDIP(31)) | ||||
| #define MATERIAL_ITEM_SIZE wxSize(FromDIP(64), FromDIP(34)) | ||||
| #define MATERIAL_ITEM_REAL_SIZE wxSize(FromDIP(62), FromDIP(32)) | ||||
| #define AMS_TOTAL_COUNT 4 | ||||
| 
 | ||||
| enum TrayType { | ||||
|  | @ -92,14 +93,18 @@ public: | |||
|     ~AmsMapingPopup() {}; | ||||
| 
 | ||||
|     std::vector<std::string> m_materials_list; | ||||
|     std::string m_tag_material; | ||||
|     wxBoxSizer *m_sizer_main; | ||||
|     std::vector<wxBoxSizer*>  m_amsmapping_sizer_list; | ||||
| 
 | ||||
|     int         m_current_filament_id; | ||||
|     std::string m_tag_material; | ||||
|     wxBoxSizer *m_sizer_main{nullptr};  | ||||
| 
 | ||||
|     virtual void Popup(wxWindow *focus = NULL) wxOVERRIDE; | ||||
|     void         update_materials_list(std::vector<std::string> list); | ||||
|     void         set_tag_texture(std::string texture); | ||||
|     void         update_ams_data(std::map<std::string, Ams *> amsList); | ||||
|     void         add_ams_mapping(std::vector<TrayData> tray_data); | ||||
|     void         set_current_filament_id(int id){m_current_filament_id = id;}; | ||||
|     int          get_current_filament_id(){return m_current_filament_id;}; | ||||
|     bool         is_match_material(int id, std::string material); | ||||
|     virtual void OnDismiss() wxOVERRIDE; | ||||
|     virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE; | ||||
|  |  | |||
|  | @ -501,7 +501,7 @@ AuFolderPanel::AuFolderPanel(wxWindow *parent, AuxiliaryFolderType type, wxWindo | |||
|     m_button_add = new Button(m_scrolledWindow, _L("Add"), "auxiliary_add_file", 12, 12); | ||||
|     m_button_add->SetBackgroundColor(btn_bg_white); | ||||
|     m_button_add->SetBorderColor(btn_bd_white); | ||||
|     m_button_add->SetMinSize(wxSize(FromDIP(80), FromDIP(24))); | ||||
|     m_button_add->SetMinSize(wxSize(-1, FromDIP(24))); | ||||
|     m_button_add->SetCornerRadius(12); | ||||
|     m_button_add->SetFont(Label::Body_14); | ||||
|     // m_button_add->Bind(wxEVT_LEFT_UP, &AuxiliaryPanel::on_add, this);
 | ||||
|  | @ -563,7 +563,7 @@ void AuFolderPanel::update(std::vector<fs::path> paths) | |||
| 
 | ||||
| void AuFolderPanel::msw_rescale()  | ||||
| { | ||||
|     m_button_add->SetMinSize(wxSize(FromDIP(80), FromDIP(24))); | ||||
|     m_button_add->SetMinSize(wxSize(-1, FromDIP(24))); | ||||
|     for (auto i = 0; i < m_aufiles_list.GetCount(); i++) { | ||||
|         AuFiles *aufile = m_aufiles_list[i]; | ||||
|         aufile->file->msw_rescale(); | ||||
|  | @ -707,21 +707,14 @@ void AuxiliaryPanel::init_tabpanel() | |||
|     m_tabpanel->SetBackgroundColour(*wxWHITE); | ||||
|     m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent &e) { ; }); | ||||
| 
 | ||||
| #if !BBL_RELEASE_TO_PUBLIC | ||||
|     m_designer_panel = new DesignerPanel(m_tabpanel, AuxiliaryFolderType::DESIGNER); | ||||
| #endif | ||||
| 
 | ||||
|     m_pictures_panel          = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::MODEL_PICTURE); | ||||
|     m_bill_of_materials_panel = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::BILL_OF_MATERIALS); | ||||
|     m_assembly_panel          = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::ASSEMBLY_GUIDE); | ||||
|     m_others_panel            = new AuFolderPanel(m_tabpanel, AuxiliaryFolderType::OTHERS); | ||||
| 
 | ||||
| #if !BBL_RELEASE_TO_PUBLIC | ||||
|     m_tabpanel->AddPage(m_designer_panel, _L("Basic Info"), "", true); | ||||
|     m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), "", false); | ||||
| #else | ||||
|     m_tabpanel->AddPage(m_pictures_panel, _L("Pictures"), "", true); | ||||
| #endif | ||||
|     m_tabpanel->AddPage(m_bill_of_materials_panel, _L("Bill of Materials"), "", false); | ||||
|     m_tabpanel->AddPage(m_assembly_panel, _L("Assembly Guide"), "", false); | ||||
|     m_tabpanel->AddPage(m_others_panel, _L("Others"), "", false); | ||||
|  | @ -743,9 +736,7 @@ void AuxiliaryPanel::msw_rescale() { | |||
|     m_bill_of_materials_panel->msw_rescale(); | ||||
|     m_assembly_panel->msw_rescale(); | ||||
|     m_others_panel->msw_rescale(); | ||||
| #if !BBL_RELEASE_TO_PUBLIC | ||||
|     m_designer_panel->msw_rescale(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void AuxiliaryPanel::on_size(wxSizeEvent &event) | ||||
|  | @ -897,9 +888,7 @@ void AuxiliaryPanel::Reload(wxString aux_path) | |||
|             fs::create_directory(folder_path.ToStdWstring()); | ||||
|         } | ||||
|         update_all_panel(); | ||||
|         #if !BBL_RELEASE_TO_PUBLIC | ||||
|         m_designer_panel->update_info(); | ||||
|         #endif | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -947,9 +936,7 @@ void AuxiliaryPanel::Reload(wxString aux_path) | |||
| 
 | ||||
|     update_all_panel(); | ||||
|     update_all_cover(); | ||||
|     #if !BBL_RELEASE_TO_PUBLIC | ||||
|     m_designer_panel->update_info(); | ||||
|     #endif | ||||
| } | ||||
| 
 | ||||
| void AuxiliaryPanel::update_all_panel() | ||||
|  |  | |||
|  | @ -77,28 +77,13 @@ void BBLStatusBarBind::set_progress(int val) | |||
|     if(val < 0) | ||||
|         return; | ||||
| 
 | ||||
|     bool need_layout = false; | ||||
|     //add the logic for arrange/orient jobs, which don't call stop_busy
 | ||||
|     if(val == m_prog->GetRange()) { | ||||
|         m_prog->SetValue(0); | ||||
|         set_percent_text("0%"); | ||||
|         //m_sizer->Hide(m_prog);
 | ||||
|         need_layout = true; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (!m_sizer->IsShown(m_prog)) { | ||||
|             m_sizer->Show(m_prog); | ||||
|             m_sizer->Show(m_cancelbutton); | ||||
|             need_layout = true; | ||||
|         } | ||||
|         m_prog->SetValue(val); | ||||
|         set_percent_text(wxString::Format("%d%%", val)); | ||||
|     } | ||||
| 
 | ||||
|     if (need_layout) { | ||||
|         m_sizer->Layout(); | ||||
|     if (!m_sizer->IsShown(m_prog)) { | ||||
|         m_sizer->Show(m_prog); | ||||
|         m_sizer->Show(m_cancelbutton); | ||||
|     } | ||||
|     m_prog->SetValue(val); | ||||
|     set_percent_text(wxString::Format("%d%%", val)); | ||||
|     m_sizer->Layout(); | ||||
| } | ||||
| 
 | ||||
| int BBLStatusBarBind::get_range() const | ||||
|  |  | |||
|  | @ -26,19 +26,19 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) | |||
|     wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL); | ||||
|     wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL); | ||||
| 
 | ||||
|     m_status_text = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, 0); | ||||
|     m_status_text = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxSize(m_self->FromDIP(280), -1), 0); | ||||
|     m_status_text->SetForegroundColour(wxColour(107, 107, 107)); | ||||
|     m_status_text->SetFont(::Label::Body_13); | ||||
|     m_status_text->Wrap(-1); | ||||
|     m_sizer_body->Add(m_status_text, 0, 0, 0); | ||||
|     m_status_text->Wrap(m_self->FromDIP(280)); | ||||
|     | ||||
| 
 | ||||
|     m_prog = new wxGauge(m_self, wxID_ANY, 100, wxDefaultPosition, wxSize(-1, m_self->FromDIP(6)), wxGA_HORIZONTAL); | ||||
|     m_prog->SetValue(0); | ||||
| 
 | ||||
|     block_left = new wxWindow(m_prog, wxID_ANY, wxPoint(0, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2)); | ||||
|     block_left->SetBackgroundColour(wxColour(255, 255, 255)); | ||||
|     block_right = new wxWindow(m_prog, wxID_ANY, wxPoint(m_prog->GetSize().GetWidth() - 2, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2)); | ||||
|     block_right->SetBackgroundColour(wxColour(255, 255, 255)); | ||||
|   /*  block_left = new wxWindow(m_prog, wxID_ANY, wxPoint(0, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2));
 | ||||
|       block_left->SetBackgroundColour(wxColour(255, 255, 255)); | ||||
|       block_right = new wxWindow(m_prog, wxID_ANY, wxPoint(m_prog->GetSize().GetWidth() - 2, 0), wxSize(2, m_prog->GetSize().GetHeight() * 2)); | ||||
|       block_right->SetBackgroundColour(wxColour(255, 255, 255));*/ | ||||
| 
 | ||||
|     m_sizer_bottom->Add(m_prog, 1, wxALIGN_CENTER, 0); | ||||
| 
 | ||||
|  | @ -47,9 +47,10 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) | |||
|     m_cancelbutton->SetTextColor(wxColour(107, 107, 107)); | ||||
|     m_cancelbutton->SetBackgroundColor(wxColour(255, 255, 255)); | ||||
|     m_cancelbutton->SetCornerRadius(12); | ||||
|     m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { | ||||
|     m_cancelbutton->Bind(wxEVT_BUTTON,  | ||||
|         [this](wxCommandEvent &evt) { | ||||
|         m_was_cancelled = true; | ||||
|         if (m_cancel_cb_fina)  | ||||
|         if (m_cancel_cb_fina) | ||||
|             m_cancel_cb_fina(); | ||||
|     }); | ||||
| 
 | ||||
|  | @ -60,7 +61,9 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) | |||
|     m_sizer_bottom->Add(m_stext_percent, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, 10); | ||||
| 
 | ||||
|     m_sizer_bottom->Add(m_cancelbutton, 0, wxALIGN_CENTER, 0); | ||||
|     m_sizer_body->Add(0, 0, 0, wxTOP, 5); | ||||
| 
 | ||||
|     m_sizer_body->Add(m_status_text, 0, 0, 0); | ||||
|     m_sizer_body->Add(0, 0, 0, wxTOP, 1); | ||||
|     m_sizer_body->Add(m_sizer_bottom, 1, wxEXPAND, 0); | ||||
| 
 | ||||
|     m_sizer->Add(m_sizer_body, 1, wxALIGN_CENTER, 0); | ||||
|  | @ -73,8 +76,8 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) | |||
| 
 | ||||
| void BBLStatusBarSend::set_prog_block() | ||||
| { | ||||
|     block_left->SetPosition(wxPoint(0, 0)); | ||||
|     block_right->SetPosition(wxPoint(m_prog->GetSize().GetWidth() - 2, 0)); | ||||
|     //block_left->SetPosition(wxPoint(0, 0));
 | ||||
|     //block_right->SetPosition(wxPoint(m_prog->GetSize().GetWidth() - 2, 0));
 | ||||
| } | ||||
| 
 | ||||
| int BBLStatusBarSend::get_progress() const | ||||
|  | @ -84,33 +87,19 @@ int BBLStatusBarSend::get_progress() const | |||
| 
 | ||||
| void BBLStatusBarSend::set_progress(int val) | ||||
| { | ||||
|     set_prog_block(); | ||||
|     //set_prog_block();
 | ||||
| 
 | ||||
|     if(val < 0) | ||||
|         return; | ||||
| 
 | ||||
|     bool need_layout = false; | ||||
|     //add the logic for arrange/orient jobs, which don't call stop_busy
 | ||||
|     if(val == m_prog->GetRange()) { | ||||
|         m_prog->SetValue(0); | ||||
|         set_percent_text("0%"); | ||||
|         m_sizer->Hide(m_prog); | ||||
|         need_layout = true; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (!m_sizer->IsShown(m_prog)) { | ||||
|             m_sizer->Show(m_prog); | ||||
|             m_sizer->Show(m_cancelbutton); | ||||
|             need_layout = true; | ||||
|         } | ||||
|         m_prog->SetValue(val); | ||||
|         set_percent_text(wxString::Format("%d%%", val)); | ||||
|     } | ||||
| 
 | ||||
|     if (need_layout) { | ||||
|         m_sizer->Layout(); | ||||
|     if (!m_sizer->IsShown(m_prog)) { | ||||
|         m_sizer->Show(m_prog); | ||||
|         m_sizer->Show(m_cancelbutton); | ||||
|     } | ||||
|     m_prog->SetValue(val); | ||||
|     set_percent_text(wxString::Format("%d%%", val)); | ||||
|     m_sizer->Layout(); | ||||
| } | ||||
| 
 | ||||
| int BBLStatusBarSend::get_range() const | ||||
|  | @ -185,6 +174,9 @@ void BBLStatusBarSend::set_status_text(const wxString& txt) | |||
|     //auto txtss = "The printing project is being uploaded... 25%%";
 | ||||
|     //m_status_text->SetLabelText(txtss);
 | ||||
|     m_status_text->SetLabelText(txt); | ||||
|     m_status_text->SetSize(wxSize(m_self->FromDIP(280), -1)); | ||||
|     m_status_text->SetMaxSize(wxSize(m_self->FromDIP(280), -1)); | ||||
|     m_status_text->Wrap(m_self->FromDIP(280)); | ||||
| } | ||||
| 
 | ||||
| void BBLStatusBarSend::set_percent_text(const wxString &txt) | ||||
|  | @ -203,7 +195,7 @@ void BBLStatusBarSend::set_status_text(const char *txt) | |||
| } | ||||
| 
 | ||||
| void BBLStatusBarSend::msw_rescale() {  | ||||
|     set_prog_block(); | ||||
|     //set_prog_block();
 | ||||
|     m_cancelbutton->SetMinSize(wxSize(m_self->FromDIP(56), m_self->FromDIP(24))); | ||||
| } | ||||
| 
 | ||||
|  | @ -230,6 +222,7 @@ void BBLStatusBarSend::reset() | |||
|     set_status_text(""); | ||||
|     m_was_cancelled = false; | ||||
|     set_progress(0); | ||||
|     set_percent_text(wxString::Format("%d%%", 0)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -250,4 +243,9 @@ void BBLStatusBarSend::hide_cancel_button() | |||
|     m_sizer->Layout(); | ||||
| } | ||||
| 
 | ||||
| void BBLStatusBarSend::change_button_label(wxString name)  | ||||
| { | ||||
|     m_cancelbutton->SetLabel(name); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -73,6 +73,7 @@ public: | |||
|     // Temporary methods to satisfy Perl side
 | ||||
|     void show_cancel_button(); | ||||
|     void hide_cancel_button(); | ||||
|     void change_button_label(wxString name); | ||||
| 
 | ||||
| private: | ||||
|     bool     m_busy = false; | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include "PartPlate.hpp" | ||||
| 
 | ||||
| #define TOPBAR_ICON_SIZE  18 | ||||
| #define TOPBAR_TITLE_WIDTH  300 | ||||
| 
 | ||||
| using namespace Slic3r; | ||||
| 
 | ||||
|  | @ -243,7 +244,7 @@ void BBLTopbar::Init(wxFrame* parent) | |||
|     this->AddSpacer(FromDIP(10)); | ||||
|     this->AddStretchSpacer(1); | ||||
| 
 | ||||
|     m_title_item = this->AddLabel(ID_TITLE, "", FromDIP(300)); | ||||
|     m_title_item = this->AddLabel(ID_TITLE, "", FromDIP(TOPBAR_TITLE_WIDTH)); | ||||
|     m_title_item->SetAlignment(wxCENTER); | ||||
| 
 | ||||
|     this->AddSpacer(FromDIP(10)); | ||||
|  | @ -402,6 +403,9 @@ wxMenu* BBLTopbar::GetTopMenu() | |||
| 
 | ||||
| void BBLTopbar::SetTitle(wxString title) | ||||
| { | ||||
|     wxGCDC dc(this); | ||||
|     title = wxControl::Ellipsize(title, dc, wxELLIPSIZE_END, FromDIP(TOPBAR_TITLE_WIDTH)); | ||||
| 
 | ||||
|     m_title_item->SetLabel(title); | ||||
|     m_title_item->SetAlignment(wxALIGN_CENTRE_HORIZONTAL); | ||||
|     this->Refresh(); | ||||
|  |  | |||
|  | @ -436,17 +436,23 @@ void UnBindMachineDilaog::on_unbind_printer(wxCommandEvent &event) | |||
|     if (result == 0) { | ||||
|         DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); | ||||
|         if (!dev) return; | ||||
|         dev->update_user_machine_list_info(); | ||||
|         // clean local machine access code info
 | ||||
|         MachineObject* obj = dev->get_local_machine(m_machine_info->dev_id); | ||||
|         if (obj) { | ||||
|             obj->set_access_code(""); | ||||
|         } | ||||
|         dev->erase_user_machine(m_machine_info->dev_id); | ||||
| 
 | ||||
|         m_status_text->SetLabelText(_L("Log out successful.")); | ||||
|         m_button_cancel->SetLabel(_L("Close")); | ||||
|         m_button_unbind->Hide(); | ||||
|         EndModal(wxID_OK); | ||||
|     } | ||||
|     else { | ||||
|         m_status_text->SetLabelText(_L("Failed to log out.")); | ||||
|         EndModal(wxID_CANCEL); | ||||
|         return; | ||||
|     } | ||||
|     EndModal(wxID_OK); | ||||
| } | ||||
| 
 | ||||
|  void UnBindMachineDilaog::on_dpi_changed(const wxRect &suggested_rect) | ||||
|  |  | |||
|  | @ -97,13 +97,23 @@ CalibrationDialog::CalibrationDialog(Plater *plater) | |||
| 
 | ||||
|     auto staticline = new ::StaticLine(cali_right_panel); | ||||
|     staticline->SetLineColour(wxColour(0x00, 0xAE, 0x42)); | ||||
| 
 | ||||
|     m_calibration_flow = new StepIndicator(cali_right_panel, wxID_ANY); | ||||
|     auto calibration_panel = new wxPanel(cali_right_panel); | ||||
|     calibration_panel->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); | ||||
|     auto calibration_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|     calibration_panel->SetMinSize(wxSize(FromDIP(170), FromDIP(160))); | ||||
|     calibration_panel->SetSize(wxSize(FromDIP(170), FromDIP(160))); | ||||
|     | ||||
|     m_calibration_flow = new StepIndicator(calibration_panel, wxID_ANY); | ||||
|     StateColor bg_color(std::pair<wxColour, int>(wxColour(248, 248, 248), StateColor::Normal)); | ||||
|     m_calibration_flow->SetBackgroundColor(bg_color); | ||||
|     m_calibration_flow->SetFont(Label::Body_12); | ||||
| 
 | ||||
|     m_calibration_flow->SetMinSize(wxSize(FromDIP(170), FromDIP(160))); | ||||
|     m_calibration_flow->SetSize(wxSize(FromDIP(170), FromDIP(160))); | ||||
|      | ||||
|     calibration_panel->SetSizer(calibration_sizer); | ||||
|     calibration_panel->Layout(); | ||||
|     calibration_sizer->Add(m_calibration_flow, 0, wxALIGN_CENTER_HORIZONTAL | wxEXPAND, 0); | ||||
| 
 | ||||
|     StateColor btn_bg_green(std::pair<wxColour, int>(AMS_CONTROL_DISABLE_COLOUR, StateColor::Disabled), std::pair<wxColour, int>(wxColour(27, 136, 68), StateColor::Pressed), | ||||
|                             std::pair<wxColour, int>(wxColour(61, 203, 115), StateColor::Hovered), std::pair<wxColour, int>(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); | ||||
|  | @ -119,10 +129,10 @@ CalibrationDialog::CalibrationDialog(Plater *plater) | |||
|     cali_right_sizer_v->Add(cali_text_right_top, 0, wxALIGN_CENTER, 0); | ||||
|     cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(7)); | ||||
|     cali_right_sizer_v->Add(staticline, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(10)); | ||||
|     cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(9)); | ||||
|     cali_right_sizer_v->Add(m_calibration_flow, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(6)); | ||||
|     cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(10)); | ||||
|     cali_right_sizer_v->Add(m_calibration_btn, 0, wxALIGN_CENTER, 0); | ||||
|     cali_right_sizer_v->Add(0, 0, 0, wxTOP, FromDIP(3)); | ||||
|     cali_right_sizer_v->Add(calibration_panel, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, FromDIP(6)); | ||||
|     cali_right_sizer_v->Add(0, 0, 1, wxEXPAND, 5); | ||||
|     cali_right_sizer_v->Add(m_calibration_btn, 0, wxALIGN_CENTER_HORIZONTAL, 0); | ||||
| 
 | ||||
|     cali_right_sizer_h->Add(cali_right_sizer_v, 0, wxALIGN_CENTER, 0); | ||||
|     cali_right_panel->SetSizer(cali_right_sizer_h); | ||||
|  | @ -137,7 +147,6 @@ CalibrationDialog::CalibrationDialog(Plater *plater) | |||
|     SetSizer(m_sizer_main); | ||||
|     Layout(); | ||||
|     Fit(); | ||||
|     Centre(wxBOTH); | ||||
| 
 | ||||
|     Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &evt) { Hide(); }); | ||||
| 
 | ||||
|  | @ -151,29 +160,41 @@ void CalibrationDialog::on_dpi_changed(const wxRect &suggested_rect) {} | |||
| void CalibrationDialog::update_cali(MachineObject *obj) | ||||
| { | ||||
|     if (!obj) return; | ||||
| 
 | ||||
|     // in printing
 | ||||
|     if (obj->is_in_printing()) { | ||||
|         m_calibration_flow->DeleteAllItems(); | ||||
|         m_calibration_btn->Disable(); | ||||
|         return; | ||||
|     } else { | ||||
|          m_calibration_btn->Enable(); | ||||
|         if (!obj->is_in_calibration()) { | ||||
|             m_calibration_flow->DeleteAllItems(); | ||||
|             m_calibration_btn->SetLabel(_L("Start Calibration")); | ||||
|     if (obj->is_in_calibration() || obj->is_calibration_done()) { | ||||
|         if (obj->is_calibration_done()) { | ||||
|             m_calibration_btn->Enable(); | ||||
|             m_calibration_btn->SetLabel(_L("Completed")); | ||||
|         } else { | ||||
|             // RUNNING && IDLE
 | ||||
|             m_calibration_btn->Disable(); | ||||
|             m_calibration_btn->SetLabel(_L("Calibrating")); | ||||
| 
 | ||||
|             if (is_stage_list_info_changed(obj)) { | ||||
|                 // change items if stage_list_info changed
 | ||||
|                 m_calibration_flow->DeleteAllItems(); | ||||
|                 for (int i = 0; i < obj->stage_list_info.size(); i++) { m_calibration_flow->AppendItem(get_stage_string(obj->stage_list_info[i])); } | ||||
|             } | ||||
|             int index = obj->get_curr_stage_idx(); | ||||
|             m_calibration_flow->SelectItem(index); | ||||
|         } | ||||
|         auto size = wxSize(-1, obj->stage_list_info.size() * FromDIP(44)); | ||||
|         if (m_calibration_flow->GetSize().y != size.y) { | ||||
|             m_calibration_flow->SetSize(size); | ||||
|             m_calibration_flow->SetMinSize(size); | ||||
|             m_calibration_flow->SetMaxSize(size); | ||||
|             Layout(); | ||||
|         } | ||||
|         if (is_stage_list_info_changed(obj)) { | ||||
|             // change items if stage_list_info changed
 | ||||
|             m_calibration_flow->DeleteAllItems(); | ||||
|             for (int i = 0; i < obj->stage_list_info.size(); i++) { | ||||
|                 m_calibration_flow->AppendItem(get_stage_string(obj->stage_list_info[i])); | ||||
|             } | ||||
|         } | ||||
|         int index = obj->get_curr_stage_idx(); | ||||
|         m_calibration_flow->SelectItem(index); | ||||
|     } else { | ||||
|         // IDLE
 | ||||
|         if (obj->is_in_printing()) { | ||||
|             m_calibration_btn->Disable(); | ||||
|         } | ||||
|         else { | ||||
|             m_calibration_btn->Enable(); | ||||
|         } | ||||
|         m_calibration_flow->DeleteAllItems(); | ||||
|         m_calibration_btn->SetLabel(_L("Start Calibration")); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -193,11 +214,23 @@ bool CalibrationDialog::is_stage_list_info_changed(MachineObject *obj) | |||
| void CalibrationDialog::on_start_calibration(wxMouseEvent &event) | ||||
| { | ||||
|     if (m_obj) { | ||||
|         BOOST_LOG_TRIVIAL(trace) << "on_start_calibration"; | ||||
|         m_obj->command_start_calibration(); | ||||
|         if (m_obj->is_calibration_done()) { | ||||
|             m_obj->calibration_done = false; | ||||
|             EndModal(wxID_CANCEL); | ||||
|             Close(); | ||||
|         } else { | ||||
|             BOOST_LOG_TRIVIAL(info) << "on_start_calibration"; | ||||
|             m_obj->command_start_calibration(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CalibrationDialog::update_machine_obj(MachineObject *obj) { m_obj = obj; } | ||||
| 
 | ||||
| bool CalibrationDialog::Show(bool show)  | ||||
| { | ||||
|     if (show) { CentreOnParent(); } | ||||
|     return DPIDialog::Show(show); | ||||
| } | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
|  |  | |||
|  | @ -50,6 +50,7 @@ public: | |||
|     bool             is_stage_list_info_changed(MachineObject *obj); | ||||
|     void             on_start_calibration(wxMouseEvent &event); | ||||
|     void             update_machine_obj(MachineObject *obj); | ||||
|     bool             Show(bool show) override; | ||||
| }; | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
|  |  | |||
|  | @ -3,6 +3,10 @@ | |||
| #include "I18N.hpp" | ||||
| #include "Widgets/Label.hpp" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "BitmapCache.hpp" | ||||
| #include <wx/progdlg.h> | ||||
| #include <wx/clipbrd.h> | ||||
| #include <wx/dcgraph.h> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
|  | @ -128,5 +132,94 @@ void CameraPopup::OnMouse(wxMouseEvent &event) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| CameraItem::CameraItem(wxWindow *parent,std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover) | ||||
|     : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) | ||||
| { | ||||
| #ifdef __WINDOWS__ | ||||
|     SetDoubleBuffered(true); | ||||
| #endif //__WINDOWS__
 | ||||
| 
 | ||||
|     m_bitmap_on_normal  = create_scaled_bitmap(on_normal, nullptr, 20); | ||||
|     m_bitmap_off_normal = create_scaled_bitmap(off_normal, nullptr, 20); | ||||
|     m_bitmap_on_hover   = create_scaled_bitmap(on_hover, nullptr, 20); | ||||
|     m_bitmap_off_hover  = create_scaled_bitmap(off_hover, nullptr, 20); | ||||
| 
 | ||||
|     SetSize(wxSize(FromDIP(20), FromDIP(20))); | ||||
|     SetMinSize(wxSize(FromDIP(20), FromDIP(20))); | ||||
|     SetMaxSize(wxSize(FromDIP(20), FromDIP(20))); | ||||
|     Bind(wxEVT_PAINT, &CameraItem::paintEvent, this); | ||||
|     Bind(wxEVT_ENTER_WINDOW, &CameraItem::on_enter_win, this); | ||||
|     Bind(wxEVT_LEAVE_WINDOW, &CameraItem::on_level_win, this); | ||||
| } | ||||
| 
 | ||||
| CameraItem::~CameraItem() {} | ||||
| 
 | ||||
| void CameraItem::msw_rescale() {} | ||||
| 
 | ||||
| void CameraItem::set_switch(bool is_on) | ||||
| { | ||||
|     m_on = is_on; | ||||
|     Refresh(); | ||||
| } | ||||
| 
 | ||||
| void CameraItem::on_enter_win(wxMouseEvent &evt) | ||||
| { | ||||
|     m_hover = true; | ||||
|     Refresh(); | ||||
| } | ||||
| 
 | ||||
| void CameraItem::on_level_win(wxMouseEvent &evt) | ||||
| { | ||||
|     m_hover = false; | ||||
|     Refresh(); | ||||
| } | ||||
| 
 | ||||
| void CameraItem::paintEvent(wxPaintEvent &evt) | ||||
| { | ||||
|     wxPaintDC dc(this); | ||||
|     render(dc); | ||||
| 
 | ||||
|     // PrepareDC(buffdc);
 | ||||
|     // PrepareDC(dc);
 | ||||
| } | ||||
| 
 | ||||
| void CameraItem::render(wxDC &dc) | ||||
| { | ||||
| #ifdef __WXMSW__ | ||||
|     wxSize     size = GetSize(); | ||||
|     wxMemoryDC memdc; | ||||
|     wxBitmap   bmp(size.x, size.y); | ||||
|     memdc.SelectObject(bmp); | ||||
|     memdc.Blit({0, 0}, size, &dc, {0, 0}); | ||||
| 
 | ||||
|     { | ||||
|         wxGCDC dc2(memdc); | ||||
|         doRender(dc2); | ||||
|     } | ||||
| 
 | ||||
|     memdc.SelectObject(wxNullBitmap); | ||||
|     dc.DrawBitmap(bmp, 0, 0); | ||||
| #else | ||||
|     doRender(dc); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void CameraItem::doRender(wxDC &dc) | ||||
| { | ||||
|     if (m_on) { | ||||
|         if (m_hover) { | ||||
|             dc.DrawBitmap(m_bitmap_on_hover, wxPoint((GetSize().x - m_bitmap_on_hover.GetSize().x) / 2, (GetSize().y - m_bitmap_on_hover.GetSize().y) / 2)); | ||||
|         } else { | ||||
|             dc.DrawBitmap(m_bitmap_on_normal, wxPoint((GetSize().x - m_bitmap_on_normal.GetSize().x) / 2, (GetSize().y - m_bitmap_on_normal.GetSize().y) / 2)); | ||||
|         } | ||||
| 
 | ||||
|     } else { | ||||
|         if (m_hover) { | ||||
|             dc.DrawBitmap(m_bitmap_off_hover, wxPoint((GetSize().x - m_bitmap_off_hover.GetSize().x) / 2, (GetSize().y - m_bitmap_off_hover.GetSize().y) / 2)); | ||||
|         } else { | ||||
|             dc.DrawBitmap(m_bitmap_off_normal, wxPoint((GetSize().x - m_bitmap_off_normal.GetSize().x) / 2, (GetSize().y - m_bitmap_off_normal.GetSize().y) / 2)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| } | ||||
|  | @ -5,6 +5,11 @@ | |||
| #include "DeviceManager.hpp" | ||||
| #include "GUI.hpp" | ||||
| #include <wx/panel.h> | ||||
| #include <wx/bitmap.h> | ||||
| #include <wx/image.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/gbsizer.h> | ||||
| #include <wx/webrequest.h> | ||||
| #include "Widgets/SwitchButton.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -44,6 +49,31 @@ private: | |||
|     wxDECLARE_EVENT_TABLE(); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class CameraItem : public wxPanel | ||||
| { | ||||
| public: | ||||
|     CameraItem(wxWindow *parent, std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover); | ||||
|     ~CameraItem(); | ||||
| 
 | ||||
|     MachineObject *m_obj{nullptr}; | ||||
|     bool     m_on{false}; | ||||
|     bool     m_hover{false}; | ||||
|     wxBitmap m_bitmap_on_normal; | ||||
|     wxBitmap m_bitmap_on_hover; | ||||
|     wxBitmap m_bitmap_off_normal; | ||||
|     wxBitmap m_bitmap_off_hover; | ||||
| 
 | ||||
|     void msw_rescale(); | ||||
|     void set_switch(bool is_on); | ||||
|     bool get_switch_status() { return m_on; }; | ||||
|     void on_enter_win(wxMouseEvent &evt); | ||||
|     void on_level_win(wxMouseEvent &evt); | ||||
|     void paintEvent(wxPaintEvent &evt); | ||||
|     void render(wxDC &dc); | ||||
|     void doRender(wxDC &dc); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -519,7 +519,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co | |||
|     for (auto el : { "support_style", "support_base_pattern", | ||||
|                     "support_base_pattern_spacing", "support_angle", | ||||
|                     "support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers", | ||||
|                     "bridge_no_support","max_bridge_length" "support_top_z_distance", | ||||
|                     "bridge_no_support", "thick_bridges", "max_bridge_length", "support_top_z_distance", | ||||
|                      //BBS: add more support params to dependent of enable_support
 | ||||
|                     "support_type","support_on_build_plate_only", | ||||
|                     "support_object_xy_distance", "independent_support_layer_height"}) | ||||
|  | @ -537,6 +537,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co | |||
|     toggle_line("tree_support_branch_angle", support_is_tree); | ||||
|     toggle_line("tree_support_wall_count", support_is_tree); | ||||
|     toggle_line("tree_support_with_infill", support_is_tree); | ||||
|     toggle_line("max_bridge_length", support_is_tree); | ||||
| 
 | ||||
|     // tree support use max_bridge_length instead of bridge_no_support
 | ||||
|     toggle_line("bridge_no_support", !support_is_tree); | ||||
| 
 | ||||
|     for (auto el : { "support_interface_spacing", "support_interface_filament", | ||||
|                      "support_interface_loop_pattern", "support_bottom_interface_spacing" }) | ||||
|  |  | |||
|  | @ -96,7 +96,7 @@ ConnectPrinterDialog::ConnectPrinterDialog(wxWindow *parent, wxWindowID id, cons | |||
|     this->SetSizer(main_sizer); | ||||
|     this->Layout(); | ||||
|     this->Fit(); | ||||
|     this->Centre(wxBOTH); | ||||
|     CentreOnParent(); | ||||
| 
 | ||||
|     m_textCtrl_code->Bind(wxEVT_TEXT, &ConnectPrinterDialog::on_input_enter, this); | ||||
|     m_button_confirm->Bind(wxEVT_BUTTON, &ConnectPrinterDialog::on_button_confirm, this); | ||||
|  |  | |||
|  | @ -8,8 +8,9 @@ | |||
| #include "libslic3r/PlaceholderParser.hpp" | ||||
| #include "libslic3r/Print.hpp" | ||||
| #include "libslic3r/PrintConfig.hpp" | ||||
| #include "MsgDialog.hpp" | ||||
| #include "Plater.hpp" | ||||
| 
 | ||||
| #include "GUI_App.hpp" | ||||
| #include "nlohmann/json.hpp" | ||||
| #include <thread> | ||||
| #include <mutex> | ||||
|  | @ -24,7 +25,6 @@ using namespace nlohmann; | |||
| 
 | ||||
| namespace pt = boost::property_tree; | ||||
| 
 | ||||
| 
 | ||||
| const int PRINTING_STAGE_COUNT = 20; | ||||
| std::string PRINTING_STAGE_STR[PRINTING_STAGE_COUNT] = { | ||||
|     "printing", | ||||
|  | @ -455,6 +455,16 @@ void MachineObject::_parse_ams_status(int ams_status) | |||
|     BOOST_LOG_TRIVIAL(trace) << "ams_debug: main = " << ams_status_main_int << ", sub = " << ams_status_sub; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_U0_firmware() | ||||
| { | ||||
|     auto ota_ver_it = module_vers.find("ota"); | ||||
|     if (ota_ver_it != module_vers.end()) { | ||||
|         if (ota_ver_it->second.sw_ver.compare("00.01.04.00") < 0) | ||||
|             return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_support_ams_mapping() | ||||
| { | ||||
|     AppConfig* config = Slic3r::GUI::wxGetApp().app_config; | ||||
|  | @ -590,7 +600,6 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std | |||
| 
 | ||||
|     // tray_index : tray_color
 | ||||
|     std::map<int, FilamentInfo> tray_filaments; | ||||
| 
 | ||||
|     for (auto ams = amsList.begin(); ams != amsList.end(); ams++) { | ||||
|         for (auto tray = ams->second->trayList.begin(); tray != ams->second->trayList.end(); tray++) { | ||||
|             int ams_id = atoi(ams->first.c_str()); | ||||
|  | @ -634,45 +643,48 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std | |||
| 
 | ||||
|     // is_support_ams_mapping
 | ||||
|     if (!is_support_ams_mapping()) { | ||||
|         BOOST_LOG_TRIVIAL(info) << "ams_mapping: do not support, use order mapping"; | ||||
|         for (int i = 0; i < filaments.size(); i++) { | ||||
|             FilamentInfo info; | ||||
|             if (i < tray_info_list.size()) { | ||||
|                 info.id = filaments[i].id; | ||||
|                 info.tray_id = filaments[i].id; | ||||
|                 info.color = tray_info_list[i].color; | ||||
|                 info.type = tray_info_list[i].type; | ||||
|             } else { | ||||
|                 info.id = filaments[i].id; | ||||
|                 info.tray_id = -1; | ||||
|             } | ||||
|             info.id = filaments[i].id; | ||||
|             info.tray_id = -1; | ||||
|             result.push_back(info); | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     // calc distance map
 | ||||
|     struct DisValue { | ||||
|         int  tray_id; | ||||
|         float distance; | ||||
|         bool  is_same_color = true; | ||||
|         bool  is_type_match = true; | ||||
|     }; | ||||
|     char buffer[256]; | ||||
|     std::vector<std::vector<DisValue>> distance_map; | ||||
| 
 | ||||
|     // print title
 | ||||
|     ::sprintf(buffer, "F(id)"); | ||||
|     std::string line = std::string(buffer); | ||||
|     for (auto tray = tray_filaments.begin(); tray != tray_filaments.end(); tray++) { | ||||
|         ::sprintf(buffer, "   AMS%02d", tray->second.id+1); | ||||
|         line += std::string(buffer); | ||||
|     } | ||||
|     BOOST_LOG_TRIVIAL(info) << "ams_mapping_distance:" << line; | ||||
| 
 | ||||
|     for (int i = 0; i < filaments.size(); i++) { | ||||
|         std::vector<DisValue> rol; | ||||
|         ::sprintf(buffer, "F(%02d)", filaments[i].id+1); | ||||
|         line = std::string(buffer); | ||||
|         for (auto tray = tray_filaments.begin(); tray != tray_filaments.end(); tray++) { | ||||
|             DisValue val; | ||||
|             val.tray_id = tray->first; | ||||
|             val.tray_id = tray->second.id; | ||||
|             wxColour c = wxColour(filaments[i].color); | ||||
|             val.distance = calc_color_distance(c, AmsTray::decode_color(tray->second.color)); | ||||
|             //val.is_same_color = val.distance < MAPPING_COLOR_THRESHOLD;
 | ||||
|             if (filaments[i].type != tray->second.type) { | ||||
|                 val.distance = 999999; | ||||
|                 val.is_type_match = false; | ||||
|             } else { | ||||
|                 val.is_type_match = true; | ||||
|             } | ||||
|             ::sprintf(buffer, "  %6.0f", val.distance); | ||||
|             line += std::string(buffer); | ||||
|             rol.push_back(val); | ||||
|         } | ||||
|         BOOST_LOG_TRIVIAL(info) << "ams_mapping_distance:" << line; | ||||
|         distance_map.push_back(rol); | ||||
|     } | ||||
| 
 | ||||
|  | @ -683,6 +695,7 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std | |||
|         info.tray_id = -1; | ||||
|         result.push_back(info); | ||||
|     } | ||||
| 
 | ||||
|     std::set<int> picked_src; | ||||
|     std::set<int> picked_tar; | ||||
|     for (int k = 0; k < distance_map.size(); k++) { | ||||
|  | @ -693,8 +706,9 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std | |||
|             if (picked_src.find(i) != picked_src.end()) | ||||
|                 continue; | ||||
|             for (int j = 0; j < distance_map[i].size(); j++) { | ||||
|                 if (picked_tar.find(j) == picked_tar.end() | ||||
|                     && distance_map[i][j].is_same_color | ||||
|                 if (picked_tar.find(j) != picked_tar.end()) | ||||
|                     continue; | ||||
|                 if (distance_map[i][j].is_same_color | ||||
|                     && distance_map[i][j].is_type_match) { | ||||
|                     if (min_val > distance_map[i][j].distance) { | ||||
|                         min_val = distance_map[i][j].distance; | ||||
|  | @ -707,25 +721,31 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std | |||
|         if (picked_src_idx >= 0 && picked_tar_idx >= 0) { | ||||
|             auto tray = tray_filaments.find(distance_map[k][picked_tar_idx].tray_id); | ||||
|             if (tray != tray_filaments.end()) { | ||||
|                 result[picked_src_idx].tray_id = tray->first; | ||||
|                 result[picked_src_idx].color = tray->second.color; | ||||
|                 result[picked_src_idx].type = tray->second.type; | ||||
|                 BOOST_LOG_TRIVIAL(trace) << "tray_id = " << tray->first << ", distance = " << distance_map[k][picked_tar_idx].distance; | ||||
|                 result[picked_src_idx].tray_id  = tray->first; | ||||
|                 result[picked_src_idx].color    = tray->second.color; | ||||
|                 result[picked_src_idx].type     = tray->second.type; | ||||
|                 result[picked_src_idx].distance = tray->second.distance; | ||||
|             } | ||||
|             else { | ||||
|                 FilamentInfo info; | ||||
|                 info.tray_id = -1; | ||||
|             } | ||||
|             picked_tar.insert(picked_tar_idx); | ||||
|             ::sprintf(buffer, "ams_mapping, picked F(%02d) AMS(%02d), distance=%6.0f", picked_src_idx+1, picked_tar_idx+1, | ||||
|                 distance_map[picked_src_idx][picked_tar_idx].distance); | ||||
|             BOOST_LOG_TRIVIAL(info) << std::string(buffer); | ||||
|             picked_src.insert(picked_src_idx); | ||||
|             picked_tar.insert(picked_tar_idx); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::vector<FilamentInfo> cache_map_result = result; | ||||
| 
 | ||||
|     //check ams mapping result
 | ||||
|     if (is_valid_mapping_result(result)) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     reset_mapping_result(result); | ||||
|     try { | ||||
|         // try to use ordering ams mapping
 | ||||
|         bool order_mapping_result = true; | ||||
|  | @ -749,15 +769,23 @@ int MachineObject::ams_filament_mapping(std::vector<FilamentInfo> filaments, std | |||
|         } | ||||
| 
 | ||||
|         //check order mapping result
 | ||||
|         if (!is_valid_mapping_result(result)) { | ||||
|             reset_mapping_result(result); | ||||
|             return -1; | ||||
|         if (is_valid_mapping_result(result)) { | ||||
|             return 0; | ||||
|         } | ||||
|     } catch(...) { | ||||
|         reset_mapping_result(result); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     // try to match some color
 | ||||
|     reset_mapping_result(result); | ||||
|     result = cache_map_result; | ||||
|     for (auto it = result.begin(); it != result.end(); it++) { | ||||
|         if (it->distance >= 6000) { | ||||
|             it->tray_id = -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -778,6 +806,7 @@ void MachineObject::reset_mapping_result(std::vector<FilamentInfo>& result) | |||
| { | ||||
|     for (int i = 0; i < result.size(); i++) { | ||||
|         result[i].tray_id = -1; | ||||
|         result[i].distance = 99999; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -904,7 +933,7 @@ std::map<int, MachineObject::ModuleVersionInfo> MachineObject::get_ams_version() | |||
| 
 | ||||
| bool MachineObject::is_system_printing() | ||||
| { | ||||
|     if (is_in_calibration()) | ||||
|     if (is_in_calibration() && is_in_printing_status(print_status)) | ||||
|         return true; | ||||
|     //FIXME
 | ||||
|     //if (print_type == "system" && is_in_printing_status(print_status))
 | ||||
|  | @ -936,10 +965,40 @@ bool MachineObject::is_in_calibration() | |||
|     if (boost::contains(m_gcode_file, "auto_cali_for_user.gcode") | ||||
|         && stage_curr != 0) { | ||||
|         return true; | ||||
|     } else { | ||||
|         // reset
 | ||||
|         if (stage_curr != 0) { | ||||
|             calibration_done = false; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_calibration_done() | ||||
| { | ||||
|     return calibration_done; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_calibration_running() | ||||
| { | ||||
|     if (is_in_calibration() && is_in_printing_status(print_status)) | ||||
|         return true; | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void MachineObject::parse_state_changed_event() | ||||
| { | ||||
|     // parse calibration done
 | ||||
|     if (last_mc_print_stage != mc_print_stage) { | ||||
|         if (mc_print_stage == 1 && boost::contains(m_gcode_file, "auto_cali_for_user.gcode")) { | ||||
|             calibration_done = true; | ||||
|         } else { | ||||
|             calibration_done = false; | ||||
|         } | ||||
|     } | ||||
|     last_mc_print_stage = mc_print_stage; | ||||
| } | ||||
| 
 | ||||
| PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl) | ||||
| { | ||||
|     if (lvl < (int)SPEED_LEVEL_COUNT) | ||||
|  | @ -950,7 +1009,10 @@ PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl) | |||
| 
 | ||||
| bool MachineObject::is_sdcard_printing() | ||||
| { | ||||
|     if (can_abort() && obj_subtask_id.compare("0") == 0 && profile_id_ == "0" && project_id_ == "0") | ||||
|     if (can_abort() | ||||
|         && (obj_subtask_id.compare("0") == 0 || obj_subtask_id.empty()) | ||||
|         && (profile_id_ == "0" || profile_id_.empty()) | ||||
|         && (project_id_ == "0" || project_id_.empty())) | ||||
|         return true; | ||||
|     else | ||||
|         return false; | ||||
|  | @ -961,6 +1023,16 @@ bool MachineObject::has_sdcard() | |||
|     return camera_has_sdcard; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::has_timelapse() | ||||
| { | ||||
|     return camera_timelapse; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::has_recording() | ||||
| { | ||||
|     return camera_recording; | ||||
| } | ||||
| 
 | ||||
| int MachineObject::command_get_version() | ||||
| { | ||||
|     json j; | ||||
|  | @ -974,10 +1046,10 @@ int MachineObject::command_request_push_all() | |||
|     auto curr_time = std::chrono::system_clock::now(); | ||||
|     auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - last_request_push); | ||||
|     if (diff.count() < REQUEST_PUSH_MIN_TIME) { | ||||
|         BOOST_LOG_TRIVIAL(trace) << "command_request_push_all: send request too fast"; | ||||
|         BOOST_LOG_TRIVIAL(trace) << "static: command_request_push_all: send request too fast, dev_id=" << dev_id; | ||||
|         return -1; | ||||
|     } else { | ||||
|         BOOST_LOG_TRIVIAL(trace) << "command_request_push_all"; | ||||
|         BOOST_LOG_TRIVIAL(trace) << "static: command_request_push_all, dev_id=" << dev_id; | ||||
|         last_request_push = std::chrono::system_clock::now(); | ||||
|     } | ||||
|     json j; | ||||
|  | @ -1365,6 +1437,11 @@ bool MachineObject::is_in_printing() | |||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_in_prepare() | ||||
| { | ||||
|     return print_status == "PREPARE"; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_printing_finished() | ||||
| { | ||||
|     if (print_status.compare("FINISH") == 0 | ||||
|  | @ -1388,8 +1465,10 @@ void MachineObject::reset() | |||
|     camera_recording = false; | ||||
|     camera_timelapse = false; | ||||
|     printing_speed_mag = 100; | ||||
|     gcode_file_prepare_percent = 0; | ||||
|     iot_print_status = ""; | ||||
|     print_status = ""; | ||||
|     last_mc_print_stage = -1; | ||||
| 
 | ||||
|     subtask_ = nullptr; | ||||
| 
 | ||||
|  | @ -1444,6 +1523,11 @@ bool MachineObject::is_connected() | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool MachineObject::is_connecting() | ||||
| { | ||||
|     return is_connected() && m_push_count == 0; | ||||
| } | ||||
| 
 | ||||
| void MachineObject::set_online_state(bool on_off) | ||||
| { | ||||
|     m_is_online = on_off; | ||||
|  | @ -1508,9 +1592,10 @@ int MachineObject::parse_json(std::string payload) | |||
|         if (j_pre.contains("print")) { | ||||
|             if (j_pre["print"].contains("command")) { | ||||
|                 if (j_pre["print"]["command"].get<std::string>() == "push_status") { | ||||
|                     m_push_count++; | ||||
|                     if (j_pre["print"].contains("msg")) { | ||||
|                         if (j_pre["print"]["msg"].get<int>() == 0) {           //all message
 | ||||
|                             BOOST_LOG_TRIVIAL(trace) << "static: get push_all msg, dev_id=" << dev_id; | ||||
|                             m_push_count++; | ||||
|                             print_json.diff2all_base_reset(j_pre); | ||||
|                         } else if (j_pre["print"]["msg"].get<int>() == 1) {    //diff message
 | ||||
|                             if (print_json.diff2all(j_pre, j) == 0) { | ||||
|  | @ -1544,11 +1629,14 @@ int MachineObject::parse_json(std::string payload) | |||
|             json jj = j["print"]; | ||||
|             if (jj.contains("command")) { | ||||
|                 if (jj["command"].get<std::string>() == "push_status") { | ||||
|                     m_push_count++; | ||||
|                     last_push_time = std::chrono::system_clock::now(); | ||||
| #pragma region printing | ||||
|                     // U0 firmware
 | ||||
|                     if (jj.contains("print_type")) { | ||||
|                         print_type = jj["print_type"].get<std::string>(); | ||||
|                     } | ||||
| 
 | ||||
|                     if (jj.contains("mc_remaining_time")) { | ||||
|                         if (jj["mc_remaining_time"].is_string()) | ||||
|                             mc_left_time = stoi(j["print"]["mc_remaining_time"].get<std::string>()) * 60; | ||||
|  | @ -1603,8 +1691,15 @@ int MachineObject::parse_json(std::string payload) | |||
| 
 | ||||
|                     if (jj.contains("gcode_file")) | ||||
|                         this->m_gcode_file = jj["gcode_file"].get<std::string>(); | ||||
| 
 | ||||
|                     if (jj.contains("project_id")  | ||||
|                     if (jj.contains("gcode_file_prepare_percent")) { | ||||
|                         std::string percent_str = jj["gcode_file_prepare_percent"].get<std::string>(); | ||||
|                         if (!percent_str.empty()) { | ||||
|                             try{ | ||||
|                                 this->gcode_file_prepare_percent = atoi(percent_str.c_str()); | ||||
|                             } catch(...) {} | ||||
|                         } | ||||
|                     } | ||||
|                     if (jj.contains("project_id") | ||||
|                         && jj.contains("profile_id") | ||||
|                         && jj.contains("subtask_id") | ||||
|                         ){ | ||||
|  | @ -1633,11 +1728,11 @@ int MachineObject::parse_json(std::string payload) | |||
|                             curr_task->task_progress = mc_print_percent; | ||||
|                             curr_task->printing_status = print_status; | ||||
|                             curr_task->task_id = jj["subtask_id"].get<std::string>(); | ||||
|                              | ||||
| 
 | ||||
|                         } | ||||
|                     } | ||||
| #pragma endregion | ||||
|                      | ||||
| 
 | ||||
| #pragma region status | ||||
|                     /* temperature */ | ||||
|                     if (jj.contains("bed_temper")) { | ||||
|  | @ -1755,14 +1850,14 @@ int MachineObject::parse_json(std::string payload) | |||
|                             camera_has_sdcard = jj["sdcard"].get<bool>(); | ||||
|                         } else { | ||||
|                             //do not check sdcard if no sdcard field
 | ||||
|                             camera_has_sdcard = true; | ||||
|                             camera_has_sdcard = false; | ||||
|                         } | ||||
|                     } | ||||
|                     catch (...) { | ||||
|                         ; | ||||
|                     } | ||||
| #pragma endregion | ||||
|                      | ||||
| 
 | ||||
| #pragma region upgrade | ||||
|                     try { | ||||
|                         if (jj.contains("upgrade_state")) { | ||||
|  | @ -1788,9 +1883,15 @@ int MachineObject::parse_json(std::string payload) | |||
|                                 upgrade_force_upgrade = jj["upgrade_state"]["force_upgrade"].get<bool>(); | ||||
|                             if (jj["upgrade_state"].contains("err_code")) | ||||
|                                 upgrade_err_code = jj["upgrade_state"]["err_code"].get<int>(); | ||||
|                             if (jj["upgrade_state"].contains("dis_state")) | ||||
|                             if (jj["upgrade_state"].contains("dis_state")) { | ||||
|                                 if (upgrade_display_state != jj["upgrade_state"]["dis_state"].get<int>() | ||||
|                                     && jj["upgrade_state"]["dis_state"].get<int>() == 3) { | ||||
|                                     GUI::wxGetApp().CallAfter([this] { | ||||
|                                         this->command_get_version(); | ||||
|                                     }); | ||||
|                                 } | ||||
|                                 upgrade_display_state = jj["upgrade_state"]["dis_state"].get<int>(); | ||||
|                             else { | ||||
|                             } else { | ||||
|                                 //BBS compatibility with old version
 | ||||
|                                 if (upgrade_status == "DOWNLOADING" | ||||
|                                     || upgrade_status == "FLASHING" | ||||
|  | @ -1847,7 +1948,7 @@ int MachineObject::parse_json(std::string payload) | |||
|                     catch (...) { | ||||
|                         ; | ||||
|                     } | ||||
| #pragma endregion             | ||||
| #pragma endregion | ||||
| 
 | ||||
| #pragma region hms | ||||
|                     // parse hms msg
 | ||||
|  | @ -1977,9 +2078,17 @@ int MachineObject::parse_json(std::string payload) | |||
|                                             curr_tray = tray_iter->second; | ||||
|                                         } | ||||
|                                         if (!curr_tray) continue; | ||||
| 
 | ||||
|                                         if (curr_tray->hold_count > 0) { | ||||
|                                             curr_tray->hold_count--; | ||||
|                                             continue; | ||||
|                                         } | ||||
| 
 | ||||
|                                         curr_tray->id = (*tray_it)["id"].get<std::string>(); | ||||
|                                         if (tray_it->contains("tag_uid")) | ||||
|                                             curr_tray->tag_uid          = (*tray_it)["tag_uid"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->tag_uid = "0"; | ||||
|                                         if (tray_it->contains("tray_info_idx") && tray_it->contains("tray_type")) { | ||||
|                                             curr_tray->setting_id       = (*tray_it)["tray_info_idx"].get<std::string>(); | ||||
|                                             std::string type            = (*tray_it)["tray_type"].get<std::string>(); | ||||
|  | @ -1990,32 +2099,59 @@ int MachineObject::parse_json(std::string payload) | |||
|                                             } else { | ||||
|                                                 curr_tray->type = type; | ||||
|                                             } | ||||
|                                         } else { | ||||
|                                             curr_tray->setting_id = ""; | ||||
|                                             curr_tray->type       = ""; | ||||
|                                         } | ||||
|                                         if (tray_it->contains("tray_sub_brands")) | ||||
|                                             curr_tray->sub_brands       = (*tray_it)["tray_sub_brands"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->sub_brands = ""; | ||||
|                                         if (tray_it->contains("tray_weight")) | ||||
|                                             curr_tray->weight           = (*tray_it)["tray_weight"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->weight = ""; | ||||
|                                         if (tray_it->contains("tray_diameter")) | ||||
|                                             curr_tray->diameter         = (*tray_it)["tray_diameter"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->diameter = ""; | ||||
|                                         if (tray_it->contains("tray_temp")) | ||||
|                                             curr_tray->temp             = (*tray_it)["tray_temp"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->temp = ""; | ||||
|                                         if (tray_it->contains("tray_time")) | ||||
|                                             curr_tray->time             = (*tray_it)["tray_time"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->time = ""; | ||||
|                                         if (tray_it->contains("bed_temp_type")) | ||||
|                                             curr_tray->bed_temp_type    = (*tray_it)["bed_temp_type"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->bed_temp_type = ""; | ||||
|                                         if (tray_it->contains("bed_temp")) | ||||
|                                             curr_tray->bed_temp         = (*tray_it)["bed_temp"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->bed_temp = ""; | ||||
|                                         if (tray_it->contains("nozzle_temp_max")) | ||||
|                                             curr_tray->nozzle_temp_max = (*tray_it)["nozzle_temp_max"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->nozzle_temp_max = ""; | ||||
|                                         if (tray_it->contains("nozzle_temp_min")) | ||||
|                                             curr_tray->nozzle_temp_min = (*tray_it)["nozzle_temp_min"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->nozzle_temp_min = ""; | ||||
|                                         if (tray_it->contains("xcam_info")) | ||||
|                                             curr_tray->xcam_info = (*tray_it)["xcam_info"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->xcam_info = ""; | ||||
|                                         if (tray_it->contains("tray_uuid")) | ||||
|                                             curr_tray->uuid = (*tray_it)["tray_uuid"].get<std::string>(); | ||||
|                                         else | ||||
|                                             curr_tray->uuid = "0"; | ||||
|                                         if (tray_it->contains("tray_color")) { | ||||
|                                             auto color = (*tray_it)["tray_color"].get<std::string>(); | ||||
|                                             curr_tray->update_color_from_str(color); | ||||
|                                         } else { | ||||
|                                             curr_tray->color = ""; | ||||
|                                         } | ||||
|                                         try { | ||||
|                                             if (!ams_id.empty() && !curr_tray->id.empty()) { | ||||
|  | @ -2051,12 +2187,20 @@ int MachineObject::parse_json(std::string payload) | |||
|                     } | ||||
| #pragma endregion | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                 } else if (jj["command"].get<std::string>() == "gcode_line") { | ||||
|                     //ack of gcode_line
 | ||||
|                     BOOST_LOG_TRIVIAL(debug) << "parse_json, ack of gcode_line = " << j.dump(4); | ||||
|                 } else if (jj["command"].get<std::string>() == "project_file") { | ||||
|                     //ack of project file
 | ||||
|                     BOOST_LOG_TRIVIAL(debug) << "parse_json, ack of project_file = " << j.dump(4); | ||||
|                     std::string result; | ||||
|                     if (jj.contains("result")) { | ||||
|                         result = jj["result"].get<std::string>(); | ||||
|                         if (result == "FAIL") { | ||||
|                             wxString text = _L("Failed to start printing job"); | ||||
|                             GUI::wxGetApp().show_dialog(text); | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (jj["command"].get<std::string>() == "ams_filament_setting") { | ||||
|                     if (jj["ams_id"].is_number()) { | ||||
|                         int ams_id = jj["ams_id"].get<int>(); | ||||
|  | @ -2071,6 +2215,8 @@ int MachineObject::parse_json(std::string payload) | |||
|                                 tray_it->second->type = jj["tray_type"].get<std::string>(); | ||||
|                                 tray_it->second->color = jj["tray_color"].get<std::string>(); | ||||
|                                 tray_it->second->setting_id = jj["tray_info_idx"].get<std::string>(); | ||||
|                                 // delay update
 | ||||
|                                 tray_it->second->set_hold_count(); | ||||
|                             } else { | ||||
|                                 BOOST_LOG_TRIVIAL(warning) << "ams_filament_setting, can not find in trayList, tray_id=" << tray_id; | ||||
|                             } | ||||
|  | @ -2133,6 +2279,8 @@ int MachineObject::parse_json(std::string payload) | |||
|             } | ||||
|         } | ||||
|         catch (...)  {} | ||||
| 
 | ||||
|         parse_state_changed_event(); | ||||
|     } | ||||
|     catch (...) { | ||||
|         BOOST_LOG_TRIVIAL(trace) << "parse_json failed! dev_id=" << this->dev_id <<", payload = " << payload; | ||||
|  | @ -2339,6 +2487,10 @@ DeviceManager::~DeviceManager() | |||
|     userMachineList.clear(); | ||||
| } | ||||
| 
 | ||||
| void DeviceManager::set_agent(NetworkAgent* agent) | ||||
| { | ||||
|     m_agent = agent; | ||||
| } | ||||
| 
 | ||||
| void DeviceManager::on_machine_alive(std::string json_str) | ||||
| { | ||||
|  | @ -2376,7 +2528,12 @@ void DeviceManager::on_machine_alive(std::string json_str) | |||
|             obj->wifi_signal = printer_signal; | ||||
|             obj->dev_connection_type = connect_type; | ||||
|             obj->bind_state = bind_state; | ||||
|             BOOST_LOG_TRIVIAL(info) << "SsdpDiscovery:: Update Machine Info, printer_sn = " << dev_id << ", signal = " << printer_signal; | ||||
| 
 | ||||
|             // U0 firmware
 | ||||
|             if (obj->dev_connection_type.empty() && obj->bind_state.empty()) | ||||
|                 obj->bind_state = "free"; | ||||
| 
 | ||||
|             BOOST_LOG_TRIVIAL(debug) << "SsdpDiscovery:: Update Machine Info, printer_sn = " << dev_id << ", signal = " << printer_signal; | ||||
|             obj->last_alive = Slic3r::Utils::get_current_time_utc(); | ||||
|             obj->m_is_online = true; | ||||
|         } | ||||
|  | @ -2396,7 +2553,7 @@ void DeviceManager::on_machine_alive(std::string json_str) | |||
|             localMachineList.insert(std::make_pair(dev_id, obj)); | ||||
| 
 | ||||
| 
 | ||||
|             BOOST_LOG_TRIVIAL(info) << "SsdpDiscovery::New Machine, ip = " << dev_ip << ", printer_name= " << dev_name << ", printer_type = " << printer_type_str << ", signal = " << printer_signal; | ||||
|             BOOST_LOG_TRIVIAL(debug) << "SsdpDiscovery::New Machine, ip = " << dev_ip << ", printer_name= " << dev_name << ", printer_type = " << printer_type_str << ", signal = " << printer_signal; | ||||
|         } | ||||
|     } | ||||
|     catch (...) { | ||||
|  | @ -2480,6 +2637,11 @@ MachineObject* DeviceManager::get_local_machine(std::string dev_id) | |||
|     return it->second; | ||||
| } | ||||
| 
 | ||||
| void DeviceManager::erase_user_machine(std::string dev_id) | ||||
| { | ||||
|     userMachineList.erase(dev_id); | ||||
| } | ||||
| 
 | ||||
| MachineObject* DeviceManager::get_user_machine(std::string dev_id) | ||||
| { | ||||
|     if (!Slic3r::GUI::wxGetApp().is_user_login()) | ||||
|  | @ -2522,7 +2684,7 @@ void DeviceManager::clean_user_info() | |||
| 
 | ||||
| bool DeviceManager::set_selected_machine(std::string dev_id) | ||||
| { | ||||
|     BOOST_LOG_TRIVIAL(trace) << "set_selected_machine=" << dev_id; | ||||
|     BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id; | ||||
|     auto my_machine_list = get_my_machine_list(); | ||||
|     auto it = my_machine_list.find(dev_id); | ||||
|     if (it != my_machine_list.end()) { | ||||
|  | @ -2534,7 +2696,7 @@ bool DeviceManager::set_selected_machine(std::string dev_id) | |||
|             if (m_agent) { | ||||
|                 if (it->second->connection_type() != "lan" || it->second->connection_type().empty()) { | ||||
|                     if (m_agent->get_user_selected_machine() != dev_id) { | ||||
|                         BOOST_LOG_TRIVIAL(trace) << "set_selected_machine: same dev_id = " << dev_id; | ||||
|                         BOOST_LOG_TRIVIAL(info) << "static: set_selected_machine: same dev_id = " << dev_id; | ||||
|                         m_agent->set_user_selected_machine(dev_id); | ||||
|                         it->second->reset(); | ||||
|                     } else { | ||||
|  | @ -2680,7 +2842,7 @@ void DeviceManager::update_user_machine_list_info() | |||
| { | ||||
|     if (!m_agent) return; | ||||
| 
 | ||||
|     BOOST_LOG_TRIVIAL(trace) << "update_user_machine_list_info"; | ||||
|     BOOST_LOG_TRIVIAL(debug) << "update_user_machine_list_info"; | ||||
|     unsigned int http_code; | ||||
|     std::string body; | ||||
|     int result = m_agent->get_user_print_info(&http_code, &body); | ||||
|  |  | |||
|  | @ -13,9 +13,9 @@ | |||
| 
 | ||||
| #define USE_LOCAL_SOCKET_BIND 0 | ||||
| 
 | ||||
| #define DISCONNECT_TIMEOUT      10000.f     // milliseconds
 | ||||
| #define DISCONNECT_TIMEOUT      30000.f     // milliseconds
 | ||||
| #define PUSHINFO_TIMEOUT        15000.f     // milliseconds
 | ||||
| #define REQUEST_PUSH_MIN_TIME    3000.f     // milliseconds
 | ||||
| #define REQUEST_PUSH_MIN_TIME   15000.f     // milliseconds
 | ||||
| 
 | ||||
| #define FILAMENT_MAX_TEMP       300 | ||||
| #define FILAMENT_DEF_TEMP       220 | ||||
|  | @ -153,11 +153,13 @@ public: | |||
|     wxColour        wx_color; | ||||
|     bool            is_bbl; | ||||
|     bool            is_exists = false; | ||||
|     int             hold_count = 0; | ||||
| 
 | ||||
|     AmsRoadPosition road_position; | ||||
|     AmsStep         step_state; | ||||
|     AmsRfidState    rfid_state; | ||||
| 
 | ||||
|     void set_hold_count() { hold_count = 3; } | ||||
|     void update_color_from_str(std::string color); | ||||
|     wxColour get_color(); | ||||
| 
 | ||||
|  | @ -244,7 +246,13 @@ public: | |||
| #define UpgradeFlashFailed      -3 | ||||
| #define UpgradePrinting         -4 | ||||
| 
 | ||||
| 
 | ||||
| // calc distance map
 | ||||
| struct DisValue { | ||||
|     int  tray_id; | ||||
|     float distance; | ||||
|     bool  is_same_color = true; | ||||
|     bool  is_type_match = true; | ||||
| }; | ||||
| 
 | ||||
| class MachineObject | ||||
| { | ||||
|  | @ -347,6 +355,7 @@ public: | |||
|     // parse amsStatusMain and ams_status_sub
 | ||||
|     void _parse_ams_status(int ams_status); | ||||
|     bool has_ams() { return ams_exist_bits != 0; } | ||||
|     bool is_U0_firmware(); | ||||
|     bool is_support_ams_mapping(); | ||||
|     bool is_only_support_cloud_print(); | ||||
|     static bool is_support_ams_mapping_version(std::string module, std::string version); | ||||
|  | @ -415,16 +424,22 @@ public: | |||
|     int     mc_print_line_number; | ||||
|     int     mc_print_percent;       /* left print progess in percent */ | ||||
|     int     mc_left_time;           /* left time in seconds */ | ||||
|     int     last_mc_print_stage; | ||||
|     bool    is_system_printing(); | ||||
| 
 | ||||
|     std::vector<int> stage_list_info; | ||||
|     int stage_curr = 0; | ||||
|     int m_push_count = 0; | ||||
|     bool calibration_done { false }; | ||||
| 
 | ||||
|     wxString get_curr_stage(); | ||||
|     // return curr stage index of stage list
 | ||||
|     int get_curr_stage_idx(); | ||||
|     bool is_in_calibration(); | ||||
|     bool is_calibration_running(); | ||||
|     bool is_calibration_done(); | ||||
| 
 | ||||
|     void parse_state_changed_event(); | ||||
| 
 | ||||
|     /* printing status */ | ||||
|     std::string print_status;      /* enum string: FINISH, RUNNING, PAUSE, INIT, FAILED */ | ||||
|  | @ -455,11 +470,14 @@ public: | |||
|     BBLSliceInfo* slice_info {nullptr}; | ||||
|     int plate_index { -1 }; | ||||
|     std::string m_gcode_file; | ||||
|     int gcode_file_prepare_percent = 0; | ||||
|     BBLSubTask* subtask_; | ||||
|     std::string obj_subtask_id;     // subtask_id == 0 for sdcard
 | ||||
|     std::string subtask_name; | ||||
|     bool is_sdcard_printing(); | ||||
|     bool has_sdcard(); | ||||
|     bool has_timelapse(); | ||||
|     bool has_recording(); | ||||
| 
 | ||||
| 
 | ||||
|     MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip); | ||||
|  | @ -517,6 +535,7 @@ public: | |||
|     bool can_pause(); | ||||
|     bool can_abort(); | ||||
|     bool is_in_printing(); | ||||
|     bool is_in_prepare(); | ||||
|     bool is_printing_finished(); | ||||
|     void reset_update_time(); | ||||
|     void reset(); | ||||
|  | @ -525,6 +544,7 @@ public: | |||
|     void set_print_state(std::string status); | ||||
| 
 | ||||
|     bool is_connected(); | ||||
|     bool is_connecting(); | ||||
|     void set_online_state(bool on_off); | ||||
|     bool is_online() { return m_is_online; } | ||||
|     bool is_info_ready(); | ||||
|  | @ -554,6 +574,7 @@ private: | |||
| public: | ||||
|     DeviceManager(NetworkAgent* agent = nullptr); | ||||
|     ~DeviceManager(); | ||||
|     void set_agent(NetworkAgent* agent); | ||||
| 
 | ||||
|     std::mutex listMutex; | ||||
|     std::string selected_machine;                               /* dev_id */ | ||||
|  | @ -566,6 +587,7 @@ public: | |||
|     MachineObject* get_local_machine(std::string dev_id); | ||||
|     MachineObject* get_user_machine(std::string dev_id); | ||||
|     MachineObject* get_my_machine(std::string dev_id); | ||||
|     void erase_user_machine(std::string dev_id); | ||||
|     void clean_user_info(); | ||||
| 
 | ||||
|     bool set_selected_machine(std::string dev_id); | ||||
|  | @ -588,8 +610,6 @@ public: | |||
|     // get alive machine
 | ||||
|     std::map<std::string, MachineObject*> get_local_machine_list(); | ||||
|     void load_last_machine(); | ||||
| 
 | ||||
|     void check_alive(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
							
								
								
									
										100
									
								
								src/slic3r/GUI/DownloadProgressDialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/slic3r/GUI/DownloadProgressDialog.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| #include "DownloadProgressDialog.hpp" | ||||
| 
 | ||||
| #include <wx/settings.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/stattext.h> | ||||
| #include <wx/button.h> | ||||
| #include <wx/statbmp.h> | ||||
| #include <wx/scrolwin.h> | ||||
| #include <wx/clipbrd.h> | ||||
| #include <wx/checkbox.h> | ||||
| #include <wx/html/htmlwin.h> | ||||
| 
 | ||||
| #include <boost/algorithm/string/replace.hpp> | ||||
| 
 | ||||
| #include "libslic3r/libslic3r.h" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "GUI.hpp" | ||||
| #include "I18N.hpp" | ||||
| //#include "ConfigWizard.hpp"
 | ||||
| #include "wxExtensions.hpp" | ||||
| #include "slic3r/GUI/MainFrame.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| 
 | ||||
| #define DESIGN_INPUT_SIZE wxSize(FromDIP(100), -1) | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| DownloadProgressDialog::DownloadProgressDialog(wxString title) | ||||
|     : DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) | ||||
| { | ||||
|     std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); | ||||
|     SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); | ||||
| 
 | ||||
|     SetBackgroundColour(*wxWHITE); | ||||
|     wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL); | ||||
|     auto        m_line_top   = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); | ||||
|     m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); | ||||
|     m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); | ||||
|     m_status_bar    = std::make_shared<BBLStatusBarSend>(this); | ||||
|     m_panel_download = m_status_bar->get_panel(); | ||||
|     m_panel_download->SetSize(wxSize(FromDIP(340), -1)); | ||||
|     m_panel_download->SetMinSize(wxSize(FromDIP(340), -1)); | ||||
|     m_panel_download->SetMaxSize(wxSize(FromDIP(340), -1)); | ||||
|     m_sizer_main->Add(m_panel_download, 0, wxALIGN_CENTER_VERTICAL|wxALL, FromDIP(20)); | ||||
|     m_sizer_main->Add(0, 0, 1, wxBOTTOM, 10); | ||||
| 
 | ||||
|     SetSizer(m_sizer_main); | ||||
|     Layout(); | ||||
|     Fit(); | ||||
|     CentreOnParent(); | ||||
| } | ||||
| 
 | ||||
| bool DownloadProgressDialog::Show(bool show) | ||||
| { | ||||
|     if (show) { | ||||
|         m_upgrade_job = std::make_shared<UpgradeNetworkJob>(m_status_bar); | ||||
|         m_upgrade_job->set_event_handle(this); | ||||
|         m_status_bar->set_progress(0); | ||||
|         Bind(EVT_UPGRADE_NETWORK_SUCCESS, [this](wxCommandEvent& evt) { | ||||
|             m_status_bar->change_button_label(_L("Finish")); | ||||
|             wxGetApp().restart_networking(); | ||||
|             m_status_bar->set_cancel_callback_fina( | ||||
|                 [this]() { | ||||
|                     this->Close(); | ||||
|                 } | ||||
|             ); | ||||
|         }); | ||||
| 
 | ||||
|         Bind(EVT_UPGRADE_NETWORK_FAILED, [this](wxCommandEvent& evt) { | ||||
|             m_status_bar->change_button_label(_L("Close")); | ||||
|             m_status_bar->set_progress(0); | ||||
|             m_status_bar->set_cancel_callback_fina( | ||||
|                 [this]() { | ||||
|                     this->Close(); | ||||
|                 } | ||||
|             ); | ||||
|         }); | ||||
| 
 | ||||
|         m_status_bar->set_cancel_callback_fina([this]() { | ||||
|             if (m_upgrade_job) { | ||||
|                 m_upgrade_job->cancel(); | ||||
|                 //EndModal(wxID_CLOSE);
 | ||||
|             } | ||||
|                  | ||||
|         }); | ||||
|         m_upgrade_job->start(); | ||||
|     } | ||||
|     return DPIDialog::Show(show); | ||||
| } | ||||
| 
 | ||||
|  DownloadProgressDialog::~DownloadProgressDialog() {} | ||||
| 
 | ||||
| void DownloadProgressDialog::on_dpi_changed(const wxRect &suggested_rect) {} | ||||
| 
 | ||||
| void DownloadProgressDialog::update_release_note(std::string release_note, std::string version) {} | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
							
								
								
									
										55
									
								
								src/slic3r/GUI/DownloadProgressDialog.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/slic3r/GUI/DownloadProgressDialog.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | |||
| #ifndef slic3r_DownloadProgressDialog_hpp_ | ||||
| #define slic3r_DownloadProgressDialog_hpp_ | ||||
| 
 | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include "GUI_Utils.hpp" | ||||
| #include <wx/dialog.h> | ||||
| #include <wx/font.h> | ||||
| #include <wx/bitmap.h> | ||||
| #include <wx/msgdlg.h> | ||||
| #include <wx/richmsgdlg.h> | ||||
| #include <wx/textctrl.h> | ||||
| #include <wx/statline.h> | ||||
| #include "Widgets/Button.hpp" | ||||
| #include "BBLStatusBar.hpp" | ||||
| #include "BBLStatusBarSend.hpp" | ||||
| #include "Jobs/UpgradeNetworkJob.hpp" | ||||
| 
 | ||||
| class wxBoxSizer; | ||||
| class wxCheckBox; | ||||
| class wxStaticBitmap; | ||||
| 
 | ||||
| #define MSG_DIALOG_BUTTON_SIZE wxSize(FromDIP(58), FromDIP(24)) | ||||
| #define MSG_DIALOG_MIDDLE_BUTTON_SIZE wxSize(FromDIP(76), FromDIP(24)) | ||||
| #define MSG_DIALOG_LONG_BUTTON_SIZE wxSize(FromDIP(90), FromDIP(24)) | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| class DownloadProgressDialog : public DPIDialog | ||||
| { | ||||
| protected: | ||||
|     bool Show(bool show) override; | ||||
| 
 | ||||
| public: | ||||
|     DownloadProgressDialog(wxString title); | ||||
|     ~DownloadProgressDialog(); | ||||
| 
 | ||||
|     void on_dpi_changed(const wxRect &suggested_rect) override; | ||||
|     void update_release_note(std::string release_note, std::string version); | ||||
| 
 | ||||
| 	std::shared_ptr<BBLStatusBarSend> m_status_bar; | ||||
|     std::shared_ptr<UpgradeNetworkJob> m_upgrade_job; | ||||
|     wxPanel *                         m_panel_download; | ||||
| 
 | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -4988,7 +4988,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv | |||
|         ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / /*1000*/koef); | ||||
|         imgui.text(buf); | ||||
|         ImGui::SameLine(); | ||||
|         ::sprintf(buf, "  %.2f g", ps.total_weight); | ||||
|         double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1; | ||||
|         ::sprintf(buf, imperial_units ?"  %.2f oz":"  %.2f g", ps.total_weight / unit_conver); | ||||
|         imgui.text(buf); | ||||
| 
 | ||||
|         auto role_time = [time_mode](ExtrusionRole role) { | ||||
|  |  | |||
|  | @ -1349,7 +1349,12 @@ void GLCanvas3D::render(bool only_init) | |||
|             right_margin = SLIDER_RIGHT_MARGIN; | ||||
|             bottom_margin = SLIDER_BOTTOM_MARGIN; | ||||
|         } | ||||
|         wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin); | ||||
|         #if ENABLE_RETINA_GL | ||||
|             float sc = m_retina_helper->get_scale_factor(); | ||||
|             wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin * sc, right_margin); | ||||
|         #else | ||||
|             wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin); | ||||
|         #endif | ||||
|     } | ||||
| 
 | ||||
|     wxGetApp().imgui()->render(); | ||||
|  | @ -3038,6 +3043,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             // Grab keyboard focus for input in gizmo dialogs.
 | ||||
|             m_canvas->SetFocus(); | ||||
| 
 | ||||
|         if (evt.LeftDown()) { | ||||
|             // Clear hover state in main toolbar
 | ||||
|             wxMouseEvent evt2 = evt; | ||||
|             evt2.SetEventType(wxEVT_MOTION); | ||||
|             evt2.SetLeftDown(false); | ||||
|             m_main_toolbar.on_mouse(evt2, *this); | ||||
|         } | ||||
| 
 | ||||
|         if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) | ||||
|             mouse_up_cleanup(); | ||||
| 
 | ||||
|  | @ -6397,34 +6410,25 @@ void GLCanvas3D::_render_paint_toolbar() const | |||
|        } | ||||
|    } | ||||
| 
 | ||||
|    #ifdef __APPLE__ | ||||
|    std::string  item_text   = (boost::format("%1% %2%") % (11) % filament_types[0]).str(); | ||||
|    const ImVec2 label_size  = ImGui::CalcTextSize(item_text.c_str(), NULL, true); | ||||
|    int          button_size = label_size.x + item_spacing; | ||||
|    #else | ||||
|    int button_size  = GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale() + item_spacing; | ||||
|    #endif | ||||
|     float button_size  = GLToolbar::Default_Icons_Size * f_scale * wxGetApp().toolbar_icon_scale() + item_spacing; | ||||
| 
 | ||||
|     imgui.set_next_window_pos(0.5f * (canvas_w + (button_size + item_spacing) * extruder_num), button_size + item_spacing * 2, ImGuiCond_Always, 1.0f, 1.0f); | ||||
|     imgui.begin(_L("Paint Toolbar"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar); | ||||
|     bool disabled = !wxGetApp().plater()->can_fillcolor(); | ||||
|     unsigned char rgb[3]; | ||||
| 
 | ||||
|     float max_text = 0; | ||||
|     for (int i = 0; i < extruder_num; i++) { | ||||
|         if (i > 0) { | ||||
|             if (filament_types.size() <= i) continue; | ||||
|             std::string  item_text  = (boost::format("%1% %2%") % (i + 1) % filament_types[i]).str(); | ||||
|             const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); | ||||
|             #ifdef __WINDOWS__ | ||||
|             if (i > 8) | ||||
|                 ImGui::SameLine(0.5 * item_spacing + (button_size - label_size.x) / 2 + (button_size + item_spacing) * i); | ||||
|             else | ||||
|                 ImGui::SameLine((button_size - label_size.x) / 2 + (button_size + item_spacing) * i); | ||||
|             #else | ||||
|             ImGui::SameLine(); | ||||
|             #endif | ||||
|         } | ||||
|             //ImGui::SameLine();
 | ||||
|         std::string item_text = (boost::format("%1%%2%") % (i + 1) % filament_types[i]).str(); | ||||
|         ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); | ||||
|         if (label_size.x > button_size) | ||||
|                label_size.x  = button_size * 0.6; | ||||
|         max_text = std::max(max_text,label_size.x); | ||||
|     } | ||||
|     for (int i = 0; i < extruder_num; i++) { | ||||
|         if (filament_types.size() <= i) continue; | ||||
| 
 | ||||
|         ImGui::SameLine(item_spacing / 2 + (button_size - max_text) / 2 + (button_size + item_spacing) * i); | ||||
|         ImGui::PushID(i); | ||||
|         Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb); | ||||
|         ImGui::PushStyleColor(ImGuiCol_Button, ImColor(rgb[0], rgb[1], rgb[2]).Value); | ||||
|  | @ -6450,21 +6454,78 @@ void GLCanvas3D::_render_paint_toolbar() const | |||
|             ImGui::PopItemFlag(); | ||||
|         ImGui::PopID(); | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i < extruder_num; i++){ | ||||
|         if (filament_types.size() <= i) continue; | ||||
|         //TODO use filament type from filament management, current use PLA by default
 | ||||
|         std::string item_text = (boost::format("%1% %2%") % (i + 1) % filament_types[i]).str(); | ||||
|         std::string item_text = (boost::format("%1%%2%") % (i + 1) % filament_types[i]).str(); | ||||
|         const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); | ||||
| 
 | ||||
|         ImGui::SameLine(item_spacing + (button_size - label_size.x) / 2 + (button_size + item_spacing) * i); | ||||
|         int len = strlen(filament_types[i].c_str()); | ||||
| 
 | ||||
|         ImGui::SameLine(item_spacing / 2 + (button_size - max_text) / 2 + (button_size + item_spacing) * i); | ||||
| 
 | ||||
|         int count = 0; | ||||
|         if (label_size.x > button_size) | ||||
|         { | ||||
|             for (int j = 0; j < filament_types[i].size(); j++) | ||||
|             { | ||||
|                  if(std::isalpha(filament_types[i][j])) | ||||
|                     count++; | ||||
|                  else | ||||
|                      break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (i > 8) | ||||
|         { | ||||
|             if (label_size.x > button_size) | ||||
|             { | ||||
|                 if(count * ImGui::GetFontSize() > button_size){ | ||||
|                     if ((len - (count + 1)) <= 3) | ||||
|                         item_text = "\t" + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count) + "\n" + "\t" + filament_types[i].substr(count, len); | ||||
|                     else | ||||
|                         item_text = "\t" + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n"+ filament_types[i].substr(count + 1, len); | ||||
|                 } else { | ||||
|                     if (count <= 4) | ||||
|                         item_text = "\t" + std::to_string(i + 1) + "\n" + "   " + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len); | ||||
|                     else | ||||
|                         item_text = "\t" + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 item_text = (boost::format("\t%1%\n   %2%") % (i + 1) % filament_types[i]).str(); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (label_size.x > button_size) | ||||
|             { | ||||
|                 if(count * ImGui::GetFontSize() > button_size){ | ||||
|                     if ((len - (count + 1)) <= 3) | ||||
|                         item_text = "\t " + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count) + "\n" + "\t" + filament_types[i].substr(count, len); | ||||
|                     else | ||||
|                         item_text = "\t " + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n"+ filament_types[i].substr(count + 1, len); | ||||
|                 } else { | ||||
|                     if (count <= 4) | ||||
|                         item_text = "\t " + std::to_string(i + 1) + "\n" + "   " + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len); | ||||
|                     else | ||||
|                         item_text = "\t " + std::to_string(i + 1) + "\n" + filament_types[i].substr(0, count + 1) + "\n" + filament_types[i].substr(count + 1, len); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                item_text = (boost::format("\t  %1%\n\t%2%") % (i + 1) % filament_types[i]).str(); | ||||
|             } | ||||
|         } | ||||
|         Slic3r::GUI::BitmapCache::parse_color(colors[i], rgb); | ||||
|         float gray = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]; | ||||
|         if (gray < 80) | ||||
|             ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), item_text.c_str()); | ||||
|         else | ||||
|             ImGui::TextColored(ImVec4(0.0f, 0.0f, 0.0f, 1.0f), item_text.c_str()); | ||||
| 
 | ||||
|         if (gray < 80){ | ||||
|                 ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), item_text.c_str());    | ||||
|         } else{ | ||||
|                 ImGui::TextColored(ImVec4(0.0f, 0.0f, 0.0f, 1.0f), item_text.c_str()); | ||||
|         }  | ||||
|     } | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     imgui.end(); | ||||
|  | @ -7468,8 +7529,8 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) | |||
|     case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break; | ||||
|     case EWarning::SomethingNotShown:  text = _u8L("Only the object being edit is visible."); break; | ||||
|     case EWarning::ObjectClashed: | ||||
|         text = _u8L("An object is layed over the boundary of plate.\n" | ||||
|             "Please solve the problem by moving it totally inside or outside plate."); | ||||
|         text = _u8L("An object is laid over the boundary of plate or exceeds the height limit.\n" | ||||
|             "Please solve the problem by moving it totally on or off the plate, and confirming that the height is within the build volume."); | ||||
|         error = ErrorType::PLATER_ERROR; | ||||
|         break; | ||||
|     } | ||||
|  |  | |||
|  | @ -299,10 +299,12 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri | |||
|         ::memcpy((void*)pressed_data.data(), (const void*)sprite_data.data(), sprite_bytes); | ||||
|         for (int i = 0; i < sprite_n_pixels; ++i) { | ||||
|             int offset = i * 4; | ||||
|             if (pressed_data.data()[offset] == 0) { | ||||
|                 ::memset((void*)&pressed_data.data()[offset], 172, 3); | ||||
|                 pressed_data.data()[offset + 3] = (unsigned char)150; | ||||
|             } | ||||
|             if (pressed_data.data()[offset + 0] == 0 &&  | ||||
|                 pressed_data.data()[offset + 1] == 0 && | ||||
|                 pressed_data.data()[offset + 2] == 0) { | ||||
|                 ::memset((void*)&pressed_data.data()[offset], 238, 3); | ||||
|                 pressed_data.data()[offset + 3] = (unsigned char) 225; | ||||
|             }  | ||||
|         } | ||||
| 
 | ||||
|         ::memcpy((void*)disable_data.data(), (const void*)sprite_data.data(), sprite_bytes); | ||||
|  | @ -315,25 +317,36 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri | |||
|         ::memcpy((void*)hover_data.data(), (const void*)sprite_data.data(), sprite_bytes); | ||||
|         for (int i = 0; i < sprite_n_pixels; ++i) { | ||||
|             int offset = i * 4; | ||||
|             if (hover_data.data()[offset] == 0) { | ||||
|                 ::memset((void*)&hover_data.data()[offset], 172, 3); | ||||
|                 hover_data.data()[offset + 3] = (unsigned char)75; | ||||
|             if (hover_data.data()[offset + 0] == 0 && | ||||
|                 hover_data.data()[offset + 1] == 0 && | ||||
|                 hover_data.data()[offset + 2] == 0)  | ||||
|             { | ||||
|                 ::memset((void *) &hover_data.data()[offset], 238, 3); | ||||
|                 hover_data.data()[offset + 3] = (unsigned char) 75; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         ::memcpy((void*)sprite_white_only_data.data(), (const void*)sprite_data.data(), sprite_bytes); | ||||
|         for (int i = 0; i < sprite_n_pixels; ++i) { | ||||
|             int offset = i * 4; | ||||
|             if (sprite_white_only_data.data()[offset + 0] != 0 || | ||||
|                 sprite_white_only_data.data()[offset + 1] != 0 ||  | ||||
|                 sprite_white_only_data.data()[offset + 2] != 0){ | ||||
|                 sprite_white_only_data.data()[offset + 0] = (unsigned char) 43; | ||||
|                 sprite_white_only_data.data()[offset + 1] = (unsigned char) 52; | ||||
|                 sprite_white_only_data.data()[offset + 2] = (unsigned char) 54; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ::memcpy((void*)sprite_gray_only_data.data(), (const void*)sprite_data.data(), sprite_bytes); | ||||
|         for (int i = 0; i < sprite_n_pixels; ++i) { | ||||
|             int offset = i * 4; | ||||
|             if (sprite_gray_only_data.data()[offset + 0] == 0) { | ||||
|             if (sprite_gray_only_data.data()[offset + 0] != 0 || | ||||
|                 sprite_gray_only_data.data()[offset + 1] != 0 ||  | ||||
|                 sprite_gray_only_data.data()[offset + 2] != 0 ) { | ||||
|                 ::memset((void*)&sprite_gray_only_data.data()[offset], 200, 3); | ||||
|             } | ||||
|             else { | ||||
|                 sprite_gray_only_data.data()[offset + 0] = (unsigned char)(sprite_data.data()[offset + 0] * 0.3 + 178); | ||||
|                 sprite_gray_only_data.data()[offset + 1] = (unsigned char)(sprite_data.data()[offset + 1] * 0.3 + 178); | ||||
|                 sprite_gray_only_data.data()[offset + 2] = (unsigned char)(sprite_data.data()[offset + 2] * 0.3 + 178); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -394,9 +407,9 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri | |||
|         glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|     else | ||||
|         glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); | ||||
| 
 | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -538,4 +538,52 @@ void desktop_open_datadir_folder() | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| void desktop_open_any_folder( const std::string path ) | ||||
| { | ||||
|     // Execute command to open a file explorer, platform dependent.
 | ||||
|     // FIXME: The const_casts aren't needed in wxWidgets 3.1, remove them when we upgrade.
 | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     const wxString widepath = from_u8(path); | ||||
|     const wchar_t *argv[]   = {L"explorer", widepath.GetData(), nullptr}; | ||||
|     ::wxExecute(const_cast<wchar_t **>(argv), wxEXEC_ASYNC, nullptr); | ||||
| #elif __APPLE__ | ||||
|     const char *argv[] = {"open", path.data(), nullptr}; | ||||
|     ::wxExecute(const_cast<char **>(argv), wxEXEC_ASYNC, nullptr); | ||||
| #else | ||||
|     const char *argv[] = {"xdg-open", path.data(), nullptr}; | ||||
| 
 | ||||
|     // Check if we're running in an AppImage container, if so, we need to remove AppImage's env vars,
 | ||||
|     // because they may mess up the environment expected by the file manager.
 | ||||
|     // Mostly this is about LD_LIBRARY_PATH, but we remove a few more too for good measure.
 | ||||
|     if (wxGetEnv("APPIMAGE", nullptr)) { | ||||
|         // We're running from AppImage
 | ||||
|         wxEnvVariableHashMap env_vars; | ||||
|         wxGetEnvMap(&env_vars); | ||||
| 
 | ||||
|         env_vars.erase("APPIMAGE"); | ||||
|         env_vars.erase("APPDIR"); | ||||
|         env_vars.erase("LD_LIBRARY_PATH"); | ||||
|         env_vars.erase("LD_PRELOAD"); | ||||
|         env_vars.erase("UNION_PRELOAD"); | ||||
| 
 | ||||
|         wxExecuteEnv exec_env; | ||||
|         exec_env.env = std::move(env_vars); | ||||
| 
 | ||||
|         wxString owd; | ||||
|         if (wxGetEnv("OWD", &owd)) { | ||||
|             // This is the original work directory from which the AppImage image was run,
 | ||||
|             // set it as CWD for the child process:
 | ||||
|             exec_env.cwd = std::move(owd); | ||||
|         } | ||||
| 
 | ||||
|         ::wxExecute(const_cast<char **>(argv), wxEXEC_ASYNC, nullptr, &exec_env); | ||||
|     } else { | ||||
|         // Looks like we're NOT running from AppImage, we'll make no changes to the environment.
 | ||||
|         ::wxExecute(const_cast<char **>(argv), wxEXEC_ASYNC, nullptr, nullptr); | ||||
|     } | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } } | ||||
|  |  | |||
|  | @ -82,7 +82,8 @@ extern void about(); | |||
| extern void login(); | ||||
| // Ask the destop to open the datadir using the default file explorer.
 | ||||
| extern void desktop_open_datadir_folder(); | ||||
| 
 | ||||
| // Ask the destop to open one folder
 | ||||
| extern void desktop_open_any_folder(const std::string path); | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -11,6 +11,7 @@ | |||
| #include "slic3r/GUI/DeviceManager.hpp" | ||||
| #include "slic3r/Utils/NetworkAgent.hpp" | ||||
| #include "slic3r/GUI/WebViewDialog.hpp" | ||||
| #include "slic3r/GUI/Jobs/UpgradeNetworkJob.hpp" | ||||
| 
 | ||||
| #include <wx/app.h> | ||||
| #include <wx/colour.h> | ||||
|  | @ -22,7 +23,8 @@ | |||
| #include <mutex> | ||||
| #include <stack> | ||||
| 
 | ||||
| #define BBL_HAS_FIRST_PAGE 1 | ||||
| #define BBL_HAS_FIRST_PAGE          1 | ||||
| #define STUDIO_INACTIVE_TIMEOUT     15*60*1000 | ||||
| 
 | ||||
| class wxMenuItem; | ||||
| class wxMenuBar; | ||||
|  | @ -104,6 +106,7 @@ enum CameraMenuIDs { | |||
|     wxID_CAMERA_COUNT, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class Tab; | ||||
| class ConfigWizard; | ||||
| 
 | ||||
|  | @ -186,6 +189,7 @@ public: | |||
| class GUI_App : public wxApp | ||||
| { | ||||
| public: | ||||
|      | ||||
|     //BBS: remove GCodeViewer as seperate APP logic
 | ||||
|     enum class EAppMode : unsigned char | ||||
|     { | ||||
|  | @ -241,9 +245,13 @@ private: | |||
| 
 | ||||
|     //BBS
 | ||||
|     bool m_is_closing {false}; | ||||
|     Slic3r::DeviceManager* m_device_manager; | ||||
|     Slic3r::DeviceManager* m_device_manager { nullptr }; | ||||
|     NetworkAgent* m_agent { nullptr }; | ||||
|     std::vector<std::string> need_delete_presets;   // store setting ids of preset
 | ||||
|     bool m_networking_compatible { false }; | ||||
|     bool m_networking_need_update { false }; | ||||
|     bool m_networking_cancel_update { false }; | ||||
|     std::shared_ptr<UpgradeNetworkJob> m_upgrade_network_job; | ||||
| 
 | ||||
|     VersionInfo version_info; | ||||
| 
 | ||||
|  | @ -335,7 +343,7 @@ public: | |||
|     void            load_gcode(wxWindow* parent, wxString& input_file) const; | ||||
| 
 | ||||
|     void            ShowUserGuide(); | ||||
|     void            ShowDailyTip(); | ||||
|     void            ShowDownNetPluginDlg(); | ||||
|     void            ShowUserLogin(); | ||||
|     void            ShowOnlyFilament(); | ||||
|     //BBS
 | ||||
|  | @ -358,11 +366,18 @@ public: | |||
|     void            on_http_error(wxCommandEvent &evt); | ||||
|     void            on_user_login(wxCommandEvent &evt); | ||||
| 
 | ||||
|     // BBS
 | ||||
|     bool            is_studio_active(); | ||||
|     void            reset_to_active(); | ||||
|     bool            m_studio_active = true; | ||||
|     std::chrono::system_clock::time_point  last_active_point; | ||||
| 
 | ||||
|     void            check_update(bool show_tips); | ||||
|     void            check_new_version(bool show_tips = false); | ||||
|     void            request_new_version(); | ||||
|     void            enter_force_upgrade(); | ||||
|     void            no_new_version(); | ||||
|     void            show_dialog(wxString msg); | ||||
|     void            reload_settings(); | ||||
|     void            remove_user_presets(); | ||||
|     void            sync_preset(Preset* preset); | ||||
|  | @ -484,12 +499,23 @@ public: | |||
|     void            associate_files(std::wstring extend); | ||||
|     void            disassociate_files(std::wstring extend); | ||||
| #endif // __WXMSW__
 | ||||
|     std::string     get_plugin_url(std::string country_code); | ||||
|     int             download_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr); | ||||
|     int             install_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr); | ||||
|     std::string     get_http_url(std::string country_code); | ||||
|     bool            is_compatibility_version(); | ||||
|     bool            check_networking_version(); | ||||
|     void            cancel_networking_install(); | ||||
|     void            restart_networking(); | ||||
| 
 | ||||
| private: | ||||
|     int             updating_bambu_networking(); | ||||
|     bool            on_init_inner(); | ||||
|     bool            on_init_network(); | ||||
|     void            init_networking_callbacks(); | ||||
|     void            init_app_config(); | ||||
|     //BBS set extra header for http request
 | ||||
|     std::map<std::string, std::string> get_extra_header(); | ||||
|     void            init_http_extra_header(); | ||||
|     bool            check_older_app_config(Semver current_version, bool backup); | ||||
|     void            copy_older_config(); | ||||
|  |  | |||
|  | @ -464,7 +464,8 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty | |||
|         auto item = L("Timelapse Wipe Tower"); | ||||
|         type      = ModelVolumeType::TIMELAPSE_WIPE_TOWER; | ||||
|         append_menu_item(sub_menu, wxID_ANY, _(item), "", | ||||
|             [type, item](wxCommandEvent&) { obj_list()->load_generic_subobject(item, type); }, "", menu); | ||||
|             [type, item](wxCommandEvent &) { obj_list()->load_generic_subobject(item, type); }, "", menu, | ||||
|             []() { return plater()->can_add_timelapse_wt(); }, m_parent); | ||||
|     } | ||||
| 
 | ||||
|     return sub_menu; | ||||
|  |  | |||
|  | @ -264,6 +264,8 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|         // which seems to be working as of now.
 | ||||
|         this->CallAfter([this](){ ensure_current_item_visible(); }); | ||||
| #else | ||||
|         update_name_column_width(); | ||||
| 
 | ||||
|         ensure_current_item_visible(); | ||||
| #endif | ||||
|         e.Skip(); | ||||
|  | @ -768,17 +770,21 @@ void ObjectList::update_filament_colors() | |||
| 
 | ||||
| void ObjectList::update_name_column_width() const | ||||
| { | ||||
|     auto em = em_unit(const_cast<ObjectList*>(this)); | ||||
|     int extra_width = 0; | ||||
|     wxSize client_size = this->GetClientSize(); | ||||
|     bool p_vbar = this->GetParent()->HasScrollbar(wxVERTICAL); | ||||
|     bool p_hbar = this->GetParent()->HasScrollbar(wxHORIZONTAL); | ||||
| 
 | ||||
|     auto em = em_unit(const_cast<ObjectList*>(this)); | ||||
|     // BBS: walkaround for wxDataViewCtrl::HasScrollbar() does not return correct status
 | ||||
|     int others_width = 0; | ||||
|     for (int cn = colName; cn < colCount; cn++) { | ||||
|         if (cn != colName) { | ||||
|             if (GetColumn(cn)->IsHidden()) | ||||
|                 extra_width += m_columns_width[cn]; | ||||
|             if (!GetColumn(cn)->IsHidden()) | ||||
|                 others_width += m_columns_width[cn]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     GetColumn(colName)->SetWidth((m_columns_width[colName] + extra_width) * em); | ||||
|     GetColumn(colName)->SetWidth(client_size.x - (others_width)*em); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::set_filament_column_hidden(const bool hide) const | ||||
|  | @ -1145,6 +1151,8 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me | |||
|                 GLGizmosManager& gizmos_mgr = wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager(); | ||||
|                 if (gizmos_mgr.get_current_type() != GLGizmosManager::EType::FdmSupports) | ||||
|                     gizmos_mgr.open_gizmo(GLGizmosManager::EType::FdmSupports); | ||||
|                 else | ||||
|                     gizmos_mgr.reset_all_states(); | ||||
|             } | ||||
|         } | ||||
|         else if (col_num == colColorPaint) { | ||||
|  | @ -1153,6 +1161,8 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me | |||
|                 GLGizmosManager& gizmos_mgr = wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager(); | ||||
|                 if (gizmos_mgr.get_current_type() != GLGizmosManager::EType::MmuSegmentation) | ||||
|                     gizmos_mgr.open_gizmo(GLGizmosManager::EType::MmuSegmentation); | ||||
|                 else | ||||
|                     gizmos_mgr.reset_all_states(); | ||||
|             } | ||||
|         } | ||||
|         else if (col_num == colEditing) { | ||||
|  | @ -2028,13 +2038,16 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name | |||
|     new_object->translate(-bb.center()); | ||||
| 
 | ||||
|     if (is_timelapse_wt) { | ||||
|         new_object->instances[0]->set_offset( Vec3d(80.0, 230.0, -new_object->origin_translation.z()) ); | ||||
|         new_object->is_timelapse_wipe_tower = true; | ||||
|         auto   curr_plate    = wxGetApp().plater()->get_partplate_list().get_curr_plate(); | ||||
|         int    highest_extruder = 0; | ||||
|         double max_height = curr_plate->estimate_timelapse_wipe_tower_height(&highest_extruder); | ||||
|         new_object->scale(1, 1, max_height / new_object->bounding_box().size()[2]); | ||||
| 
 | ||||
|         // move to garbage bin of curr plate
 | ||||
|         auto offset = curr_plate->get_origin() + Vec3d(80.0, 230.0, -new_object->origin_translation.z()); | ||||
|         new_object->instances[0]->set_offset(offset); | ||||
| 
 | ||||
|         new_object->config.set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); | ||||
|         new_object->config.set_key_value("top_shell_layers", new ConfigOptionInt(0)); | ||||
|         new_object->config.set("extruder", highest_extruder); | ||||
|  | @ -2237,14 +2250,15 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con | |||
| 
 | ||||
|                 // update extruder color in ObjectList
 | ||||
|                 wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx); | ||||
|                 // BBS
 | ||||
| #if 0 | ||||
|                 if (obj_item) { | ||||
|                     // BBS
 | ||||
|                     if (last_volume->config.has("extruder")) { | ||||
|                         int extruder_id = last_volume->config.opt_int("extruder"); | ||||
|                         object->config.set("extruder", extruder_id); | ||||
|                     } | ||||
|                     wxString extruder = object->config.has("extruder") ? wxString::Format("%d", object->config.extruder()) : _devL("1"); | ||||
|                     m_objects_model->SetExtruder(extruder, obj_item); | ||||
|                 } | ||||
| #endif | ||||
|                 // add settings to the object, if it has them
 | ||||
|                 add_settings_item(obj_item, &object->config.get()); | ||||
|             } | ||||
|  |  | |||
|  | @ -246,7 +246,7 @@ void GLGizmoBase::GizmoImguiEnd() | |||
|     m_imgui->end(); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoBase::GizmoImguiSetNextWIndowPos(float x, float y, int flag, float pivot_x, float pivot_y) | ||||
| void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x, float pivot_y) | ||||
| { | ||||
|     if (abs(last_input_window_width) > 0.01f) { | ||||
|         if (x + last_input_window_width > m_parent.get_canvas_size().get_width()) { | ||||
|  |  | |||
|  | @ -206,7 +206,7 @@ protected: | |||
| 
 | ||||
|     bool GizmoImguiBegin(const std::string& name, int flags); | ||||
|     void GizmoImguiEnd(); | ||||
|     void GizmoImguiSetNextWIndowPos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); | ||||
|     void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); | ||||
|     // Returns the picking color for the given id, based on the BASE_ID constant
 | ||||
|     // No check is made for clashing with other picking color (i.e. GLVolumes)
 | ||||
|     std::array<float, 4> picking_color_component(unsigned int id) const; | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ bool GLGizmoFdmSupports::on_init() | |||
|     m_desc["remove"]                = _L("Erase painting"); | ||||
|     m_desc["remove_all"]            = _L("Erase all painting"); | ||||
|     m_desc["highlight_by_angle"]    = _L("Highlight overhang areas") + ": "; | ||||
|     m_desc["fragment_filter"]       = _L("Fragment filter"); | ||||
|     m_desc["fragment_filter"]       = _L("Gap fill"); | ||||
|     m_desc["perform_filter"]        = _L("Perform"); | ||||
|     m_desc["fragment_area"]         = _L("Fragment area"); | ||||
|     m_desc["brush_size"]            = _L("Set pen size"); | ||||
|  | @ -246,7 +246,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l | |||
|     ImGui::AlignTextToFramePadding(); | ||||
|     m_imgui->text(m_desc.at("tool_type")); | ||||
|     std::array<wchar_t, 4> tool_icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::FillButtonIcon, ImGui::FragmentFilterIcon }; | ||||
|     std::array<wxString, 4> tool_tips = { _L("Circle"), _L("Sphere"), _L("Fill"), _L("Fragment Filter") }; | ||||
|     std::array<wxString, 4> tool_tips = { _L("Circle"), _L("Sphere"), _L("Fill"), _L("Gap Fill") }; | ||||
|     for (int i = 0; i < tool_icons.size(); i++) { | ||||
|         std::string  str_label = std::string("##"); | ||||
|         std::wstring btn_name = tool_icons[i] + boost::nowide::widen(str_label); | ||||
|  |  | |||
|  | @ -337,12 +337,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|     GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); | ||||
| 
 | ||||
|     // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
 | ||||
|     const float clipping_slider_left  = m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f); | ||||
|     const float clipping_slider_left  = m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.f); | ||||
|     const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); | ||||
|     const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); | ||||
|     const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); | ||||
|     const float fragment_area_slider_left = m_imgui->calc_text_size(m_desc.at("fragment_area")).x + m_imgui->scaled(1.f); | ||||
|     const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(1.f); | ||||
|     const float fragment_area_slider_left = m_imgui->calc_text_size(m_desc.at("fragment_area")).x + m_imgui->scaled(1.5f); | ||||
|     const float height_range_slider_left = m_imgui->calc_text_size(m_desc.at("height_range")).x + m_imgui->scaled(1.5f); | ||||
| 
 | ||||
|     const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); | ||||
|     const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform_filter")).x + m_imgui->scaled(1.f); | ||||
|  | @ -359,6 +359,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|     total_text_max += caption_max + m_imgui->scaled(1.f); | ||||
|     caption_max += m_imgui->scaled(1.f); | ||||
| 
 | ||||
|     const float circle_max_width = std::max(clipping_slider_left,cursor_slider_left); | ||||
|     const float height_max_width = std::max(clipping_slider_left,height_range_slider_left); | ||||
|     const float sliders_left_width = std::max(smart_fill_slider_left, | ||||
|                                          std::max(cursor_slider_left, std::max(edge_detect_slider_left, std::max(fragment_area_slider_left, std::max(height_range_slider_left, | ||||
|                                                                                                                                               clipping_slider_left))))); | ||||
|  | @ -404,7 +406,15 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|         // draw filament background
 | ||||
|         ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; | ||||
|         if (m_selected_extruder_idx != extruder_idx) flags |= ImGuiColorEditFlags_NoBorder; | ||||
|         bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); | ||||
|         #ifdef __APPLE__ | ||||
|             ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); | ||||
|             ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); | ||||
|             bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); | ||||
|             ImGui::PopStyleVar(1); | ||||
|             ImGui::PopStyleColor(1); | ||||
|         #else | ||||
|             bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size); | ||||
|         #endif | ||||
|         color_button_high = ImGui::GetCursorPos().y - color_button - 2.0; | ||||
|         if (color_picked) { m_selected_extruder_idx = extruder_idx; } | ||||
| 
 | ||||
|  | @ -425,7 +435,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|     m_imgui->text(m_desc.at("tool_type")); | ||||
| 
 | ||||
|     std::array<wchar_t, 6> tool_icons = { ImGui::CircleButtonIcon,ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::FragmentFilterIcon }; | ||||
|     std::array<wxString, 6> tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Fragment Filter") }; | ||||
|     std::array<wxString, 6> tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill") }; | ||||
|     for (int i = 0; i < tool_icons.size(); i++) { | ||||
|         std::string  str_label = std::string("##"); | ||||
|         std::wstring btn_name  = tool_icons[i] + boost::nowide::widen(str_label); | ||||
|  | @ -460,33 +470,54 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|     if (m_current_tool != old_tool) | ||||
|         this->tool_changed(old_tool, m_current_tool); | ||||
| 
 | ||||
|     if (m_current_tool == ImGui::CircleButtonIcon) { | ||||
|         m_cursor_type = TriangleSelector::CursorType::CIRCLE; | ||||
|     if (m_current_tool == ImGui::CircleButtonIcon || m_current_tool == ImGui::SphereButtonIcon) { | ||||
|         if (m_current_tool == ImGui::CircleButtonIcon) | ||||
|             m_cursor_type = TriangleSelector::CursorType::CIRCLE; | ||||
|         else | ||||
|              m_cursor_type = TriangleSelector::CursorType::SPHERE; | ||||
|         m_tool_type = ToolType::BRUSH; | ||||
| 
 | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc.at("cursor_size")); | ||||
|         ImGui::SameLine(sliders_left_width); | ||||
|         ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width); | ||||
|         ImGui::SameLine(circle_max_width); | ||||
|         ImGui::PushItemWidth(window_width - circle_max_width - slider_width_times * slider_icon_width); | ||||
|         m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
|     } else if (m_current_tool == ImGui::SphereButtonIcon){ | ||||
|         m_cursor_type = TriangleSelector::CursorType::SPHERE; | ||||
|         m_tool_type = ToolType::BRUSH; | ||||
| 
 | ||||
|         ImGui::Separator(); | ||||
| 
 | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc.at("cursor_size")); | ||||
|         ImGui::SameLine(sliders_left_width); | ||||
|         ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width); | ||||
|         m_imgui->bbl_slider_float_style("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f", 1.0f, true); | ||||
|         m_imgui->text(m_desc.at("clipping_of_view")); | ||||
| 
 | ||||
|         auto clp_dist = float(m_c->object_clipper()->get_position()); | ||||
|         ImGui::SameLine(circle_max_width); | ||||
|         ImGui::PushItemWidth(window_width - circle_max_width - slider_width_times * slider_icon_width); | ||||
|         bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
|         bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|         if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } | ||||
| 
 | ||||
|     } else if (m_current_tool == ImGui::TriangleButtonIcon) { | ||||
|         m_cursor_type = TriangleSelector::CursorType::POINTER; | ||||
|         m_tool_type   = ToolType::BRUSH; | ||||
| 
 | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc.at("clipping_of_view")); | ||||
| 
 | ||||
|         auto clp_dist = float(m_c->object_clipper()->get_position()); | ||||
|         ImGui::SameLine(clipping_slider_left); | ||||
|         ImGui::PushItemWidth(window_width - clipping_slider_left - slider_width_times * slider_icon_width); | ||||
|         bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|         if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } | ||||
| 
 | ||||
|     } else if (m_current_tool == ImGui::FillButtonIcon) { | ||||
|         m_cursor_type = TriangleSelector::CursorType::POINTER; | ||||
|         m_imgui->bbl_checkbox(m_desc["edge_detection"], m_detect_geometry_edge); | ||||
|  | @ -511,34 +542,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|             // set to negative value to disable edge detection
 | ||||
|             m_smart_fill_angle = -1.f; | ||||
|         } | ||||
|     } else if (m_current_tool == ImGui::HeightRangeIcon) { | ||||
|         m_tool_type   = ToolType::BRUSH; | ||||
|         m_cursor_type = TriangleSelector::CursorType::HEIGHT_RANGE; | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc["height_range"] + ":"); | ||||
|         ImGui::SameLine(sliders_left_width); | ||||
|         ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width); | ||||
|         std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Heigh range," "Facet in [cursor z, cursor z + height] will be selected."); | ||||
|         m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
|     } | ||||
|     else if (m_current_tool == ImGui::FragmentFilterIcon) { | ||||
|         m_tool_type = ToolType::FRAGMENT_FILTER; | ||||
|         m_cursor_type = TriangleSelector::CursorType::POINTER; | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc["fragment_area"] + ":"); | ||||
|         ImGui::SameLine(sliders_left_width); | ||||
|         ImGui::PushItemWidth(window_width - sliders_left_width - slider_width_times * slider_icon_width); | ||||
|         std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold"); | ||||
|         m_imgui->bbl_slider_float_style("##fragment_area", &TriangleSelectorPatch::fragment_area, TriangleSelectorPatch::FragmentAreaMin, TriangleSelectorPatch::FragmentAreaMax, format_str.data(), 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         ImGui::BBLDragFloat("##fragment_area_input", &TriangleSelectorPatch::fragment_area, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
|     } | ||||
| 
 | ||||
|     if (m_current_tool != ImGui::FragmentFilterIcon) { | ||||
|         ImGui::Separator(); | ||||
| 
 | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|  | @ -552,8 +555,49 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott | |||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|         if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true);} | ||||
| 
 | ||||
|     } else if (m_current_tool == ImGui::HeightRangeIcon) { | ||||
|         m_tool_type   = ToolType::BRUSH; | ||||
|         m_cursor_type = TriangleSelector::CursorType::HEIGHT_RANGE; | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc["height_range"] + ":"); | ||||
|         ImGui::SameLine(height_max_width); | ||||
|         ImGui::PushItemWidth(window_width - height_max_width - slider_width_times * slider_icon_width); | ||||
|         std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Heigh range," "Facet in [cursor z, cursor z + height] will be selected."); | ||||
|         m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|         ImGui::Separator(); | ||||
| 
 | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc.at("clipping_of_view")); | ||||
| 
 | ||||
|         auto clp_dist = float(m_c->object_clipper()->get_position()); | ||||
|         ImGui::SameLine(height_max_width); | ||||
|         ImGui::PushItemWidth(window_width - height_max_width - slider_width_times * slider_icon_width); | ||||
|         bool slider_clp_dist = m_imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|         if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); } | ||||
|     } | ||||
|     else if (m_current_tool == ImGui::FragmentFilterIcon) { | ||||
|         m_tool_type = ToolType::FRAGMENT_FILTER; | ||||
|         m_cursor_type = TriangleSelector::CursorType::POINTER; | ||||
|         ImGui::AlignTextToFramePadding(); | ||||
|         m_imgui->text(m_desc["fragment_area"] + ":"); | ||||
|         ImGui::SameLine(fragment_area_slider_left); | ||||
|         ImGui::PushItemWidth(window_width - fragment_area_slider_left - slider_width_times * slider_icon_width); | ||||
|         std::string format_str = std::string("%.2f") + I18N::translate_utf8("", "Triangle patch area threshold,""triangle patch will be merged to neighbor if its area is less than threshold"); | ||||
|         m_imgui->bbl_slider_float_style("##fragment_area", &TriangleSelectorPatch::fragment_area, TriangleSelectorPatch::FragmentAreaMin, TriangleSelectorPatch::FragmentAreaMax, format_str.data(), 1.0f, true); | ||||
|         ImGui::SameLine(window_width - slider_icon_width); | ||||
|         ImGui::PushItemWidth(1.5 * slider_icon_width); | ||||
|         ImGui::BBLDragFloat("##fragment_area_input", &TriangleSelectorPatch::fragment_area, 0.05f, 0.0f, 0.0f, "%.2f"); | ||||
|     } | ||||
| 
 | ||||
|     ImGui::Separator(); | ||||
|     ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); | ||||
|  |  | |||
|  | @ -85,7 +85,7 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const | |||
|     //if ((border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= border + icons_size))) {
 | ||||
|     if (((top_y + border) <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= (top_y + border + icons_size))) { | ||||
|         // which icon is it on?
 | ||||
|         size_t from_left = (size_t)((float)mouse_pos(0) - top_x) / stride_x; | ||||
|         int from_left = (float) mouse_pos(0) - top_x < 0 ? -1 : (int) ((float) mouse_pos(0) - top_x) / stride_x; | ||||
|         if (from_left < 0) | ||||
|             return Undefined; | ||||
|         // is it really on the icon or already past the border?
 | ||||
|  |  | |||
|  | @ -18,6 +18,9 @@ | |||
| 
 | ||||
| #include <boost/algorithm/string.hpp> | ||||
| 
 | ||||
| #define MAX_NUM 9999.99 | ||||
| #define MAX_SIZE "9999.99" | ||||
| 
 | ||||
| namespace Slic3r | ||||
| { | ||||
| namespace GUI | ||||
|  | @ -25,6 +28,8 @@ namespace GUI | |||
| 
 | ||||
| const double GizmoObjectManipulation::in_to_mm = 25.4; | ||||
| const double GizmoObjectManipulation::mm_to_in = 0.0393700787; | ||||
| const double GizmoObjectManipulation::oz_to_g = 28.34952; | ||||
| const double GizmoObjectManipulation::g_to_oz = 0.035274; | ||||
| 
 | ||||
| // Helper function to be used by drop to bed button. Returns lowest point of this
 | ||||
| // volume in world coordinate system.
 | ||||
|  | @ -576,9 +581,10 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper, | |||
|     else | ||||
|         original_position = this->m_new_position; | ||||
|     Vec3d display_position = m_buffered_position; | ||||
| 
 | ||||
|     // Rotation
 | ||||
|     Vec3d rotation   = this->m_buffered_rotation; | ||||
|     float unit_size  = max_unit_size(2, display_position, display_position, "move") + space_size;; | ||||
|     float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size; | ||||
|     int   index      = 1; | ||||
|     int   index_unit = 1; | ||||
| 
 | ||||
|  | @ -611,6 +617,12 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper, | |||
|     ImGui::BBLInputDouble(label_values[0][2], &display_position[2], 0.0f, 0.0f, "%.2f"); | ||||
|     ImGui::SameLine(caption_max + (++index_unit) * unit_size + (++index) * space_size); | ||||
|     imgui_wrapper->text(this->m_new_unit_string); | ||||
| 
 | ||||
|     for (int i = 0;i<display_position.size();i++) | ||||
|     { | ||||
|         if (display_position[i] > MAX_NUM)display_position[i] = MAX_NUM; | ||||
|     } | ||||
| 
 | ||||
|     m_buffered_position = display_position; | ||||
|     update(current_active_id, "position", original_position, m_buffered_position); | ||||
|     // the init position values are not zero, won't add reset button
 | ||||
|  | @ -671,7 +683,7 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe | |||
|     }; | ||||
| 
 | ||||
|     float space_size    = imgui_wrapper->get_style_scaling() * 8; | ||||
|     float position_size = imgui_wrapper->calc_text_size(_L("Position")).x + space_size; | ||||
|     float position_size = imgui_wrapper->calc_text_size(_L("Rotation")).x + space_size; | ||||
|     float World_size    = imgui_wrapper->calc_text_size(_L("World coordinates")).x + space_size; | ||||
|     float caption_max   = std::max(position_size, World_size) + 2 * space_size; | ||||
|     float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x; | ||||
|  | @ -685,7 +697,8 @@ void GizmoObjectManipulation::do_render_rotate_window(ImGuiWrapper *imgui_wrappe | |||
|     Vec3d display_position = m_buffered_position; | ||||
|     // Rotation
 | ||||
|     Vec3d rotation   = this->m_buffered_rotation; | ||||
|     float unit_size  = max_unit_size(2, rotation, rotation, "rotate") + space_size * 2; | ||||
| 
 | ||||
|     float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size; | ||||
|     int   index      = 1; | ||||
|     int   index_unit = 1; | ||||
| 
 | ||||
|  | @ -792,7 +805,9 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w | |||
|     }; | ||||
| 
 | ||||
|     float space_size = imgui_wrapper->get_style_scaling() * 8; | ||||
|     float caption_max = imgui_wrapper->calc_text_size(_L("Position:")).x + space_size; | ||||
|     float scale_size = imgui_wrapper->calc_text_size(_L("Scale")).x + space_size; | ||||
|     float size_len = imgui_wrapper->calc_text_size(_L("Size")).x + space_size; | ||||
|     float caption_max = std::max(scale_size, size_len) + 2 * space_size; | ||||
|     float end_text_size = imgui_wrapper->calc_text_size(this->m_new_unit_string).x; | ||||
|     ImGui::AlignTextToFramePadding(); | ||||
|     unsigned int current_active_id = ImGui::GetActiveID(); | ||||
|  | @ -802,12 +817,12 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w | |||
| 
 | ||||
|     Vec3d display_position = m_buffered_position; | ||||
| 
 | ||||
|     float unit_size = max_unit_size(2, scale, display_size, "scale") + space_size; | ||||
|     float unit_size = imgui_wrapper->calc_text_size(MAX_SIZE).x + space_size; | ||||
|     bool imperial_units = this->m_imperial_units; | ||||
| 
 | ||||
|     int index      = 2; | ||||
|     int index_unit = 1; | ||||
|      | ||||
| 
 | ||||
|     ImGui::PushItemWidth(caption_max); | ||||
|     ImGui::Dummy(ImVec2(caption_max, -1)); | ||||
|     //imgui_wrapper->text(_L(" "));
 | ||||
|  | @ -839,8 +854,6 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w | |||
|     ImGui::BBLInputDouble(label_scale_values[0][2], &scale[2], 0.0f, 0.0f, "%.2f"); | ||||
|     ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size); | ||||
|     imgui_wrapper->text(_L("%")); | ||||
|     m_buffered_scale = scale; | ||||
| 
 | ||||
| 
 | ||||
|     if (m_show_clear_scale) { | ||||
|         ImGui::SameLine(caption_max + 3 * unit_size + 4 * space_size + end_text_size); | ||||
|  | @ -851,7 +864,6 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w | |||
|         ImGui::InvisibleButton("", ImVec2(ImGui::GetFontSize(), ImGui::GetFontSize())); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     //Size
 | ||||
|     Vec3d original_size; | ||||
|     if (this->m_imperial_units) | ||||
|  | @ -875,6 +887,12 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w | |||
|     ImGui::BBLInputDouble(label_scale_values[1][2], &display_size[2], 0.0f, 0.0f, "%.2f"); | ||||
|     ImGui::SameLine(caption_max + (++index_unit) *unit_size + (++index) * space_size); | ||||
|     imgui_wrapper->text(this->m_new_unit_string); | ||||
| 
 | ||||
|     for (int i = 0;i<display_size.size();i++) | ||||
|     { | ||||
|         if (display_size[i] > MAX_NUM || scale[i]> MAX_NUM)display_size[i] = MAX_NUM; | ||||
|     } | ||||
|     m_buffered_scale = scale; | ||||
|     m_buffered_size = display_size; | ||||
|     int size_sel = update(current_active_id, "size", original_size, m_buffered_size); | ||||
|     ImGui::PopStyleVar(1); | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ class GizmoObjectManipulation | |||
| public: | ||||
|     static const double in_to_mm; | ||||
|     static const double mm_to_in; | ||||
|     static const double g_to_oz; | ||||
|     static const double oz_to_g; | ||||
| 
 | ||||
|     struct Cache | ||||
|     { | ||||
|  |  | |||
|  | @ -451,6 +451,8 @@ bool IMSlider::init_texture() | |||
|         result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off.svg", 28, 28, m_one_layer_off_id); | ||||
|         result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off_hover.svg", 28, 28, m_one_layer_off_hover_id); | ||||
|         result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_arrow.svg", 28, 28, m_one_layer_arrow_id); | ||||
|         result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/im_gcode_pause.svg", 14, 14, m_pause_icon_id); | ||||
|         result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/im_slider_delete.svg", 14, 14, m_delete_icon_id); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
|  | @ -859,11 +861,13 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { | |||
|     if (m_ticks.empty()) | ||||
|         return; | ||||
| 
 | ||||
|     ImGuiContext &context       = *GImGui; | ||||
| 
 | ||||
|     ImVec2 tick_box      = ImVec2(46.0f, 16.0f) * m_scale; | ||||
|     ImVec2 tick_offset   = ImVec2(19.0f, 11.0f) * m_scale; | ||||
|     float  tick_width    = 1.0f * m_scale; | ||||
|     ImVec2 icon_offset   = ImVec2(13.0f, 7.0f) * m_scale; | ||||
|     ImVec2 icon_size     = ImVec2(16.0f, 16.0f) * m_scale; | ||||
|     ImVec2 icon_size     = ImVec2(14.0f, 14.0f) * m_scale; | ||||
| 
 | ||||
|     const ImU32 tick_clr = IM_COL32(144, 144, 144, 255); | ||||
|     const ImU32 tick_hover_box_clr = IM_COL32(219, 253, 231, 255); | ||||
|  | @ -876,12 +880,10 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { | |||
|         return get_pos_from_value(v_min, v_max, tick, slideable_region); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     float tick_pos; | ||||
|     std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin(); | ||||
|     while (tick_it != m_ticks.ticks.end()) | ||||
|     { | ||||
|         tick_pos = get_tick_pos(tick_it->tick); | ||||
|         float tick_pos = get_tick_pos(tick_it->tick); | ||||
| 
 | ||||
|         //draw tick hover box when hovered
 | ||||
|         ImRect tick_hover_box = ImRect(slideable_region.GetCenter().x - tick_box.x / 2, tick_pos - tick_box.y / 2, slideable_region.GetCenter().x + tick_box.x / 2, | ||||
|  | @ -890,8 +892,10 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { | |||
|         if (ImGui::IsMouseHoveringRect(tick_hover_box.Min, tick_hover_box.Max)) | ||||
|         { | ||||
|             ImGui::RenderFrame(tick_hover_box.Min, tick_hover_box.Max, tick_hover_box_clr, false); | ||||
|             m_tick_value = tick_it->tick; | ||||
|             m_tick_rect = ImVec4(tick_hover_box.Min.x, tick_hover_box.Min.y, tick_hover_box.Max.x, tick_hover_box.Max.y); | ||||
|             if (context.IO.MouseClicked[0]) { | ||||
|                 m_tick_value   = tick_it->tick; | ||||
|                 m_tick_rect    = ImVec4(tick_hover_box.Min.x, tick_hover_box.Min.y, tick_hover_box.Max.x, tick_hover_box.Max.y); | ||||
|             } | ||||
|         } | ||||
|         ++tick_it; | ||||
|     } | ||||
|  | @ -899,7 +903,7 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { | |||
|     tick_it = m_ticks.ticks.begin(); | ||||
|     while (tick_it != m_ticks.ticks.end()) | ||||
|     { | ||||
|         tick_pos = get_tick_pos(tick_it->tick); | ||||
|         float tick_pos = get_tick_pos(tick_it->tick); | ||||
| 
 | ||||
|         //draw ticks
 | ||||
|         ImRect tick_left  = ImRect(slideable_region.GetCenter().x - tick_offset.x, tick_pos - tick_width, slideable_region.GetCenter().x - tick_offset.y, tick_pos); | ||||
|  | @ -908,17 +912,36 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { | |||
|         ImGui::RenderFrame(tick_right.Min, tick_right.Max, tick_clr, false); | ||||
| 
 | ||||
|         //draw pause icon
 | ||||
|         ImGui::PushID(tick_it->tick); | ||||
|         ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); | ||||
|         if (tick_it->type == PausePrint) { | ||||
|             std::wstring pause_icon_name = ImGui::GcodePauseIcon + boost::nowide::widen(std::string("")); | ||||
|             button_with_pos(into_u8(pause_icon_name).c_str(), icon_size, ImVec2(slideable_region.GetCenter().x + icon_offset.x, tick_pos - icon_offset.y)); | ||||
|             ImTextureID pause_icon_id = m_pause_icon_id; | ||||
|             ImVec2      icon_pos     = ImVec2(slideable_region.GetCenter().x + icon_offset.x, tick_pos - icon_offset.y); | ||||
|             button_with_pos(pause_icon_id, icon_size, icon_pos); | ||||
|             if (ImGui::IsMouseHoveringRect(icon_pos, icon_pos + icon_size)) {  | ||||
|                 if(context.IO.MouseClicked[0]) | ||||
|                     int a = 0; | ||||
|             } | ||||
|         } | ||||
|         ImGui::PopStyleColor(1); | ||||
|         ImGui::PopID(); | ||||
| 
 | ||||
|         ++tick_it; | ||||
|     } | ||||
| 
 | ||||
|     tick_it = GetSelection() == ssHigher ? m_ticks.ticks.find(TickCode{this->GetHigherValue()}) : | ||||
|               GetSelection() == ssLower  ? m_ticks.ticks.find(TickCode{this->GetLowerValue()}) : | ||||
|                                            m_ticks.ticks.end(); | ||||
|     if (tick_it != m_ticks.ticks.end()) { | ||||
|         // draw delete icon
 | ||||
|         ImTextureID delete_icon_id = m_delete_icon_id; | ||||
|         ImVec2      icon_pos       = ImVec2(slideable_region.GetCenter().x + icon_offset.x, get_tick_pos(tick_it->tick) - icon_offset.y); | ||||
|         button_with_pos(m_delete_icon_id, icon_size, icon_pos); | ||||
|         if (ImGui::IsMouseHoveringRect(icon_pos, icon_pos + icon_size)) { | ||||
|             if (context.IO.MouseClicked[0]) { | ||||
|                 // delete tick
 | ||||
|                 Type type = tick_it->type; | ||||
|                 m_ticks.ticks.erase(tick_it); | ||||
|                 post_ticks_changed_event(type); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower_value, std::string& higher_label, std::string& lower_label,int v_min, int v_max, const ImVec2& pos,const ImVec2& size, SelectedSlider& selection, bool one_layer_flag, float scale) | ||||
|  | @ -989,8 +1012,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
| 
 | ||||
|     ImRect one_handle = ImRect(higher_handle.Min - ImVec2(one_handle_offset, 0), higher_handle.Max - ImVec2(one_handle_offset, 0)); | ||||
| 
 | ||||
|     static bool become_del_handle = false; | ||||
|     static bool pressed_in_del = false; | ||||
|     //static bool become_del_handle = false;
 | ||||
|     bool value_changed = false; | ||||
|     if (!one_layer_flag)  | ||||
|     { | ||||
|  | @ -999,14 +1021,10 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
|         if (ImGui::ItemHoverable(higher_handle, id) && context.IO.MouseClicked[0]) { | ||||
|             selection = ssHigher;  | ||||
|             h_selected = true; | ||||
|             m_tick_value = -1; | ||||
|             m_tick_rect = ImVec4(); | ||||
|         } | ||||
|         if (ImGui::ItemHoverable(lower_handle, id) && context.IO.MouseClicked[0]) { | ||||
|             selection = ssLower;  | ||||
|             h_selected = false; | ||||
|             m_tick_value = -1; | ||||
|             m_tick_rect = ImVec4(); | ||||
|         } | ||||
| 
 | ||||
|         // update handle position and value
 | ||||
|  | @ -1015,31 +1033,11 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
|             value_changed = slider_behavior(id, higher_slideable_region, v_min, v_max, | ||||
|                 higher_value, &higher_handle, ImGuiSliderFlags_Vertical,  | ||||
|                 m_tick_value, m_tick_rect); | ||||
| 
 | ||||
|             auto it = m_ticks.ticks.find(TickCode{ *higher_value }); | ||||
|             if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type)) | ||||
|             { | ||||
|                 become_del_handle = true; | ||||
|             } | ||||
|             else { | ||||
|                 become_del_handle = false; | ||||
|                 pressed_in_del = false; | ||||
|             } | ||||
|         } | ||||
|         if (!h_selected) { | ||||
|             value_changed = slider_behavior(id, lower_slideable_region, v_min, v_max, | ||||
|                 lower_value, &lower_handle, ImGuiSliderFlags_Vertical, | ||||
|                 m_tick_value, m_tick_rect); | ||||
| 
 | ||||
|             auto it = m_ticks.ticks.find(TickCode{ *lower_value }); | ||||
|             if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type)) | ||||
|             { | ||||
|                 become_del_handle = true; | ||||
|             } | ||||
|             else { | ||||
|                 become_del_handle = false; | ||||
|                 pressed_in_del = false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ImVec2 higher_handle_center = higher_handle.GetCenter(); | ||||
|  | @ -1095,37 +1093,6 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
|             window->DrawList->AddLine(lower_handle_center + ImVec2(0.0f, -line_offset), lower_handle_center + ImVec2(0.0f, line_offset), white_bg, line_width); | ||||
|         } | ||||
| 
 | ||||
|         if (become_del_handle) { | ||||
| 
 | ||||
|             if (context.IO.MouseDown[0] && | ||||
|                 (ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id))) | ||||
|             { | ||||
|                 pressed_in_del = true; | ||||
|             } | ||||
|             if (pressed_in_del && context.IO.MouseReleased[0] && ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id)) { | ||||
|                 pressed_in_del = false; | ||||
|                 //delete tick
 | ||||
|                 auto it = m_ticks.ticks.find(TickCode{ h_selected ? *higher_value : *lower_value }); | ||||
|                 if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type)) | ||||
|                 { | ||||
|                     Type type = it->type; | ||||
|                     m_ticks.ticks.erase(it); | ||||
|                     post_ticks_changed_event(type); | ||||
|                     m_tick_value = -1; | ||||
|                     m_tick_rect = ImVec4(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (h_selected) { | ||||
|                 window->DrawList->AddCircleFilled(higher_handle_center, handle_radius - handle_border, delete_btn_clr); | ||||
|                 window->DrawList->AddLine(higher_handle_center + ImVec2(-line_offset, 0.0f), higher_handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width); | ||||
|             } | ||||
|             if (!h_selected) { | ||||
|                 window->DrawList->AddCircleFilled(lower_handle_center, handle_radius - handle_border, delete_btn_clr); | ||||
|                 window->DrawList->AddLine(lower_handle_center + ImVec2(-line_offset, 0.0f), lower_handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // draw higher label
 | ||||
|         auto text_utf8 = into_u8(higher_label); | ||||
|         text_content_size = ImGui::CalcTextSize(text_utf8.c_str()); | ||||
|  | @ -1157,15 +1124,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
|         value_changed = slider_behavior(id, one_slideable_region, v_min, v_max, | ||||
|             higher_value, &one_handle, ImGuiSliderFlags_Vertical, | ||||
|             m_tick_value, m_tick_rect); | ||||
|         auto it = m_ticks.ticks.find(TickCode{ *higher_value }); | ||||
|         if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type)) | ||||
|         { | ||||
|             become_del_handle = true; | ||||
|         } | ||||
|         else { | ||||
|             become_del_handle = false; | ||||
|             pressed_in_del; | ||||
|         } | ||||
| 
 | ||||
|         ImVec2 handle_center = one_handle.GetCenter(); | ||||
| 
 | ||||
|         // judge whether to open menu
 | ||||
|  | @ -1190,28 +1149,6 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
|         window->DrawList->AddCircleFilled(handle_center, handle_radius - handle_border, handle_clr); | ||||
|         window->DrawList->AddLine(handle_center + ImVec2(-line_offset, 0.0f), handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width); | ||||
|         window->DrawList->AddLine(handle_center + ImVec2(0.0f, -line_offset), handle_center + ImVec2(0.0f, line_offset), white_bg, line_width); | ||||
|         if (become_del_handle) { | ||||
|             if (context.IO.MouseDown[0] && | ||||
|                 (ImGui::ItemHoverable(one_handle, id))) | ||||
|             { | ||||
|                 pressed_in_del = true; | ||||
|             } | ||||
|             if (pressed_in_del && context.IO.MouseReleased[0] && ImGui::ItemHoverable(one_handle, id)) { | ||||
|                 pressed_in_del = false; | ||||
|                 //delete tick
 | ||||
|                 auto it = m_ticks.ticks.find(TickCode{ *higher_value }); | ||||
|                 if (it != m_ticks.ticks.end() && check_ticks_changed_event(it->type)) | ||||
|                 { | ||||
|                     Type type = it->type; | ||||
|                     m_ticks.ticks.erase(it); | ||||
|                     post_ticks_changed_event(type); | ||||
|                     m_tick_value = -1; | ||||
|                     m_tick_rect = ImVec4(); | ||||
|                 } | ||||
|             } | ||||
|             window->DrawList->AddCircleFilled(handle_center, handle_radius - handle_border, delete_btn_clr); | ||||
|             window->DrawList->AddLine(handle_center + ImVec2(-line_offset, 0.0f), handle_center + ImVec2(line_offset, 0.0f), white_bg, line_width); | ||||
|         } | ||||
| 
 | ||||
|         // draw label
 | ||||
|         auto text_utf8 = into_u8(higher_label); | ||||
|  | @ -1222,6 +1159,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower | |||
|         ImGui::RenderFrame(text_rect.Min, text_rect.Max, white_bg, false, rounding); | ||||
|         ImGui::RenderText(text_start + text_padding, higher_label.c_str()); | ||||
|     } | ||||
| 
 | ||||
|     return value_changed; | ||||
| } | ||||
| 
 | ||||
|  | @ -1294,6 +1232,7 @@ bool IMSlider::render(int canvas_width, int canvas_height) | |||
| 
 | ||||
|     ImGui::PopStyleVar(3); | ||||
|     ImGui::PopStyleColor(2); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -343,6 +343,8 @@ private: | |||
|     void *m_one_layer_arrow_id; | ||||
|     void *m_one_layer_off_id; | ||||
|     void *m_one_layer_off_hover_id; | ||||
|     void *m_pause_icon_id; | ||||
|     void *m_delete_icon_id; | ||||
| 
 | ||||
|     DrawMode            m_draw_mode = dmRegular; | ||||
|     Mode                m_mode          = SingleExtruder; | ||||
|  |  | |||
|  | @ -64,8 +64,7 @@ static const std::map<const wchar_t, std::string> font_icons = { | |||
|     {ImGui::FragmentFilterIcon     , "fragment_filter"               }, | ||||
|     {ImGui::FoldButtonIcon         , "im_fold"                       }, | ||||
|     {ImGui::UnfoldButtonIcon       , "im_unfold"                     }, | ||||
|     {ImGui::GcodePauseIcon         , "im_gcode_pause"                }, | ||||
|     {ImGui::SphereButtonIcon       , "toolbar_modifier_sphere"                }, | ||||
|     {ImGui::SphereButtonIcon       , "toolbar_modifier_sphere"       }, | ||||
| 
 | ||||
| }; | ||||
| static const std::map<const wchar_t, std::string> font_icons_large = { | ||||
|  | @ -257,30 +256,37 @@ bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const | |||
|     return value_changed; | ||||
| } | ||||
| 
 | ||||
| bool button_with_pos(const char* label, const ImVec2& size, const ImVec2& pos, ImGuiButtonFlags flags/* = 0*/) { | ||||
| bool button_with_pos(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &pos, const ImVec2 &uv0, const ImVec2 &uv1, int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col, const ImVec2 &margin) | ||||
| { | ||||
| 
 | ||||
|     ImGuiWindow* window = ImGui::GetCurrentWindow(); | ||||
|     if (window->SkipItems) | ||||
|         return false; | ||||
|     ImGuiContext &g      = *GImGui; | ||||
|     ImGuiWindow * window = g.CurrentWindow; | ||||
|     if (window->SkipItems) return false; | ||||
| 
 | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const ImGuiStyle& style = g.Style; | ||||
|     const ImGuiID id = window->GetID(label); | ||||
|     const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); | ||||
|     // Default to using texture ID as ID. User can still push string/integer prefixes.
 | ||||
|     ImGui::PushID((void *) (intptr_t) user_texture_id); | ||||
|     const ImGuiID id = window->GetID("#image"); | ||||
|     ImGui::PopID(); | ||||
| 
 | ||||
|     const ImRect bb(pos, pos + size); | ||||
|     const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float) frame_padding, (float) frame_padding) : g.Style.FramePadding; | ||||
| 
 | ||||
|     const ImRect bb(pos, pos + size + padding * 2 + margin * 2); | ||||
| 
 | ||||
|     bool hovered, held; | ||||
|     bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags); | ||||
|     bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); | ||||
| 
 | ||||
|     // Render
 | ||||
|     const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); | ||||
|     ImGui::RenderNavHighlight(bb, id); | ||||
|     ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); | ||||
| 
 | ||||
|     if (g.LogEnabled) | ||||
|         ImGui::LogSetNextTextDecoration("[", "]"); | ||||
|     ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); | ||||
|     const float border_size = g.Style.FrameBorderSize; | ||||
|     if (border_size > 0.0f) { | ||||
|         window->DrawList->AddRect(bb.Min + ImVec2(1, 1), bb.Max + ImVec2(1, 1), col, g.Style.FrameRounding, 0, border_size); | ||||
|         window->DrawList->AddRect(bb.Min, bb.Max, col, g.Style.FrameRounding, 0, border_size); | ||||
|     } | ||||
| 
 | ||||
|     if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, ImGui::GetColorU32(bg_col)); | ||||
|     window->DrawList->AddImage(user_texture_id, bb.Min + padding + margin, bb.Max - padding - margin, uv0, uv1, ImGui::GetColorU32(tint_col)); | ||||
| 
 | ||||
|     return pressed; | ||||
| } | ||||
|  |  | |||
|  | @ -28,7 +28,15 @@ namespace GUI { | |||
| bool get_data_from_svg(const std::string &filename, unsigned int max_size_px, ThumbnailData &thumbnail_data); | ||||
| 
 | ||||
| bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const ImS32 v_max, ImS32* out_value, ImRect* out_handle, ImGuiSliderFlags flags = 0, const int fixed_value = -1, const ImVec4& fixed_rect = ImVec4()); | ||||
| bool button_with_pos(const char* label, const ImVec2& size, const ImVec2& pos, ImGuiButtonFlags flags = 0); | ||||
| bool button_with_pos(ImTextureID   user_texture_id, | ||||
|                      const ImVec2 &size, | ||||
|                      const ImVec2 &pos, | ||||
|                      const ImVec2 &uv0           = ImVec2(0, 0), | ||||
|                      const ImVec2 &uv1           = ImVec2(1, 1), | ||||
|                      int           frame_padding = -1, | ||||
|                      const ImVec4 &bg_col        = ImVec4(0, 0, 0, 0), | ||||
|                      const ImVec4 &tint_col      = ImVec4(1, 1, 1, 1), | ||||
|                      const ImVec2 &margin        = ImVec2(0, 0)); | ||||
| bool menu_item_with_icon(const char* label, const char* shortcut, ImU32 icon_color, bool selected, bool enabled = true); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -99,9 +99,11 @@ void BindJob::process() | |||
|             } else if (stage == BBL::BindJobStage::LoginStageFinished) { | ||||
|                 curr_percent = 100; | ||||
|                 msg = _L("Logging in"); | ||||
|             } else { | ||||
|                 msg = _L("Logging in"); | ||||
|             } | ||||
|             if (code != 0) { | ||||
|                 msg = login_failed_str + wxString::Format("(code=%d,info=%s)", code, info); | ||||
|                 msg = _L("Login failed") + wxString::Format("(code=%d,info=%s)", code, info); | ||||
|             } | ||||
|             update_status(curr_percent, msg); | ||||
|         } | ||||
|  |  | |||
|  | @ -51,6 +51,49 @@ void PrintJob::on_success(std::function<void()> success) | |||
|     m_success_fun = success; | ||||
| } | ||||
| 
 | ||||
| wxString PrintJob::get_http_error_msg(unsigned int status, std::string body) | ||||
| { | ||||
|     int code = 0; | ||||
|     std::string error; | ||||
|     std::string message; | ||||
|     wxString result; | ||||
|     if (status >= 400 && status < 500) | ||||
|         try { | ||||
|         json j = json::parse(body); | ||||
|         if (j.contains("code")) { | ||||
|             if (!j["code"].is_null()) | ||||
|                 code = j["code"].get<int>(); | ||||
|         } | ||||
|         if (j.contains("error")) { | ||||
|             if (!j["error"].is_null()) | ||||
|                 error = j["error"].get<std::string>(); | ||||
|         } | ||||
|         if (j.contains("message")) { | ||||
|             if (!j["message"].is_null()) | ||||
|                 message = j["message"].get<std::string>(); | ||||
|         } | ||||
|         switch (status) { | ||||
|             ; | ||||
|         } | ||||
|     } | ||||
|     catch (...) { | ||||
|         ; | ||||
|     } | ||||
|     else if (status == 503) { | ||||
|         return _L("Service Unavailable"); | ||||
|     } | ||||
|     else { | ||||
|         wxString unkown_text = _L("Unkown Error."); | ||||
|         unkown_text += wxString::Format("status=%u, body=%s", status, body); | ||||
|         return unkown_text; | ||||
|     } | ||||
| 
 | ||||
|     BOOST_LOG_TRIVIAL(error) << "http_error: status=" << status << ", code=" << code << ", error=" << error; | ||||
| 
 | ||||
|     result = wxString::Format("code=%u, error=%s", code, from_u8(error)); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void PrintJob::process() | ||||
| { | ||||
|     /* display info */ | ||||
|  | @ -114,8 +157,10 @@ void PrintJob::process() | |||
|     params.dev_ip = m_dev_ip; | ||||
|     params.username = "bblp"; | ||||
|     params.password = m_access_code; | ||||
|     wxString error_text; | ||||
|     wxString msg_text; | ||||
| 
 | ||||
|     auto update_fn = [this, &msg, &curr_percent](int stage, int code, std::string info) { | ||||
|     auto update_fn = [this, &msg, &curr_percent, &error_text](int stage, int code, std::string info) { | ||||
|                         if (stage == BBL::SendingPrintJobStage::PrintingStageCreate) { | ||||
|                             if (this->connection_type == "lan") { | ||||
|                                 msg = _L("Sending print job over LAN"); | ||||
|  | @ -157,7 +202,7 @@ void PrintJob::process() | |||
|                         } | ||||
|                         else if (stage == BBL::SendingPrintJobStage::PrintingStageFinished) { | ||||
|                             curr_percent = 100; | ||||
|                             msg = wxString::Format(_L("Successfully sent.Will automatically jump to the device page in %s s"), info); | ||||
|                             msg = wxString::Format(_L("Successfully sent. Will automatically jump to the device page in %s s"), info); | ||||
|                         } else { | ||||
|                             if (this->connection_type == "lan") { | ||||
|                                 msg = _L("Sending print job over LAN"); | ||||
|  | @ -165,6 +210,10 @@ void PrintJob::process() | |||
|                                 msg = _L("Sending print job through cloud service"); | ||||
|                             } | ||||
|                         } | ||||
|                         if (code != 0) { | ||||
|                             error_text = this->get_http_error_msg(code, info); | ||||
|                             msg += wxString::Format("[%s]", error_text); | ||||
|                         } | ||||
|                         this->update_status(curr_percent, msg); | ||||
|                     }; | ||||
| 
 | ||||
|  | @ -193,19 +242,6 @@ void PrintJob::process() | |||
|             BOOST_LOG_TRIVIAL(info) << "print_job: send with cloud"; | ||||
|             this->update_status(curr_percent, _L("Sending print job through cloud service")); | ||||
|             result = m_agent->start_print(params, update_fn, cancel_fn); | ||||
|             if (result < 0) { | ||||
|                 if (!params.password.empty() && !params.dev_ip.empty()) { | ||||
|                     //try to send with local only
 | ||||
|                     if (this->has_sdcard) { | ||||
|                         this->update_status(curr_percent, _L("Sending print job over LAN")); | ||||
|                         result = m_agent->start_local_print(params, update_fn, cancel_fn); | ||||
|                     } else { | ||||
|                         this->update_status(curr_percent, _L("Failed to connect to the cloud server connection. Please insert an SD card and resend the print job, which will transfer the print file via LAN. ")); | ||||
|                         BOOST_LOG_TRIVIAL(error) << "print_job: failed, need sdcard"; | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         if (this->has_sdcard) { | ||||
|  | @ -224,26 +260,29 @@ void PrintJob::process() | |||
| 
 | ||||
|     if (result < 0) { | ||||
|         if (result == BAMBU_NETWORK_ERR_FTP_LOGIN_DENIED) { | ||||
|             update_status(curr_percent, upload_failed_str); | ||||
|             msg_text = upload_failed_str; | ||||
|         } if (result == BAMBU_NETWORK_ERR_FILE_NOT_EXIST) { | ||||
|             update_status(curr_percent, file_is_not_exists_str); | ||||
|             msg_text = file_is_not_exists_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_FILE_OVER_SIZE) { | ||||
|             update_status(curr_percent, file_over_size_str); | ||||
|             msg_text = file_over_size_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_CHECK_MD5_FAILED) { | ||||
|             update_status(curr_percent, failed_in_cloud_service_str); | ||||
|             msg_text = failed_in_cloud_service_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_INVALID_PARAMS) { | ||||
|             update_status(curr_percent, upload_failed_str); | ||||
|             msg_text = upload_failed_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_CANCELED) { | ||||
|             update_status(curr_percent, print_canceled_str); | ||||
|             msg_text = print_canceled_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_TIMEOUT) { | ||||
|             update_status(curr_percent, timeout_to_upload_str); | ||||
|             msg_text = timeout_to_upload_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_INVALID_RESULT) { | ||||
|             update_status(curr_percent, upload_failed_str); | ||||
|             msg_text = upload_failed_str; | ||||
|         } else if (result == BAMBU_NETWORK_ERR_FTP_UPLOAD_FAILED) { | ||||
|             update_status(curr_percent, upload_failed_str); | ||||
|             msg_text = upload_failed_str; | ||||
|         } else { | ||||
|             update_status(curr_percent, failed_in_cloud_service_str); | ||||
|         } | ||||
|         if (!error_text.IsEmpty()) | ||||
|             msg_text += wxString::Format("[%s]", error_text); | ||||
|         update_status(curr_percent, msg_text); | ||||
|         BOOST_LOG_TRIVIAL(error) << "print_job: failed, result = " << result; | ||||
|     } else { | ||||
|         BOOST_LOG_TRIVIAL(error) << "print_job: send ok."; | ||||
|  |  | |||
|  | @ -70,6 +70,7 @@ public: | |||
|     void set_print_job_finished_event(int event_id) { m_print_job_completed_id = event_id; } | ||||
| 
 | ||||
|     void on_success(std::function<void()> success); | ||||
|     wxString get_http_error_msg(unsigned int status, std::string body); | ||||
|     void process() override; | ||||
|     void finalize() override; | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										136
									
								
								src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | |||
| #include "UpgradeNetworkJob.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/GUI.hpp" | ||||
| #include "slic3r/GUI/GUI_App.hpp" | ||||
| #include "slic3r/Utils/Http.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| wxDEFINE_EVENT(EVT_UPGRADE_UPDATE_MESSAGE, wxCommandEvent); | ||||
| wxDEFINE_EVENT(EVT_UPGRADE_NETWORK_SUCCESS, wxCommandEvent); | ||||
| wxDEFINE_EVENT(EVT_UPGRADE_NETWORK_FAILED, wxCommandEvent); | ||||
| 
 | ||||
| 
 | ||||
| UpgradeNetworkJob::UpgradeNetworkJob(std::shared_ptr<ProgressIndicator> pri) | ||||
|     : Job{std::move(pri)} | ||||
| { | ||||
|     ; | ||||
| } | ||||
| 
 | ||||
| void UpgradeNetworkJob::on_exception(const std::exception_ptr &eptr) | ||||
| { | ||||
|     try { | ||||
|         if (eptr) | ||||
|             std::rethrow_exception(eptr); | ||||
|     } catch (std::exception &e) { | ||||
|         UpgradeNetworkJob::on_exception(eptr); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void UpgradeNetworkJob::on_success(std::function<void()> success) | ||||
| { | ||||
|     m_success_fun = success; | ||||
| } | ||||
| 
 | ||||
| void UpgradeNetworkJob::update_status(int st, const wxString &msg) | ||||
| { | ||||
|     GUI::Job::update_status(st, msg); | ||||
|     wxCommandEvent event(EVT_UPGRADE_UPDATE_MESSAGE); | ||||
|     event.SetString(msg); | ||||
|     event.SetEventObject(m_event_handle); | ||||
|     wxPostEvent(m_event_handle, event); | ||||
| } | ||||
| 
 | ||||
| void UpgradeNetworkJob::process() | ||||
| { | ||||
|     // downloading
 | ||||
|     int result = 0; | ||||
|      | ||||
|     AppConfig* app_config = wxGetApp().app_config; | ||||
|     if (!app_config) | ||||
|         return; | ||||
| 
 | ||||
|     BOOST_LOG_TRIVIAL(info) << "[download_plugin]: enter"; | ||||
| 
 | ||||
|     // get temp path
 | ||||
|     fs::path target_file_path = (fs::temp_directory_path() / "network_plugin.zip"); | ||||
|     fs::path tmp_path = target_file_path; | ||||
|     auto path_str = tmp_path.string() + wxString::Format(".%d%s", get_current_pid(), ".tmp").ToStdString(); | ||||
|     tmp_path = fs::path(path_str); | ||||
| 
 | ||||
|     auto cancel_fn = [this]() { | ||||
|         return was_canceled(); | ||||
|     }; | ||||
|     int curr_percent = 0; | ||||
|     result = wxGetApp().download_plugin( | ||||
|         [this, &curr_percent](int state, int percent, bool &cancel) { | ||||
|             if (state == InstallStatusNormal) { | ||||
|                 update_status(percent, _L("Downloading")); | ||||
|             } else if (state == InstallStatusDownloadFailed) { | ||||
|                 update_status(percent, _L("Download failed")); | ||||
|             } else { | ||||
|                 update_status(percent, _L("Downloading")); | ||||
|             } | ||||
|             curr_percent = percent; | ||||
|         }, cancel_fn); | ||||
|      | ||||
|     if (was_canceled()) { | ||||
|         update_status(0, _L("Cancelled")); | ||||
|         wxCommandEvent event(wxEVT_CLOSE_WINDOW); | ||||
|         event.SetEventObject(m_event_handle); | ||||
|         wxPostEvent(m_event_handle, event); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (result < 0) { | ||||
|         update_status(curr_percent, _L("Download failed")); | ||||
|         wxCommandEvent event(EVT_UPGRADE_NETWORK_FAILED); | ||||
|         event.SetEventObject(m_event_handle); | ||||
|         wxPostEvent(m_event_handle, event); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     result = wxGetApp().install_plugin([this](int state, int percent, bool&cancel) { | ||||
|         if (state == InstallStatusInstallCompleted) { | ||||
|             update_status(percent, _L("Finish")); | ||||
|         } else { | ||||
|             update_status(percent, _L("Installing")); | ||||
|         } | ||||
|         }, cancel_fn); | ||||
| 
 | ||||
|     if (was_canceled()) { | ||||
|         update_status(0, _L("Cancelled")); | ||||
|         wxCommandEvent event(wxEVT_CLOSE_WINDOW); | ||||
|         event.SetEventObject(m_event_handle); | ||||
|         wxPostEvent(m_event_handle, event); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (result != 0) { | ||||
|         update_status(curr_percent, _L("Install failed")); | ||||
|         wxCommandEvent event(EVT_UPGRADE_NETWORK_FAILED); | ||||
|         event.SetEventObject(m_event_handle); | ||||
|         wxPostEvent(m_event_handle, event); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     wxCommandEvent event(EVT_UPGRADE_NETWORK_SUCCESS); | ||||
|     event.SetEventObject(m_event_handle); | ||||
|     wxPostEvent(m_event_handle, event); | ||||
|     return; | ||||
| } | ||||
| 
 | ||||
| void UpgradeNetworkJob::finalize() | ||||
| { | ||||
|     if (was_canceled()) return; | ||||
| 
 | ||||
|     Job::finalize(); | ||||
| } | ||||
| 
 | ||||
| void UpgradeNetworkJob::set_event_handle(wxWindow *hanle) | ||||
| { | ||||
|     m_event_handle = hanle; | ||||
| } | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
							
								
								
									
										56
									
								
								src/slic3r/GUI/Jobs/UpgradeNetworkJob.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/slic3r/GUI/Jobs/UpgradeNetworkJob.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| #ifndef __UpgradeNetworkJob_HPP__ | ||||
| #define __UpgradeNetworkJob_HPP__ | ||||
| 
 | ||||
| #include <functional> | ||||
| #include "Job.hpp" | ||||
| 
 | ||||
| namespace fs = boost::filesystem; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| enum PluginInstallStatus { | ||||
|     InstallStatusNormal = 0, | ||||
|     InstallStatusDownloadFailed = 1, | ||||
|     InstallStatusDownloadCompleted = 2, | ||||
|     InstallStatusUnzipFailed = 3, | ||||
|     InstallStatusInstallCompleted = 4, | ||||
| }; | ||||
| 
 | ||||
| typedef std::function<void(int status, int percent, bool& cancel)> InstallProgressFn; | ||||
| 
 | ||||
| class UpgradeNetworkJob : public Job | ||||
| { | ||||
|     wxWindow *           m_event_handle{nullptr}; | ||||
|     std::function<void()> m_success_fun{nullptr}; | ||||
|     bool                m_job_finished{ false }; | ||||
|     int                 m_print_job_completed_id = 0; | ||||
| 
 | ||||
|     InstallProgressFn pro_fn { nullptr }; | ||||
| 
 | ||||
| protected: | ||||
|     void on_exception(const std::exception_ptr &) override; | ||||
| public: | ||||
|     UpgradeNetworkJob(std::shared_ptr<ProgressIndicator> pri); | ||||
| 
 | ||||
|     int  status_range() const override | ||||
|     { | ||||
|         return 100; | ||||
|     } | ||||
| 
 | ||||
|     bool is_finished() { return m_job_finished;  } | ||||
| 
 | ||||
|     void on_success(std::function<void()> success); | ||||
|     void update_status(int st, const wxString &msg); | ||||
|     void process() override; | ||||
|     void finalize() override; | ||||
|     void set_event_handle(wxWindow* hanle); | ||||
| }; | ||||
| 
 | ||||
| wxDECLARE_EVENT(EVT_UPGRADE_UPDATE_MESSAGE, wxCommandEvent); | ||||
| wxDECLARE_EVENT(EVT_UPGRADE_NETWORK_SUCCESS, wxCommandEvent); | ||||
| wxDECLARE_EVENT(EVT_UPGRADE_NETWORK_FAILED, wxCommandEvent); | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
| 
 | ||||
| #endif // ARRANGEJOB_HPP
 | ||||
|  | @ -157,7 +157,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ | |||
| #ifdef __WXOSX__ | ||||
|     set_miniaturizable(GetHandle()); | ||||
| #endif | ||||
|      | ||||
| 
 | ||||
|     //reset developer_mode to false  and user_mode to comAdvanced
 | ||||
|     wxGetApp().app_config->set_bool("developer_mode", false); | ||||
|     if (wxGetApp().app_config->get("user_mode") == "develop") { | ||||
|  | @ -178,17 +178,17 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ | |||
|     // Fonts were created by the DPIFrame constructor for the monitor, on which the window opened.
 | ||||
|     wxGetApp().update_fonts(this); | ||||
| 
 | ||||
|     #ifdef __WINDOWS__ | ||||
|         m_topbar         = new BBLTopbar(this); | ||||
|     #else | ||||
| #ifdef __WINDOWS__ | ||||
|     m_topbar         = new BBLTopbar(this); | ||||
| #else | ||||
|     auto panel_topbar = new wxPanel(this, wxID_ANY); | ||||
|     panel_topbar->SetBackgroundColour(wxColour(38, 46, 48)); | ||||
|     auto sizer_tobar = new wxBoxSizer(wxVERTICAL); | ||||
|     m_topbar         = new BBLTopbar(panel_topbar, this); | ||||
|     m_topbar         = new BBLTopbar(this); | ||||
|     sizer_tobar->Add(m_topbar, 0, wxEXPAND); | ||||
|     panel_topbar->SetSizer(sizer_tobar); | ||||
|     panel_topbar->Layout(); | ||||
|     #endif | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -326,11 +326,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ | |||
|     // initialize layout
 | ||||
|     m_main_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|     wxSizer* sizer = new wxBoxSizer(wxVERTICAL); | ||||
|     #ifdef __WINDOWS__ | ||||
| #ifdef __WINDOWS__ | ||||
|      sizer->Add(m_topbar, 0, wxEXPAND); | ||||
|     #else | ||||
| #else | ||||
|      sizer->Add(panel_topbar, 0, wxEXPAND); | ||||
|     #endif // __WINDOWS__
 | ||||
| #endif // __WINDOWS__
 | ||||
| 
 | ||||
| 
 | ||||
|     sizer->Add(m_main_sizer, 1, wxEXPAND); | ||||
|  | @ -357,14 +357,10 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ | |||
|     Fit(); | ||||
| 
 | ||||
|     const wxSize min_size = wxGetApp().get_min_size(); //wxSize(76*wxGetApp().em_unit(), 49*wxGetApp().em_unit());
 | ||||
| #ifdef __APPLE__ | ||||
|     // Using SetMinSize() on Mac messes up the window position in some cases
 | ||||
|     // cf. https://groups.google.com/forum/#!topic/wx-users/yUKPBBfXWO0
 | ||||
|     SetSize(min_size/*wxSize(760, 490)*/); | ||||
| #else | ||||
| 
 | ||||
|     SetMinSize(min_size/*wxSize(760, 490)*/); | ||||
|     SetSize(wxSize(FromDIP(1200), FromDIP(800))); | ||||
| #endif | ||||
| 
 | ||||
|     Layout(); | ||||
| 
 | ||||
|     update_title(); | ||||
|  | @ -747,6 +743,29 @@ void MainFrame::init_tabpanel() | |||
|     m_tabpanel->Hide(); | ||||
|     m_settings_dialog.set_tabpanel(m_tabpanel); | ||||
| 
 | ||||
|     m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGING, [this](wxBookCtrlEvent& e) { | ||||
|         int old_sel = e.GetOldSelection(); | ||||
|         int new_sel = e.GetSelection(); | ||||
|         if (new_sel == tpMonitor) { | ||||
|             if (!wxGetApp().getAgent()) { | ||||
|                 e.Veto(); | ||||
|                 BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2%, lack of network plugins")%old_sel %new_sel; | ||||
|                 if (m_plater) { | ||||
|                     wxCommandEvent *evt = new wxCommandEvent(EVT_INSTALL_PLUGIN_HINT); | ||||
|                     wxQueueEvent(m_plater, evt); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else if (new_sel == tp3DEditor) { | ||||
|             if (m_plater && (m_plater->only_gcode_mode() || (m_plater->using_exported_file()))) { | ||||
|                 e.Veto(); | ||||
|                 BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2% in preview mode")%old_sel %new_sel; | ||||
|                 wxCommandEvent *evt = new wxCommandEvent(EVT_PREVIEW_ONLY_MODE_HINT); | ||||
|                 wxQueueEvent(m_plater, evt); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
| #ifdef __WXMSW__ | ||||
|     m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent& e) { | ||||
| #else | ||||
|  | @ -758,12 +777,11 @@ void MainFrame::init_tabpanel() | |||
|         //wxString page_text = m_tabpanel->GetPageText(sel);
 | ||||
|         m_last_selected_tab = m_tabpanel->GetSelection(); | ||||
|         if (panel == m_plater) { | ||||
|             if (m_with_3dEditor && (sel == tp3DEditor)) { | ||||
|             if (sel == tp3DEditor) { | ||||
|                 wxPostEvent(m_plater, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); | ||||
|                 m_param_panel->OnActivate(); | ||||
|             } | ||||
|             else if ((m_with_3dEditor&&(sel == tpPreview)) | ||||
|                 || (!m_with_3dEditor&&(sel == tp3DEditor))){ | ||||
|             else if (sel == tpPreview) { | ||||
|                 wxPostEvent(m_plater, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); | ||||
|                 m_param_panel->OnActivate(); | ||||
|             } | ||||
|  | @ -774,7 +792,7 @@ void MainFrame::init_tabpanel() | |||
|             //monitor
 | ||||
|         } | ||||
| 
 | ||||
|         if (m_with_3dEditor && (sel == tp3DEditor)) { | ||||
|         if (sel == tp3DEditor) { | ||||
|             m_topbar->EnableUndoRedoItems(); | ||||
|         } | ||||
|         else { | ||||
|  | @ -1672,10 +1690,13 @@ void MainFrame::init_menubar_as_editor() | |||
|         append_menu_item(export_menu, wxID_ANY, _L("Export all objects as STL") + dots, _L("Export all objects as STL"), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, "menu_export_stl", nullptr, | ||||
|             [this](){return can_export_model(); }, this); | ||||
|         // BBS export Gcode
 | ||||
|         wxMenuItem* item_export_gcode = append_menu_item(export_menu, wxID_ANY, _L("Export Sliced File") + dots/* + "\tCtrl+G"*/, _L("Export current Sliced file"), | ||||
|         // BBS export .gcode.3mf
 | ||||
|         append_menu_item(export_menu, wxID_ANY, _L("Export Sliced File") + dots/* + "\tCtrl+G"*/, _L("Export current Sliced file"), | ||||
|             [this](wxCommandEvent&) { if (m_plater) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); }, "menu_export_sliced_file", nullptr, | ||||
|             [this](){return can_export_gcode(); }, this); | ||||
|         append_menu_item(export_menu, wxID_ANY, _L("Export G-code") + dots/* + "\tCtrl+G"*/, _L("Export current plate as G-code"), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(false); }, "menu_export_gcode", nullptr, | ||||
|             [this]() {return can_export_gcode(); }, this); | ||||
| 
 | ||||
|         append_submenu(fileMenu, export_menu, wxID_ANY, _L("Export"), ""); | ||||
| 
 | ||||
|  | @ -1788,20 +1809,20 @@ void MainFrame::init_menubar_as_editor() | |||
|         append_menu_item(editMenu, wxID_ANY, _L("Deselect all") + "\tEsc", | ||||
|             _L("Deselects all objects"), [this](wxCommandEvent&) { m_plater->deselect_all(); }, | ||||
|             "", nullptr, [this](){return can_deselect(); }, this); | ||||
|         editMenu->AppendSeparator(); | ||||
|         append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Mesh(TODO)"), | ||||
|             _L("Display triangles of models"), [this](wxCommandEvent& evt) { | ||||
|                 wxGetApp().app_config->set_bool("show_model_mesh", evt.GetInt() == 1); | ||||
|             }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_mesh").compare("true") == 0; }, this); | ||||
|         append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Shadow(TODO)"), _L("Display shadow of objects"), | ||||
|             [this](wxCommandEvent& evt) { | ||||
|                 wxGetApp().app_config->set_bool("show_model_shadow", evt.GetInt() == 1); | ||||
|             }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_shadow").compare("true") == 0; }, this); | ||||
|         editMenu->AppendSeparator(); | ||||
|         append_menu_check_item(editMenu, wxID_ANY, _L("Show Printable Box(TODO)"), _L("Display printable box"), | ||||
|             [this](wxCommandEvent& evt) { | ||||
|                 wxGetApp().app_config->set_bool("show_printable_box", evt.GetInt() == 1); | ||||
|             }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_printable_box").compare("true") == 0; }, this); | ||||
|         //editMenu->AppendSeparator();
 | ||||
|         //append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Mesh(TODO)"),
 | ||||
|         //    _L("Display triangles of models"), [this](wxCommandEvent& evt) {
 | ||||
|         //        wxGetApp().app_config->set_bool("show_model_mesh", evt.GetInt() == 1);
 | ||||
|         //    }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_mesh").compare("true") == 0; }, this);
 | ||||
|         //append_menu_check_item(editMenu, wxID_ANY, _L("Show Model Shadow(TODO)"), _L("Display shadow of objects"),
 | ||||
|         //    [this](wxCommandEvent& evt) {
 | ||||
|         //        wxGetApp().app_config->set_bool("show_model_shadow", evt.GetInt() == 1);
 | ||||
|         //    }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_model_shadow").compare("true") == 0; }, this);
 | ||||
|         //editMenu->AppendSeparator();
 | ||||
|         //append_menu_check_item(editMenu, wxID_ANY, _L("Show Printable Box(TODO)"), _L("Display printable box"),
 | ||||
|         //    [this](wxCommandEvent& evt) {
 | ||||
|         //        wxGetApp().app_config->set_bool("show_printable_box", evt.GetInt() == 1);
 | ||||
|         //    }, nullptr, [this]() {return can_select(); }, [this]() { return wxGetApp().app_config->get("show_printable_box").compare("true") == 0; }, this);
 | ||||
|     } | ||||
| 
 | ||||
|     // BBS
 | ||||
|  | @ -2234,7 +2255,7 @@ void MainFrame::select_tab(wxPanel* panel) | |||
| //BBS
 | ||||
| void MainFrame::jump_to_monitor(std::string dev_id) | ||||
| { | ||||
|     m_tabpanel->SetSelection(m_with_3dEditor? tpMonitor:(tpMonitor-1)); | ||||
|     m_tabpanel->SetSelection(tpMonitor); | ||||
|     ((MonitorPanel*)m_monitor)->select_machine(dev_id); | ||||
| } | ||||
| 
 | ||||
|  | @ -2273,42 +2294,10 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) | |||
|     select(false); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::enable_tab(size_t tab, bool enabled) | ||||
| { | ||||
|     if (tab != tp3DEditor) | ||||
|         //currently only support 3dEditor
 | ||||
|         return; | ||||
| 
 | ||||
|     if ((enabled && m_with_3dEditor) || (!enabled && !m_with_3dEditor)) | ||||
|         //already done
 | ||||
|         return; | ||||
| 
 | ||||
|     Freeze(); | ||||
|     if (enabled) { | ||||
|         int sel = m_tabpanel->GetSelection(); | ||||
|         m_tabpanel->InsertPage(tab, m_plater, _L("Prepare"), std::string("tab_3d_active"), std::string("tab_3d_active")); | ||||
|         if (sel >= tab) | ||||
|             m_tabpanel->SetSelection(sel + 1); | ||||
|     } | ||||
|     else { | ||||
|         int sel = m_tabpanel->GetSelection(); | ||||
|         m_tabpanel->RemovePage(tab); | ||||
|         if (sel >= tab) | ||||
|             m_tabpanel->SetSelection(sel - 1); | ||||
|     } | ||||
|     m_with_3dEditor = enabled; | ||||
|     m_plater->Show(); | ||||
|     m_tabpanel->Show(); | ||||
|     Thaw(); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::request_select_tab(TabPosition pos) | ||||
| { | ||||
|     int position = pos; | ||||
|     if ((!m_with_3dEditor)&&(pos >= tpPreview)) | ||||
|         position = (int)pos -1; | ||||
|     wxCommandEvent* evt = new wxCommandEvent(EVT_SELECT_TAB); | ||||
|     evt->SetInt(position); | ||||
|     evt->SetInt(pos); | ||||
|     wxQueueEvent(this, evt); | ||||
| } | ||||
| 
 | ||||
|  | @ -2487,6 +2476,12 @@ void MainFrame::load_url(wxString url) | |||
|     wxQueueEvent(this, evt); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::refresh_plugin_tips() | ||||
| { | ||||
|     if (m_webview != nullptr) | ||||
|         m_webview->ShowNetpluginTip(); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::RunScript(wxString js) | ||||
| { | ||||
|     if (m_webview != nullptr) | ||||
|  | @ -2538,7 +2533,7 @@ void MainFrame::on_select_default_preset(SimpleEvent& evt) | |||
| { | ||||
|     MessageDialog dialog(this, | ||||
|                     _L("Do you want to synchronize your personal data from Bambu Cloud? \n" | ||||
|                         "Contains the following information:\n" | ||||
|                         "It contains the following information:\n" | ||||
|                         "1. The Process presets\n" | ||||
|                         "2. The Filament presets\n" | ||||
|                         "3. The Printer presets\n"), | ||||
|  |  | |||
|  | @ -83,7 +83,6 @@ protected: | |||
| class MainFrame : public DPIFrame | ||||
| { | ||||
|     bool        m_loaded {false}; | ||||
|     bool        m_with_3dEditor { true }; | ||||
| 
 | ||||
|     wxString    m_qs_last_input_file = wxEmptyString; | ||||
|     wxString    m_qs_last_output_file = wxEmptyString; | ||||
|  | @ -278,7 +277,6 @@ public: | |||
|     // Select tab in m_tabpanel
 | ||||
|     // When tab == -1, will be selected last selected tab
 | ||||
|     //BBS: GUI refactor
 | ||||
|     void        enable_tab(size_t tab, bool enabled = true); | ||||
|     void        select_tab(wxPanel* panel); | ||||
|     void        select_tab(size_t tab = size_t(-1)); | ||||
|     void        request_select_tab(TabPosition pos); | ||||
|  | @ -301,6 +299,7 @@ public: | |||
| 
 | ||||
|     //BBS
 | ||||
|     void        load_url(wxString url); | ||||
|     void        refresh_plugin_tips(); | ||||
|     void RunScript(wxString js); | ||||
| 
 | ||||
|     // BBS. Replace title bar and menu bar with top bar.
 | ||||
|  |  | |||
|  | @ -108,19 +108,23 @@ bool MarkdownTip::ShowTip(wxPoint pos, std::string const &tip, std::string const | |||
|             return false; | ||||
|         if (pos.x) { | ||||
|             _hide = true; | ||||
|             BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: hide soon on empty tip."; | ||||
|             this->Hide(); | ||||
|         } | ||||
|         else if (!_hide) { | ||||
|             _hide = true; | ||||
|             BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: start hide timer (300)..."; | ||||
|             _timer->StartOnce(300); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     if (_lastTip != tip) { | ||||
|     bool tipChanged = _lastTip != tip; | ||||
|     if (tipChanged) { | ||||
|         auto content = LoadTip(tip, tooltip); | ||||
|         if (content.empty()) { | ||||
|             _hide = true; | ||||
|             this->Hide(); | ||||
|             BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: hide soon on empty content."; | ||||
|             return false; | ||||
|         } | ||||
|         auto script = "window.showMarkdown('" + url_encode(content) + "', true);"; | ||||
|  | @ -140,8 +144,11 @@ bool MarkdownTip::ShowTip(wxPoint pos, std::string const &tip, std::string const | |||
|         if (pos.y + this->GetSize().y > size.y) | ||||
|             pos.y = size.y - this->GetSize().y; | ||||
|         this->SetPosition(pos); | ||||
|         _hide = false; | ||||
|         _timer->StartOnce(500); | ||||
|         if (tipChanged || _hide) { | ||||
|             _hide = false; | ||||
|             BOOST_LOG_TRIVIAL(info) << "MarkdownTip::ShowTip: start show timer (500)..."; | ||||
|             _timer->StartOnce(500); | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | @ -264,11 +271,14 @@ void MarkdownTip::OnTimer(wxTimerEvent& event) | |||
|     if (_hide) { | ||||
|         wxPoint pos = ScreenToClient(wxGetMousePosition()); | ||||
|         if (GetClientRect().Contains(pos)) { | ||||
|             BOOST_LOG_TRIVIAL(info) << "MarkdownTip::OnTimer: restart hide timer..."; | ||||
|             _timer->StartOnce(); | ||||
|             return; | ||||
|         } | ||||
|         BOOST_LOG_TRIVIAL(info) << "MarkdownTip::OnTimer: hide."; | ||||
|         this->Hide(); | ||||
|     } else { | ||||
|         BOOST_LOG_TRIVIAL(info) << "MarkdownTip::OnTimer: show."; | ||||
|         this->Show(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -163,7 +163,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) | |||
|     auto fs = m_image_grid->GetFileSystem(); | ||||
|     if (fs) { | ||||
|         m_image_grid->SetFileSystem(nullptr); | ||||
|         fs->Unbind(EVT_MODE_CHANGED, &MediaFilePanel::fileChanged, this); | ||||
|         fs->Unbind(EVT_MODE_CHANGED, &MediaFilePanel::modeChanged, this); | ||||
|         fs->Stop(true); | ||||
|     } | ||||
|     if (m_machine.empty()) { | ||||
|  | @ -171,7 +171,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) | |||
|     } else { | ||||
|         boost::shared_ptr<PrinterFileSystem> fs(new PrinterFileSystem); | ||||
|         m_image_grid->SetFileSystem(fs); | ||||
|         fs->Bind(EVT_MODE_CHANGED, &MediaFilePanel::fileChanged, this); | ||||
|         fs->Bind(EVT_MODE_CHANGED, &MediaFilePanel::modeChanged, this); | ||||
|         fs->Bind(EVT_STATUS_CHANGED, [this, wfs = boost::weak_ptr(fs)](auto &e) { | ||||
|             boost::shared_ptr fs(wfs.lock()); | ||||
|             if (m_image_grid->GetFileSystem() != fs) // canceled
 | ||||
|  | @ -183,6 +183,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) | |||
|             case PrinterFileSystem::Connecting: icon = m_bmp_loading.bmp(); msg = _L("Connecting..."); break; | ||||
|             case PrinterFileSystem::Failed: icon = m_bmp_failed.bmp(); msg = _L("Connect failed [%d]!"); break; | ||||
|             case PrinterFileSystem::ListSyncing: icon = m_bmp_loading.bmp(); msg = _L("Loading file list..."); break; | ||||
|             case PrinterFileSystem::ListReady: icon = m_bmp_empty.bmp(); msg = _L("No files"); break; | ||||
|             } | ||||
|             if (fs->GetCount() == 0) | ||||
|                 m_image_grid->SetStatus(icon, msg); | ||||
|  | @ -192,7 +193,7 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) | |||
|         if (IsShown()) fs->Start(); | ||||
|     } | ||||
|     wxCommandEvent e(EVT_MODE_CHANGED); | ||||
|     fileChanged(e); | ||||
|     modeChanged(e); | ||||
| } | ||||
| 
 | ||||
| void MediaFilePanel::Rescale() | ||||
|  | @ -218,12 +219,10 @@ void MediaFilePanel::Rescale() | |||
|     m_image_grid->Rescale(); | ||||
| } | ||||
| 
 | ||||
| void MediaFilePanel::fileChanged(wxCommandEvent& e1) | ||||
| void MediaFilePanel::modeChanged(wxCommandEvent& e1) | ||||
| { | ||||
|     e1.Skip(); | ||||
|     auto fs = m_image_grid->GetFileSystem(); | ||||
|     if (fs) | ||||
|         m_image_grid->SetStatus(m_bmp_empty.bmp(), fs->GetCount() ? L"" : _L("No files")); | ||||
|     auto mode = fs ? fs->GetGroupMode() : 0; | ||||
|     if (m_last_mode == mode) | ||||
|         return; | ||||
|  | @ -247,7 +246,7 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs) | |||
|             BOOST_LOG_TRIVIAL(info) << "MediaFilePanel::fetchUrl: camera_url: " << url; | ||||
|             CallAfter([this, url, wfs] { | ||||
|                 boost::shared_ptr fs(wfs.lock()); | ||||
|                 if (fs != m_image_grid->GetFileSystem()) return; | ||||
|                 if (!fs || fs != m_image_grid->GetFileSystem()) return; | ||||
|                 fs->SetUrl(url); | ||||
|             }); | ||||
|         }); | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ public: | |||
|     void Rescale(); | ||||
| 
 | ||||
| private: | ||||
|     void fileChanged(wxCommandEvent & e); | ||||
|     void modeChanged(wxCommandEvent & e); | ||||
| 
 | ||||
|     void fetchUrl(boost::weak_ptr<PrinterFileSystem> fs); | ||||
| 
 | ||||
|  |  | |||
|  | @ -111,7 +111,7 @@ void MediaPlayCtrl::Stop() | |||
|         m_media_ctrl->InvalidateBestSize(); | ||||
|         m_button_play->SetIcon("media_play"); | ||||
|         boost::unique_lock lock(m_mutex); | ||||
|         m_tasks.push_back(""); | ||||
|         m_tasks.push_back("<stop>"); | ||||
|         m_cond.notify_all(); | ||||
|     } | ||||
|     m_last_state = MEDIASTATE_IDLE; | ||||
|  | @ -132,6 +132,11 @@ void MediaPlayCtrl::SetStatus(wxString const& msg2) | |||
| { | ||||
|     auto msg = wxString::Format(msg2, m_failed_code); | ||||
|     BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::SetStatus: " << msg.ToUTF8().data(); | ||||
| #ifdef __WXMSW__ | ||||
|     OutputDebugStringA("MediaPlayCtrl::SetStatus: "); | ||||
|     OutputDebugStringA(msg.ToUTF8().data()); | ||||
|     OutputDebugStringA("\n"); | ||||
| #endif // __WXMSW__
 | ||||
|     m_label_status->SetLabel(msg); | ||||
|     //m_label_status->SetForegroundColour(!msg.EndsWith("!") ? 0x42AE00 : 0x3B65E9);
 | ||||
|     Layout(); | ||||
|  | @ -147,11 +152,17 @@ void MediaPlayCtrl::media_proc() | |||
|         wxString url = m_tasks.front(); | ||||
|         lock.unlock(); | ||||
|         if (url.IsEmpty()) { | ||||
|             break; | ||||
|         } | ||||
|         else if (url == "<stop>") { | ||||
|             m_media_ctrl->Stop(); | ||||
|         } | ||||
|         else if (url == "<exit>") { | ||||
|             break; | ||||
|         } | ||||
|         else if (url == "<play>") { | ||||
|             m_media_ctrl->Play(); | ||||
|         } | ||||
|         else { | ||||
|             BOOST_LOG_TRIVIAL(info) <<  "MediaPlayCtrl: start load"; | ||||
|             m_media_ctrl->Load(wxURI(url)); | ||||
|  | @ -193,10 +204,11 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent& event) | |||
|         BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl::onStateChanged: size: " << size.x << "x" << size.y; | ||||
|         m_failed_code = m_media_ctrl->GetLastError(); | ||||
|         if (size.GetWidth() > 1000) { | ||||
|             m_media_ctrl->Play(); | ||||
|             SetStatus(_L("Playing...")); | ||||
|             m_failed_retry = 0; | ||||
|             m_last_state = m_media_ctrl->GetState(); | ||||
|             boost::unique_lock lock(m_mutex); | ||||
|             m_tasks.push_back("<play>"); | ||||
|             m_cond.notify_all(); | ||||
|         } | ||||
|         else if (event.GetId()) { | ||||
|             Stop(); | ||||
|  |  | |||
|  | @ -335,7 +335,7 @@ void MonitorPanel::on_size(wxSizeEvent &event) | |||
| 
 | ||||
|     // update wifi signal image
 | ||||
|     int wifi_signal_val = 0; | ||||
|     if (!obj->is_connected()) { | ||||
|     if (!obj->is_connected() || obj->is_connecting()) { | ||||
|         m_side_tools->set_current_printer_signal(WifiSignal::NONE); | ||||
|     } else { | ||||
|         if (!obj->wifi_signal.empty() && boost::ends_with(obj->wifi_signal, "dBm")) { | ||||
|  | @ -381,6 +381,7 @@ void MonitorPanel::update_all() | |||
|     } | ||||
| 
 | ||||
|     if (obj) { | ||||
|         wxGetApp().reset_to_active(); | ||||
|         if (obj->connection_type() != last_conn_type) { | ||||
|             last_conn_type = obj->connection_type(); | ||||
|         } | ||||
|  | @ -404,7 +405,10 @@ void MonitorPanel::update_all() | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (!obj->is_connected()) { | ||||
|     if (obj->is_connecting()) { | ||||
|         show_status(MONITOR_CONNECTING); | ||||
|         return; | ||||
|     } else if (!obj->is_connected()) { | ||||
|         int server_status = 0; | ||||
|         // only disconnected server in cloud mode
 | ||||
|         if (obj->connection_type() != "lan") { | ||||
|  | @ -413,7 +417,6 @@ void MonitorPanel::update_all() | |||
|             } | ||||
|         } | ||||
|         show_status((int) MONITOR_DISCONNECTED + server_status); | ||||
|         m_status_info_panel->show_unload_ctrl(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -457,15 +460,9 @@ bool MonitorPanel::Show(bool show) | |||
|                 obj->reset_update_time(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (m_agent) | ||||
|             m_agent->start_subscribe("monitor"); | ||||
|     } | ||||
|     else { | ||||
|     } else { | ||||
|         m_refresh_timer->Stop(); | ||||
|         m_status_info_panel->m_media_play_ctrl->SetMachineObject(nullptr); | ||||
|         if (m_agent) | ||||
|             m_agent->stop_subscribe("monitor"); | ||||
|     } | ||||
|     return wxPanel::Show(show); | ||||
| } | ||||
|  | @ -503,8 +500,15 @@ void MonitorPanel::show_status(int status) | |||
|         else | ||||
|             m_connection_info->SetLabel(_L("Failed to connect to the printer")); | ||||
|         m_connection_info->Show(); | ||||
|     }else if ((status & (int) MonitorStatus::MONITOR_NORMAL) != 0) { | ||||
|         m_connection_info->SetBackgroundColor(wxColour(255, 111, 0)); | ||||
|         m_connection_info->SetBorderColor(wxColour(255, 111, 0)); | ||||
|     } else if ((status & (int) MonitorStatus::MONITOR_NORMAL) != 0) { | ||||
|         m_connection_info->Hide(); | ||||
|     } else if ((status & (int) MonitorStatus::MONITOR_CONNECTING) != 0) { | ||||
|         m_connection_info->SetLabel(_L("Connecting...")); | ||||
|         m_connection_info->SetBackgroundColor(wxColour(0, 174, 66)); | ||||
|         m_connection_info->SetBorderColor(wxColour(0, 174, 66)); | ||||
|         m_connection_info->Show(); | ||||
|     } | ||||
| 
 | ||||
|     Freeze(); | ||||
|  | @ -515,11 +519,14 @@ void MonitorPanel::show_status(int status) | |||
|         m_status_info_panel->show_status(status); | ||||
|         m_tabpanel->Refresh(); | ||||
|         m_tabpanel->Layout(); | ||||
|     } else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0) || | ||||
|         ((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0) || | ||||
|         ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) | ||||
|     } else if (((status & (int)MonitorStatus::MONITOR_NORMAL) != 0) | ||||
|         || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0) | ||||
|         || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) | ||||
|         || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0) | ||||
|         ) { | ||||
|         if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0) || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)) { | ||||
|         if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0) | ||||
|             || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) | ||||
|             || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0)) { | ||||
|             m_side_tools->set_current_printer_signal(WifiSignal::NONE); | ||||
|             set_default(); | ||||
|         } | ||||
|  |  | |||
|  | @ -390,5 +390,4 @@ void DownloadDialog::SetExtendedMessage(const wxString &extendedMessage) | |||
|     Fit(); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| } | ||||
| }} // namespace Slic3r::GUI
 | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ | |||
| #include <wx/textctrl.h> | ||||
| #include <wx/statline.h> | ||||
| #include "Widgets/Button.hpp" | ||||
| #include "BBLStatusBar.hpp" | ||||
| #include "BBLStatusBarSend.hpp" | ||||
| 
 | ||||
| class wxBoxSizer; | ||||
| class wxCheckBox; | ||||
|  | @ -364,7 +366,6 @@ private: | |||
|     wxString msg; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 SoftFever
						SoftFever