mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Update the codes to 01.01.00.10 for the formal release
1. first formal version of macos 2. add the bambu networking plugin install logic 3. auto compute the wipe volume when filament change 4. add the logic of wiping into support 5. refine the GUI layout and icons, improve the gui apperance in lots of small places 6. serveral improve to support 7. support AMS auto-mapping 8. disable lots of unstable features: such as params table, media file download, HMS 9. fix serveral kinds of bugs 10. update the document of building 11. ...
This commit is contained in:
		
							parent
							
								
									e1528e4299
								
							
						
					
					
						commit
						e9e4d75877
					
				
					 267 changed files with 10326 additions and 32228 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 { | ||||
|  | @ -1659,10 +1677,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"), ""); | ||||
| 
 | ||||
|  | @ -1775,20 +1796,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
 | ||||
|  | @ -2221,7 +2242,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); | ||||
| } | ||||
| 
 | ||||
|  | @ -2260,42 +2281,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); | ||||
| } | ||||
| 
 | ||||
|  | @ -2474,6 +2463,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) | ||||
|  | @ -2525,7 +2520,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
	
	 lane.wei
						lane.wei