mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_sinking_objects_collision
This commit is contained in:
		
						commit
						fe4baa33f6
					
				
					 23 changed files with 6118 additions and 3657 deletions
				
			
		|  | @ -7,61 +7,67 @@ | |||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    version="1.0" | ||||
|    id="warning" | ||||
|    x="0px" | ||||
|    y="0px" | ||||
|    viewBox="0 0 200 200" | ||||
|    enable-background="new 0 0 100 100" | ||||
|    xml:space="preserve" | ||||
|    sodipodi:docname="notification_info.svg" | ||||
|    width="200" | ||||
|    inkscape:version="1.0 (4035a4fb49, 2020-05-01)" | ||||
|    height="200" | ||||
|    inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata | ||||
|    width="200" | ||||
|    sodipodi:docname="notification_info.svg" | ||||
|    xml:space="preserve" | ||||
|    enable-background="new 0 0 100 100" | ||||
|    viewBox="0 0 200 200" | ||||
|    y="0px" | ||||
|    x="0px" | ||||
|    id="warning" | ||||
|    version="1.0"><metadata | ||||
|    id="metadata19"><rdf:RDF><cc:Work | ||||
|        rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type | ||||
|          rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs | ||||
|    id="defs17" /><sodipodi:namedview | ||||
|    inkscape:document-rotation="0" | ||||
|    pagecolor="#ffffff" | ||||
|    bordercolor="#666666" | ||||
|    borderopacity="1" | ||||
|    objecttolerance="10" | ||||
|    gridtolerance="10" | ||||
|    guidetolerance="10" | ||||
|    inkscape:pageopacity="0" | ||||
|    inkscape:pageshadow="2" | ||||
|    inkscape:window-width="2560" | ||||
|    inkscape:window-height="1377" | ||||
|    id="namedview15" | ||||
|    showgrid="false" | ||||
|    inkscape:zoom="5.04" | ||||
|    inkscape:cx="108.69674" | ||||
|    inkscape:cy="117.65848" | ||||
|    inkscape:window-x="-8" | ||||
|    inkscape:window-y="-8" | ||||
|    inkscape:current-layer="warning" | ||||
|    inkscape:window-maximized="1" | ||||
|    inkscape:current-layer="warning" /> | ||||
|    inkscape:window-y="-11" | ||||
|    inkscape:window-x="-11" | ||||
|    inkscape:cy="117.65848" | ||||
|    inkscape:cx="108.69674" | ||||
|    inkscape:zoom="5.04" | ||||
|    showgrid="false" | ||||
|    id="namedview15" | ||||
|    inkscape:window-height="2066" | ||||
|    inkscape:window-width="3840" | ||||
|    inkscape:pageshadow="2" | ||||
|    inkscape:pageopacity="0" | ||||
|    guidetolerance="10" | ||||
|    gridtolerance="10" | ||||
|    objecttolerance="10" | ||||
|    borderopacity="1" | ||||
|    bordercolor="#666666" | ||||
|    pagecolor="#ffffff" | ||||
|    inkscape:document-rotation="0" /> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| <g | ||||
|    style="fill:#ed6b21;fill-opacity:1" | ||||
|    id="g8" | ||||
|    transform="matrix(2,0,0,2,0.17117674,0.68464711)" | ||||
|    id="g8"><path | ||||
|      style="fill:#ed6b21;fill-opacity:1" | ||||
|      class="st1" | ||||
|    style="fill:#ed6b21;fill-opacity:1"><path | ||||
|      id="path6" | ||||
|      d="m 40.1,43.5 c 4.5,-1.2 8.2,-1.7 11,-1.7 1.7,0 3,0.3 4,0.9 0.9,0.6 1.4,1.5 1.4,2.8 0,0.5 -0.1,1.1 -0.2,1.6 l -5,23.9 c -0.1,0.7 -0.2,1.1 -0.2,1.4 0,1 0.4,1.7 1.3,2 0.8,0.3 2.4,0.5 4.6,0.5 l -0.2,1.8 c -4.3,1.1 -7.8,1.6 -10.5,1.6 -1.9,0 -3.3,-0.4 -4.4,-1.1 -1,-0.7 -1.6,-1.8 -1.6,-3.3 0,-0.7 0.1,-1.6 0.3,-2.7 l 4.6,-22 c 0.2,-1 0.3,-1.7 0.3,-2 0,-0.7 -0.3,-1.2 -0.9,-1.4 C 44,45.5 42.4,45.4 39.7,45.4 Z M 59.2,28.4 c 0,1.7 -0.5,3.1 -1.6,4.2 -1.1,1.1 -2.4,1.6 -4,1.6 -1.5,0 -2.8,-0.5 -3.8,-1.5 -1,-1 -1.5,-2.3 -1.5,-3.9 0,-1.8 0.5,-3.2 1.6,-4.2 1.1,-1 2.4,-1.5 4,-1.5 1.5,0 2.8,0.5 3.8,1.4 1,0.9 1.5,2.2 1.5,3.9 z" | ||||
|      id="path6" /></g><path | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.198413" | ||||
|      class="st1" | ||||
|      style="fill:#ed6b21;fill-opacity:1" /></g><path | ||||
|    id="path853" | ||||
|    d="m 16.939336,52.048564 c 0.24576,-0.15442 19.08533,-11.001046 41.86572,-24.103596 L 100.22396,4.1221459 142.03917,28.183626 183.85441,52.245107 V 100.734 149.2229 l -41.81468,24.06212 -41.81467,24.06214 -41.816284,-24.06216 -41.81626,-24.06216 -0.05,-48.44676 -0.05,-48.446739 z M 63.764716,163.5414 c 19.88816,11.44426 36.295164,20.80774 36.460014,20.80774 0.16481,0 16.57129,-9.36332 36.45875,-20.80738 l 36.15903,-20.80738 V 100.73468 58.734992 L 136.68178,37.925746 C 116.79341,26.480662 100.38715,17.116638 100.22347,17.116804 100.05968,17.116972 83.653536,26.48106 63.765126,37.925887 l -36.16072,20.808776 v 41.999497 41.9995 z" | ||||
|    id="path853" /><path | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.198413" | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.198413" /><path | ||||
|    id="path855" | ||||
|    d="m 89.952923,157.02042 c -4.242772,-0.58044 -7.113036,-2.32486 -8.380448,-5.09326 -0.626294,-1.368 -0.807444,-3.89074 -0.464458,-6.46814 0.1277,-0.95968 2.419926,-12.20538 5.093816,-24.99044 2.67389,-12.78508 4.908156,-23.917618 4.965016,-24.738958 0.115,-1.6621 -0.189601,-2.54084 -1.114721,-3.21606 -0.792772,-0.57856 -2.966462,-0.9222 -6.787666,-1.07302 -3.481347,-0.1374 -3.555832,-0.1494 -3.458944,-0.5573 0.05446,-0.22926 0.206042,-0.97334 0.336845,-1.6535 0.1308,-0.68016 0.338118,-1.31832 0.4607,-1.41814 0.28243,-0.22998 6.4844,-1.66782 9.46857,-2.19514 5.863452,-1.0361 12.531417,-1.47854 15.428597,-1.02374 5.36116,0.84161 7.82828,3.38728 7.50956,7.74872 -0.0602,0.82388 -2.44364,12.614038 -5.2965,26.200338 -3.08108,14.67312 -5.23336,25.36606 -5.30112,26.33702 -0.24186,3.46504 0.94802,4.64856 5.32416,5.29562 1.15984,0.1716 3.06554,0.31182 4.23488,0.31182 h 2.1261 l -0.1262,1.04166 c -0.0694,0.57292 -0.174,1.37074 -0.23232,1.77292 l -0.1062,0.73126 -2.51448,0.59446 c -8.31236,1.96515 -17.063901,2.95498 -21.165277,2.39389 z" | ||||
|    id="path855" /><path | ||||
|    id="path859" | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.198413" /><path | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.280598" | ||||
|    d="m 103.80449,68.371429 c -4.85388,-1.747057 -7.401434,-6.318219 -6.705139,-12.031262 0.68816,-5.646301 5.025269,-9.262423 11.052899,-9.215502 4.20991,0.03277 7.4957,1.946636 9.16606,5.33893 0.89045,1.808402 0.93519,2.048665 0.92966,4.992684 -0.007,3.886952 -0.60744,5.58627 -2.81498,7.970671 -2.18267,2.35755 -4.19782,3.227419 -7.70164,3.324532 -1.90628,0.05284 -3.02496,-0.05544 -3.92686,-0.380053 z" | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.280598" /><path | ||||
|    id="path861" | ||||
|    id="path859" /><path | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.280598" | ||||
|    d="m 88.159837,156.51971 c -4.689261,-1.3224 -6.765722,-3.65088 -6.999725,-7.84929 -0.143463,-2.57397 -0.367006,-1.35766 5.236874,-28.49422 2.02374,-9.79989 3.976706,-19.42817 4.339925,-21.396181 1.189159,-6.443166 0.608576,-7.052275 -7.07692,-7.424629 -1.896078,-0.09186 -3.506416,-0.262489 -3.578529,-0.37917 -0.07211,-0.116682 0.01749,-0.855929 0.199113,-1.642772 0.380336,-1.647704 6.64e-4,-1.47536 6.265635,-2.844151 5.6684,-1.238451 9.941962,-1.750196 14.87169,-1.780835 6.11275,-0.03799 8.21381,0.630882 10.35608,3.296884 0.84162,1.047378 0.86697,1.161816 0.83925,3.788072 -0.0245,2.316986 -0.5437,5.179915 -3.59555,19.824542 -7.12659,34.19777 -7.24867,34.91174 -6.23405,36.46024 0.25629,0.39114 0.76211,0.90521 1.12406,1.14236 1.05449,0.69093 4.30303,1.25008 7.29332,1.25534 l 2.76816,0.005 -0.20111,1.61344 c -0.11061,0.88739 -0.33162,1.69456 -0.49112,1.79371 -0.42321,0.26308 -8.03018,1.8551 -11.29784,2.36446 -4.118692,0.64201 -11.953193,0.79357 -13.819263,0.26733 z" | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.280598" /></svg> | ||||
|    id="path861" /><path | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.204365" | ||||
|    d="M 14.442311,50.587986 C 14.695444,50.428934 34.100201,39.256909 57.564008,25.761283 L 100.22547,1.2237759 143.29514,26.0071 l 43.0697,24.783326 v 49.943554 49.94357 l -43.06912,24.78398 -43.06911,24.78401 -43.07077,-24.78403 -43.070753,-24.78402 -0.0515,-49.90017 -0.0515,-49.900133 z M 62.672458,165.4256 c 20.484805,11.78759 37.384012,21.43197 37.553812,21.43197 0.16975,0 17.06843,-9.64422 37.55251,-21.4316 l 37.2438,-21.4316 V 100.73468 57.475007 L 137.77703,36.041484 c -20.48502,-11.788437 -37.38347,-21.433381 -37.55206,-21.43321 -0.1687,1.73e-4 -17.067028,9.645183 -37.55209,21.433355 L 25.427333,57.474668 v 43.259482 43.25948 z" | ||||
|    id="path853-2" /><path | ||||
|    style="opacity:0.999;fill:#ed6b21;fill-opacity:1;stroke-width:0.18254" | ||||
|    d="M 23.59806,55.943454 C 23.824159,55.801388 41.156564,45.822492 62.114522,33.768146 l 38.105398,-21.916997 38.46998,22.136562 38.47002,22.136563 v 44.609776 44.60979 l -38.4695,22.13715 -38.46949,22.13717 -38.470985,-22.13719 -38.470959,-22.13718 -0.046,-44.57102 -0.046,-44.571001 z M 66.67741,158.51686 c 18.297107,10.52872 33.39156,19.14312 33.54322,19.14312 0.15162,0 15.24558,-8.61425 33.54204,-19.14279 L 167.02898,139.3744 V 100.73468 62.094968 L 133.7611,42.950461 C 115.4638,32.420984 100.37005,23.806082 100.21947,23.806235 100.06878,23.806389 84.975124,32.42135 66.677787,42.950591 L 33.409924,62.094665 v 38.639535 38.63954 z" | ||||
|    id="path853-0" /></svg> | ||||
|  |  | |||
| Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 7.1 KiB | 
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -7,21 +7,25 @@ src/slic3r/GUI/ButtonsDescription.cpp | |||
| src/slic3r/GUI/ConfigManipulation.cpp | ||||
| src/slic3r/GUI/ConfigSnapshotDialog.cpp | ||||
| src/slic3r/GUI/ConfigWizard.cpp | ||||
| src/slic3r/GUI/DesktopIntegrationDialog.cpp | ||||
| src/slic3r/GUI/DoubleSlider.cpp | ||||
| src/slic3r/GUI/ExtraRenderers.cpp | ||||
| src/slic3r/GUI/ExtruderSequenceDialog.cpp | ||||
| src/slic3r/GUI/Field.cpp | ||||
| src/slic3r/GUI/FirmwareDialog.cpp | ||||
| src/slic3r/GUI/GalleryDialog.cpp | ||||
| src/slic3r/GUI/GCodeViewer.cpp | ||||
| src/slic3r/GUI/GLCanvas3D.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | ||||
|  | @ -34,9 +38,12 @@ src/slic3r/GUI/GUI_ObjectList.cpp | |||
| src/slic3r/GUI/GUI_ObjectManipulation.cpp | ||||
| src/slic3r/GUI/GUI_ObjectSettings.cpp | ||||
| src/slic3r/GUI/GUI_Preview.cpp | ||||
| src/slic3r/GUI/HintNotification.cpp | ||||
| src/slic3r/GUI/ImGuiWrapper.cpp | ||||
| src/slic3r/GUI/Jobs/ArrangeJob.cpp | ||||
| src/slic3r/GUI/Jobs/FillBedJob.cpp | ||||
| src/slic3r/GUI/Jobs/Job.cpp | ||||
| src/slic3r/GUI/Jobs/PlaterJob.cpp | ||||
| src/slic3r/GUI/Jobs/RotoptimizeJob.cpp | ||||
| src/slic3r/GUI/Jobs/SLAImportJob.cpp | ||||
| src/slic3r/GUI/KBShortcutsDialog.cpp | ||||
|  | @ -59,6 +66,7 @@ src/slic3r/GUI/RammingChart.cpp | |||
| src/slic3r/GUI/SavePresetDialog.cpp | ||||
| src/slic3r/GUI/Search.cpp | ||||
| src/slic3r/GUI/Selection.cpp | ||||
| src/slic3r/GUI/SendSystemInfoDialog.cpp | ||||
| src/slic3r/GUI/SysInfoDialog.cpp | ||||
| src/slic3r/GUI/Tab.cpp | ||||
| src/slic3r/GUI/Tab.hpp | ||||
|  | @ -74,6 +82,7 @@ src/slic3r/Utils/OctoPrint.cpp | |||
| src/slic3r/Utils/PresetUpdater.cpp | ||||
| src/slic3r/Utils/Http.cpp | ||||
| src/slic3r/Utils/Process.cpp | ||||
| src/slic3r/Utils/Repetier.cpp | ||||
| src/libslic3r/GCode.cpp | ||||
| src/libslic3r/ExtrusionEntity.cpp | ||||
| src/libslic3r/Flow.cpp | ||||
|  |  | |||
|  | @ -134,6 +134,13 @@ static constexpr const char* SOURCE_OFFSET_Z_KEY = "source_offset_z"; | |||
| static constexpr const char* SOURCE_IN_INCHES    = "source_in_inches"; | ||||
| static constexpr const char* SOURCE_IN_METERS    = "source_in_meters"; | ||||
| 
 | ||||
| static constexpr const char* MESH_STAT_EDGES_FIXED          = "edges_fixed"; | ||||
| static constexpr const char* MESH_STAT_DEGENERATED_FACETS   = "degenerate_facets"; | ||||
| static constexpr const char* MESH_STAT_FACETS_REMOVED       = "facets_removed"; | ||||
| static constexpr const char* MESH_STAT_FACETS_RESERVED      = "facets_reversed"; | ||||
| static constexpr const char* MESH_STAT_BACKWARDS_EDGES      = "backwards_edges"; | ||||
| 
 | ||||
| 
 | ||||
| const unsigned int VALID_OBJECT_TYPES_COUNT = 1; | ||||
| const char* VALID_OBJECT_TYPES[] = | ||||
| { | ||||
|  | @ -383,6 +390,7 @@ namespace Slic3r { | |||
|                 unsigned int first_triangle_id; | ||||
|                 unsigned int last_triangle_id; | ||||
|                 MetadataList metadata; | ||||
|                 RepairedMeshErrors mesh_stats; | ||||
| 
 | ||||
|                 VolumeMetadata(unsigned int first_triangle_id, unsigned int last_triangle_id) | ||||
|                     : first_triangle_id(first_triangle_id) | ||||
|  | @ -531,7 +539,9 @@ namespace Slic3r { | |||
|         bool _handle_end_config_object(); | ||||
| 
 | ||||
|         bool _handle_start_config_volume(const char** attributes, unsigned int num_attributes); | ||||
|         bool _handle_start_config_volume_mesh(const char** attributes, unsigned int num_attributes); | ||||
|         bool _handle_end_config_volume(); | ||||
|         bool _handle_end_config_volume_mesh(); | ||||
| 
 | ||||
|         bool _handle_start_config_metadata(const char** attributes, unsigned int num_attributes); | ||||
|         bool _handle_end_config_metadata(); | ||||
|  | @ -1391,6 +1401,8 @@ namespace Slic3r { | |||
|             res = _handle_start_config_object(attributes, num_attributes); | ||||
|         else if (::strcmp(VOLUME_TAG, name) == 0) | ||||
|             res = _handle_start_config_volume(attributes, num_attributes); | ||||
|         else if (::strcmp(MESH_TAG, name) == 0) | ||||
|             res = _handle_start_config_volume_mesh(attributes, num_attributes); | ||||
|         else if (::strcmp(METADATA_TAG, name) == 0) | ||||
|             res = _handle_start_config_metadata(attributes, num_attributes); | ||||
| 
 | ||||
|  | @ -1411,6 +1423,8 @@ namespace Slic3r { | |||
|             res = _handle_end_config_object(); | ||||
|         else if (::strcmp(VOLUME_TAG, name) == 0) | ||||
|             res = _handle_end_config_volume(); | ||||
|         else if (::strcmp(MESH_TAG, name) == 0) | ||||
|             res = _handle_end_config_volume_mesh(); | ||||
|         else if (::strcmp(METADATA_TAG, name) == 0) | ||||
|             res = _handle_end_config_metadata(); | ||||
| 
 | ||||
|  | @ -1845,12 +1859,43 @@ namespace Slic3r { | |||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool _3MF_Importer::_handle_start_config_volume_mesh(const char** attributes, unsigned int num_attributes) | ||||
|     { | ||||
|         IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id); | ||||
|         if (object == m_objects_metadata.end()) { | ||||
|             add_error("Cannot assign volume mesh to a valid object"); | ||||
|             return false; | ||||
|         } | ||||
|         if (object->second.volumes.empty()) { | ||||
|             add_error("Cannot assign mesh to a valid olume"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back(); | ||||
| 
 | ||||
|         int edges_fixed         = get_attribute_value_int(attributes, num_attributes, MESH_STAT_EDGES_FIXED       ); | ||||
|         int degenerate_facets   = get_attribute_value_int(attributes, num_attributes, MESH_STAT_DEGENERATED_FACETS); | ||||
|         int facets_removed      = get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_REMOVED    ); | ||||
|         int facets_reversed     = get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_RESERVED   ); | ||||
|         int backwards_edges     = get_attribute_value_int(attributes, num_attributes, MESH_STAT_BACKWARDS_EDGES   ); | ||||
| 
 | ||||
|         volume.mesh_stats = { edges_fixed, degenerate_facets, facets_removed, facets_reversed, backwards_edges }; | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool _3MF_Importer::_handle_end_config_volume() | ||||
|     { | ||||
|         // do nothing
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool _3MF_Importer::_handle_end_config_volume_mesh() | ||||
|     { | ||||
|         // do nothing
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool _3MF_Importer::_handle_start_config_metadata(const char** attributes, unsigned int num_attributes) | ||||
|     { | ||||
|         IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id); | ||||
|  | @ -1947,7 +1992,7 @@ namespace Slic3r { | |||
|                 // Remove the vertices, that are not referenced by any face.
 | ||||
|                 its_compactify_vertices(its, true); | ||||
| 
 | ||||
|             TriangleMesh triangle_mesh(std::move(its)); | ||||
|             TriangleMesh triangle_mesh(std::move(its), volume_data.mesh_stats); | ||||
| 
 | ||||
|             if (m_version == 0) { | ||||
|                 // if the 3mf was not produced by PrusaSlicer and there is only one instance,
 | ||||
|  | @ -2970,6 +3015,15 @@ namespace Slic3r { | |||
|                             for (const std::string& key : volume->config.keys()) { | ||||
|                                 stream << "   <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n"; | ||||
|                             } | ||||
|                              | ||||
|                             // stores mesh's statistics
 | ||||
|                             const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors; | ||||
|                             stream << "   <" << MESH_TAG << " "; | ||||
|                             stream << MESH_STAT_EDGES_FIXED        << "=\"" << stats.edges_fixed        << "\" "; | ||||
|                             stream << MESH_STAT_DEGENERATED_FACETS << "=\"" << stats.degenerate_facets  << "\" "; | ||||
|                             stream << MESH_STAT_FACETS_REMOVED     << "=\"" << stats.facets_removed     << "\" "; | ||||
|                             stream << MESH_STAT_FACETS_RESERVED    << "=\"" << stats.facets_reversed    << "\" "; | ||||
|                             stream << MESH_STAT_BACKWARDS_EDGES    << "=\"" << stats.backwards_edges    << "\"/>\n"; | ||||
| 
 | ||||
|                             stream << "  </" << VOLUME_TAG << ">\n"; | ||||
|                         } | ||||
|  |  | |||
|  | @ -1638,16 +1638,17 @@ void ModelObject::print_info() const | |||
|         cout << "open_edges = " << mesh.stats().open_edges << endl; | ||||
|      | ||||
|     if (mesh.stats().repaired()) { | ||||
|         if (mesh.stats().degenerate_facets > 0) | ||||
|             cout << "degenerate_facets = "  << mesh.stats().degenerate_facets << endl; | ||||
|         if (mesh.stats().edges_fixed > 0) | ||||
|             cout << "edges_fixed = "        << mesh.stats().edges_fixed       << endl; | ||||
|         if (mesh.stats().facets_removed > 0) | ||||
|             cout << "facets_removed = "     << mesh.stats().facets_removed    << endl; | ||||
|         if (mesh.stats().facets_reversed > 0) | ||||
|             cout << "facets_reversed = "    << mesh.stats().facets_reversed   << endl; | ||||
|         if (mesh.stats().backwards_edges > 0) | ||||
|             cout << "backwards_edges = "    << mesh.stats().backwards_edges   << endl; | ||||
|         const RepairedMeshErrors& stats = mesh.stats().repaired_errors; | ||||
|         if (stats.degenerate_facets > 0) | ||||
|             cout << "degenerate_facets = "  << stats.degenerate_facets << endl; | ||||
|         if (stats.edges_fixed > 0) | ||||
|             cout << "edges_fixed = "        << stats.edges_fixed       << endl; | ||||
|         if (stats.facets_removed > 0) | ||||
|             cout << "facets_removed = "     << stats.facets_removed    << endl; | ||||
|         if (stats.facets_reversed > 0) | ||||
|             cout << "facets_reversed = "    << stats.facets_reversed   << endl; | ||||
|         if (stats.backwards_edges > 0) | ||||
|             cout << "backwards_edges = "    << stats.backwards_edges   << endl; | ||||
|     } | ||||
|     cout << "number_of_parts =  " << mesh.stats().number_of_parts << endl; | ||||
|     cout << "volume = "           << mesh.volume()                << endl; | ||||
|  | @ -1688,11 +1689,7 @@ TriangleMeshStats ModelObject::get_object_stl_stats() const | |||
| 
 | ||||
|         // initialize full_stats (for repaired errors)
 | ||||
|         full_stats.open_edges           += stats.open_edges; | ||||
|         full_stats.degenerate_facets    += stats.degenerate_facets; | ||||
|         full_stats.edges_fixed          += stats.edges_fixed; | ||||
|         full_stats.facets_removed       += stats.facets_removed; | ||||
|         full_stats.facets_reversed      += stats.facets_reversed; | ||||
|         full_stats.backwards_edges      += stats.backwards_edges; | ||||
|         full_stats.repaired_errors.merge(stats.repaired_errors); | ||||
| 
 | ||||
|         // another used satistics value
 | ||||
|         if (volume->is_model_part()) { | ||||
|  | @ -1709,7 +1706,7 @@ int ModelObject::get_mesh_errors_count(const int vol_idx /*= -1*/) const | |||
|     if (vol_idx >= 0) | ||||
|         return this->volumes[vol_idx]->get_mesh_errors_count(); | ||||
| 
 | ||||
|     const TriangleMeshStats& stats = get_object_stl_stats(); | ||||
|     const RepairedMeshErrors& stats = get_object_stl_stats().repaired_errors; | ||||
| 
 | ||||
|     return  stats.degenerate_facets + stats.edges_fixed     + stats.facets_removed + | ||||
|             stats.facets_reversed + stats.backwards_edges; | ||||
|  | @ -1781,7 +1778,7 @@ void ModelVolume::calculate_convex_hull() | |||
| 
 | ||||
| int ModelVolume::get_mesh_errors_count() const | ||||
| { | ||||
|     const TriangleMeshStats &stats = this->mesh().stats(); | ||||
|     const RepairedMeshErrors &stats = this->mesh().stats().repaired_errors; | ||||
| 
 | ||||
|     return  stats.degenerate_facets + stats.edges_fixed     + stats.facets_removed + | ||||
|             stats.facets_reversed + stats.backwards_edges; | ||||
|  |  | |||
|  | @ -105,4 +105,42 @@ PlatformFlavor platform_flavor() | |||
| 	return s_platform_flavor; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| std::string platform_to_string(Platform platform) | ||||
| { | ||||
|     switch (platform) { | ||||
|         case Platform::Uninitialized: return "Unitialized"; | ||||
|         case Platform::Unknown      : return "Unknown"; | ||||
|         case Platform::Windows      : return "Windows"; | ||||
|         case Platform::OSX          : return "OSX"; | ||||
|         case Platform::Linux        : return "Linux"; | ||||
|         case Platform::BSDUnix      : return "BSDUnix"; | ||||
|     } | ||||
|     assert(false); | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| std::string platform_flavor_to_string(PlatformFlavor pf) | ||||
| { | ||||
|     switch (pf) { | ||||
|         case PlatformFlavor::Uninitialized   : return "Unitialized"; | ||||
|         case PlatformFlavor::Unknown         : return "Unknown"; | ||||
|         case PlatformFlavor::Generic         : return "Generic"; | ||||
|         case PlatformFlavor::GenericLinux    : return "GenericLinux"; | ||||
|         case PlatformFlavor::LinuxOnChromium : return "LinuxOnChromium"; | ||||
|         case PlatformFlavor::WSL             : return "WSL"; | ||||
|         case PlatformFlavor::WSL2            : return "WSL2"; | ||||
|         case PlatformFlavor::OpenBSD         : return "OpenBSD"; | ||||
|         case PlatformFlavor::GenericOSX      : return "GenericOSX"; | ||||
|         case PlatformFlavor::OSXOnX86        : return "OSXOnX86"; | ||||
|         case PlatformFlavor::OSXOnArm        : return "OSXOnArm"; | ||||
|     } | ||||
|     assert(false); | ||||
|     return ""; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| #ifndef SLIC3R_Platform_HPP | ||||
| #define SLIC3R_Platform_HPP | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| enum class Platform | ||||
|  | @ -16,24 +18,16 @@ enum class Platform | |||
| enum class PlatformFlavor | ||||
| { | ||||
| 	Uninitialized, | ||||
| 	Unknown, | ||||
| 	// For Windows and OSX, until we need to be more specific.
 | ||||
| 	Generic, | ||||
| 	// For Platform::Linux
 | ||||
| 	GenericLinux, | ||||
| 	LinuxOnChromium, | ||||
| 	// Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel)
 | ||||
| 	WSL, | ||||
| 	// Microsoft's Windows on Linux, version 2 (virtual machine)
 | ||||
| 	WSL2, | ||||
| 	// For Platform::BSDUnix
 | ||||
| 	OpenBSD, | ||||
| 	// For Platform::OSX
 | ||||
| 	GenericOSX, | ||||
| 	// For Apple's on Intel X86 CPU
 | ||||
| 	OSXOnX86, | ||||
| 	// For Apple's on Arm CPU
 | ||||
| 	OSXOnArm, | ||||
|     Unknown, | ||||
|     Generic,         // For Windows and OSX, until we need to be more specific.
 | ||||
|     GenericLinux,    // For Platform::Linux
 | ||||
|     LinuxOnChromium, // For Platform::Linux
 | ||||
|     WSL,             // Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel)
 | ||||
|     WSL2,            // Microsoft's Windows on Linux, version 2 (virtual machine)
 | ||||
|     OpenBSD,         // For Platform::BSDUnix
 | ||||
|     GenericOSX,      // For Platform::OSX
 | ||||
|     OSXOnX86,        // For Apple's on Intel X86 CPU
 | ||||
|     OSXOnArm,        // For Apple's on Arm CPU
 | ||||
| }; | ||||
| 
 | ||||
| // To be called on program start-up.
 | ||||
|  | @ -42,6 +36,9 @@ void 			detect_platform(); | |||
| Platform 		platform(); | ||||
| PlatformFlavor 	platform_flavor(); | ||||
| 
 | ||||
| std::string platform_to_string(Platform platform); | ||||
| std::string platform_flavor_to_string(PlatformFlavor pf); | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| #endif // SLIC3R_Platform_HPP
 | ||||
|  |  | |||
|  | @ -66,8 +66,10 @@ TriangleMesh::TriangleMesh(const indexed_triangle_set &its) : its(its) | |||
|     fill_initial_stats(this->its, m_stats); | ||||
| } | ||||
| 
 | ||||
| TriangleMesh::TriangleMesh(indexed_triangle_set &&its) : its(std::move(its)) | ||||
| TriangleMesh::TriangleMesh(indexed_triangle_set &&its, const RepairedMeshErrors& errors/* = RepairedMeshErrors()*/) : its(std::move(its)) | ||||
| { | ||||
|     if (errors.repaired()) | ||||
|         m_stats.repaired_errors = errors; | ||||
|     fill_initial_stats(this->its, m_stats); | ||||
| } | ||||
| 
 | ||||
|  | @ -194,11 +196,12 @@ bool TriangleMesh::ReadSTLFile(const char* input_file, bool repair) | |||
|     auto facets_w_3_bad_edge = stl.stats.number_of_facets - stl.stats.connected_facets_1_edge; | ||||
|     m_stats.open_edges              = stl.stats.backwards_edges + facets_w_1_bad_edge + facets_w_2_bad_edge * 2 + facets_w_3_bad_edge * 3; | ||||
| 
 | ||||
|     m_stats.edges_fixed             = stl.stats.edges_fixed; | ||||
|     m_stats.degenerate_facets       = stl.stats.degenerate_facets; | ||||
|     m_stats.facets_removed          = stl.stats.facets_removed; | ||||
|     m_stats.facets_reversed         = stl.stats.facets_reversed; | ||||
|     m_stats.backwards_edges         = stl.stats.backwards_edges; | ||||
|     m_stats.repaired_errors = { stl.stats.edges_fixed, | ||||
|                                 stl.stats.degenerate_facets, | ||||
|                                 stl.stats.facets_removed, | ||||
|                                 stl.stats.facets_reversed, | ||||
|                                 stl.stats.backwards_edges }; | ||||
| 
 | ||||
|     m_stats.number_of_parts         = stl.stats.number_of_parts; | ||||
| 
 | ||||
|     stl_generate_shared_vertices(&stl, this->its); | ||||
|  |  | |||
|  | @ -16,19 +16,7 @@ namespace Slic3r { | |||
| class TriangleMesh; | ||||
| class TriangleMeshSlicer; | ||||
| 
 | ||||
| struct TriangleMeshStats { | ||||
|     // Mesh metrics.
 | ||||
|     uint32_t      number_of_facets          = 0; | ||||
|     stl_vertex    max                       = stl_vertex::Zero(); | ||||
|     stl_vertex    min                       = stl_vertex::Zero(); | ||||
|     stl_vertex    size                      = stl_vertex::Zero(); | ||||
|     float         volume                    = -1.f; | ||||
|     int           number_of_parts           = 0; | ||||
| 
 | ||||
|     // Mesh errors, remaining.
 | ||||
|     int           open_edges                = 0; | ||||
| 
 | ||||
|     // Mesh errors, fixed.
 | ||||
| struct RepairedMeshErrors { | ||||
|     // How many edges were united by merging their end points with some other end points in epsilon neighborhood?
 | ||||
|     int           edges_fixed               = 0; | ||||
|     // How many degenerate faces were removed?
 | ||||
|  | @ -43,6 +31,36 @@ struct TriangleMeshStats { | |||
|     // Edges shared by two triangles, oriented incorrectly.
 | ||||
|     int           backwards_edges           = 0; | ||||
| 
 | ||||
|     void clear() { *this = RepairedMeshErrors(); } | ||||
| 
 | ||||
|     RepairedMeshErrors merge(const RepairedMeshErrors& rhs) const { | ||||
|         RepairedMeshErrors out; | ||||
|         out.edges_fixed         = this->edges_fixed         + rhs.edges_fixed; | ||||
|         out.degenerate_facets   = this->degenerate_facets   + rhs.degenerate_facets; | ||||
|         out.facets_removed      = this->facets_removed      + rhs.facets_removed; | ||||
|         out.facets_reversed     = this->facets_reversed     + rhs.facets_reversed; | ||||
|         out.backwards_edges     = this->backwards_edges     + rhs.backwards_edges; | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     bool repaired() const { return degenerate_facets > 0 || edges_fixed > 0 || facets_removed > 0 || facets_reversed > 0 || backwards_edges > 0; } | ||||
| }; | ||||
| 
 | ||||
| struct TriangleMeshStats { | ||||
|     // Mesh metrics.
 | ||||
|     uint32_t      number_of_facets          = 0; | ||||
|     stl_vertex    max                       = stl_vertex::Zero(); | ||||
|     stl_vertex    min                       = stl_vertex::Zero(); | ||||
|     stl_vertex    size                      = stl_vertex::Zero(); | ||||
|     float         volume                    = -1.f; | ||||
|     int           number_of_parts           = 0; | ||||
| 
 | ||||
|     // Mesh errors, remaining.
 | ||||
|     int           open_edges                = 0; | ||||
| 
 | ||||
|     // Mesh errors, fixed.
 | ||||
|     RepairedMeshErrors repaired_errors; | ||||
| 
 | ||||
|     void clear() { *this = TriangleMeshStats(); } | ||||
| 
 | ||||
|     TriangleMeshStats merge(const TriangleMeshStats &rhs) const { | ||||
|  | @ -59,17 +77,13 @@ struct TriangleMeshStats { | |||
|         out.number_of_parts         = this->number_of_parts     + rhs.number_of_parts; | ||||
|         out.open_edges              = this->open_edges          + rhs.open_edges; | ||||
|         out.volume                  = this->volume              + rhs.volume; | ||||
|         out.edges_fixed             = this->edges_fixed         + rhs.edges_fixed; | ||||
|         out.degenerate_facets       = this->degenerate_facets   + rhs.degenerate_facets; | ||||
|         out.facets_removed          = this->facets_removed      + rhs.facets_removed; | ||||
|         out.facets_reversed         = this->facets_reversed     + rhs.facets_reversed; | ||||
|         out.backwards_edges         = this->backwards_edges     + rhs.backwards_edges; | ||||
|         out.repaired_errors.merge(rhs.repaired_errors); | ||||
|         return out; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     bool manifold() const { return open_edges == 0; } | ||||
|     bool repaired() const { return degenerate_facets > 0 || edges_fixed > 0 || facets_removed > 0 || facets_reversed > 0 || backwards_edges > 0; } | ||||
|     bool repaired() const { return repaired_errors.repaired(); } | ||||
| }; | ||||
| 
 | ||||
| class TriangleMesh | ||||
|  | @ -79,7 +93,7 @@ public: | |||
|     TriangleMesh(const std::vector<Vec3f> &vertices, const std::vector<Vec3i> &faces); | ||||
|     TriangleMesh(std::vector<Vec3f> &&vertices, const std::vector<Vec3i> &&faces); | ||||
|     explicit TriangleMesh(const indexed_triangle_set &M); | ||||
|     explicit TriangleMesh(indexed_triangle_set &&M); | ||||
|     explicit TriangleMesh(indexed_triangle_set &&M, const RepairedMeshErrors& repaired_errors = RepairedMeshErrors()); | ||||
|     void clear() { this->its.clear(); this->m_stats.clear(); } | ||||
|     bool ReadSTLFile(const char* input_file, bool repair = true); | ||||
|     bool write_ascii(const char* output_file); | ||||
|  |  | |||
|  | @ -141,6 +141,8 @@ set(SLIC3R_GUI_SOURCES | |||
|     GUI/RammingChart.hpp | ||||
|     GUI/RemovableDriveManager.cpp | ||||
|     GUI/RemovableDriveManager.hpp | ||||
|     GUI/SendSystemInfoDialog.cpp | ||||
|     GUI/SendSystemInfoDialog.hpp | ||||
|     GUI/BonjourDialog.cpp | ||||
|     GUI/BonjourDialog.hpp | ||||
|     GUI/ButtonsDescription.cpp | ||||
|  |  | |||
|  | @ -70,6 +70,7 @@ | |||
| #include "SavePresetDialog.hpp" | ||||
| #include "PrintHostDialogs.hpp" | ||||
| #include "DesktopIntegrationDialog.hpp" | ||||
| #include "SendSystemInfoDialog.hpp" | ||||
| 
 | ||||
| #include "BitmapCache.hpp" | ||||
| #include "Notebook.hpp" | ||||
|  | @ -681,6 +682,10 @@ void GUI_App::post_init() | |||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     // 'Send system info' dialog. Again, a CallAfter is needed on mac.
 | ||||
|     // Without it, GL extensions did not show.
 | ||||
|     CallAfter([] { show_send_system_info_dialog_if_needed(); }); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     // Sets window property to mainframe so other instances can indentify it.
 | ||||
|     OtherInstanceMessageHandler::init_windows_properties(mainframe, m_instance_hash_int); | ||||
|  |  | |||
|  | @ -405,16 +405,18 @@ std::pair<wxString, std::string> ObjectList::get_mesh_errors(const int obj_idx, | |||
|         auto_repaired_info = format_wxstr(_L_PLURAL("Auto-repaired %1$d error", "Auto-repaired %1$d errors", errors), errors); | ||||
|         tooltip += auto_repaired_info +":\n"; | ||||
| 
 | ||||
|         if (stats.degenerate_facets > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d degenerate facet", "%1$d degenerate facets", stats.degenerate_facets), stats.degenerate_facets) + "\n"; | ||||
|         if (stats.edges_fixed > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", stats.edges_fixed), stats.edges_fixed) + "\n"; | ||||
|         if (stats.facets_removed > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", stats.facets_removed), stats.facets_removed) + "\n"; | ||||
|         if (stats.facets_reversed > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", stats.facets_reversed), stats.facets_reversed) + "\n"; | ||||
|         if (stats.backwards_edges > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d backwards edge", "%1$d backwards edges", stats.backwards_edges), stats.backwards_edges) + "\n"; | ||||
|         const RepairedMeshErrors& repaired = stats.repaired_errors; | ||||
| 
 | ||||
|         if (repaired.degenerate_facets > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d degenerate facet", "%1$d degenerate facets", repaired.degenerate_facets), repaired.degenerate_facets) + "\n"; | ||||
|         if (repaired.edges_fixed > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d edge fixed", "%1$d edges fixed", repaired.edges_fixed), repaired.edges_fixed) + "\n"; | ||||
|         if (repaired.facets_removed > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet removed", "%1$d facets removed", repaired.facets_removed), repaired.facets_removed) + "\n"; | ||||
|         if (repaired.facets_reversed > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d facet reversed", "%1$d facets reversed", repaired.facets_reversed), repaired.facets_reversed) + "\n"; | ||||
|         if (repaired.backwards_edges > 0) | ||||
|             tooltip += "\t" + format_wxstr(_L_PLURAL("%1$d backwards edge", "%1$d backwards edges", repaired.backwards_edges), repaired.backwards_edges) + "\n"; | ||||
|     } | ||||
|     if (!stats.manifold()) { | ||||
|         remaining_info = format_wxstr(_L_PLURAL("Remaining %1$d open edge", "Remaining %1$d open edges", stats.open_edges), stats.open_edges); | ||||
|  | @ -904,7 +906,7 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me | |||
| 	            int obj_idx, vol_idx; | ||||
| 	            get_selected_item_indexes(obj_idx, vol_idx, item); | ||||
| 
 | ||||
| 	            if (get_mesh_errors_count(obj_idx, vol_idx) > 0 &&  | ||||
| 	            if (m_objects_model->HasWarningIcon(item) && | ||||
| 	                mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit()) | ||||
| 	                fix_through_netfabb(); | ||||
| 	        } | ||||
|  | @ -4138,7 +4140,7 @@ void ObjectList::fix_through_netfabb() | |||
|     // Close the progress dialog
 | ||||
|     progress_dlg.Update(100, ""); | ||||
| 
 | ||||
|     // Show info message
 | ||||
|     // Show info notification
 | ||||
|     wxString msg; | ||||
|     wxString bullet_suf = "\n   - "; | ||||
|     if (!succes_models.empty()) { | ||||
|  | @ -4154,9 +4156,7 @@ void ObjectList::fix_through_netfabb() | |||
|     } | ||||
|     if (msg.IsEmpty()) | ||||
|         msg = _L("Repairing was canceled"); | ||||
|     // !!! Use wxMessageDialog instead of MessageDialog here
 | ||||
|     // It will not be "dark moded" but the Application will not lose a focus after model repairing
 | ||||
|     wxMessageDialog(nullptr, msg, _L("Model Repair by the Netfabb service"), wxICON_INFORMATION | wxOK).ShowModal(); | ||||
|     plater->get_notification_manager()->push_notification(NotificationType::NetfabbFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, boost::nowide::narrow(msg)); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::simplify() | ||||
|  |  | |||
|  | @ -433,8 +433,8 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) | |||
| 					}; | ||||
| 					m_loaded_hints.emplace_back(hint_data); | ||||
| 				} else if (dict["hypertext_type"] == "menubar") { | ||||
| 					wxString menu(_L("&" + dict["hypertext_menubar_menu_name"])); | ||||
| 					wxString item(_L(dict["hypertext_menubar_item_name"])); | ||||
| 					wxString menu(_("&" + dict["hypertext_menubar_menu_name"])); | ||||
| 					wxString item(_(dict["hypertext_menubar_item_name"])); | ||||
| 					HintData	hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [menu, item]() { wxGetApp().mainframe->open_menubar_item(menu, item); } }; | ||||
| 					m_loaded_hints.emplace_back(hint_data); | ||||
| 				} | ||||
|  |  | |||
|  | @ -278,7 +278,8 @@ void NotificationManager::PopNotification::count_spaces() | |||
| 	m_left_indentation = m_line_height; | ||||
| 	if (m_data.level == NotificationLevel::ErrorNotificationLevel  | ||||
| 		|| m_data.level == NotificationLevel::WarningNotificationLevel | ||||
| 		|| m_data.level == NotificationLevel::PrintInfoNotificationLevel) { | ||||
| 		|| m_data.level == NotificationLevel::PrintInfoNotificationLevel | ||||
| 		|| m_data.level == NotificationLevel::PrintInfoShortNotificationLevel) { | ||||
| 		std::string text; | ||||
| 		text = (m_data.level == NotificationLevel::ErrorNotificationLevel ? ImGui::ErrorMarker : ImGui::WarningMarker); | ||||
| 		float picture_width = ImGui::CalcTextSize(text.c_str()).x; | ||||
|  | @ -513,7 +514,7 @@ void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui) | |||
| 		ImGui::SetCursorPosX(m_line_height / 3); | ||||
| 		ImGui::SetCursorPosY(m_window_height / 2 - m_line_height); | ||||
| 		imgui.text(text.c_str()); | ||||
| 	} else if (m_data.level == NotificationLevel::PrintInfoNotificationLevel) { | ||||
| 	} else if (m_data.level == NotificationLevel::PrintInfoNotificationLevel || m_data.level == NotificationLevel::PrintInfoShortNotificationLevel) { | ||||
| 		std::wstring text; | ||||
| 		text = ImGui::InfoMarker; | ||||
| 		ImGui::SetCursorPosX(m_line_height / 3); | ||||
|  |  | |||
|  | @ -105,7 +105,9 @@ enum class NotificationType | |||
| 	ProgressIndicator, | ||||
| 	// Give user advice to simplify object with big amount of triangles
 | ||||
| 	// Contains ObjectID for closing when object is deleted
 | ||||
| 	SimplifySuggestion | ||||
| 	SimplifySuggestion, | ||||
| 	//  information about netfabb is finished repairing model (blocking proccess)
 | ||||
| 	NetfabbFinished | ||||
| }; | ||||
| 
 | ||||
| class NotificationManager | ||||
|  | @ -123,6 +125,8 @@ public: | |||
| 		RegularNotificationLevel, | ||||
| 		// Regular level notifiaction containing info about objects or print. Has Icon.
 | ||||
| 		PrintInfoNotificationLevel, | ||||
| 		// PrintInfoNotificationLevel with shorter time
 | ||||
| 		PrintInfoShortNotificationLevel, | ||||
| 		// Information notification without a fade-out or with a longer fade-out.
 | ||||
| 		ImportantNotificationLevel, | ||||
| 		// Warning, no fade-out.
 | ||||
|  | @ -706,13 +710,14 @@ private: | |||
| 	{ | ||||
| 		switch (level) { | ||||
| 		 | ||||
| 		case NotificationLevel::ErrorNotificationLevel: 	    return 0; | ||||
| 		case NotificationLevel::WarningNotificationLevel:	    return 0; | ||||
| 		case NotificationLevel::ImportantNotificationLevel:     return 0; | ||||
| 		case NotificationLevel::ProgressBarNotificationLevel:	return 2; | ||||
| 		case NotificationLevel::RegularNotificationLevel: 	    return 10; | ||||
| 		case NotificationLevel::PrintInfoNotificationLevel:     return 10; | ||||
| 		case NotificationLevel::HintNotificationLevel:			return 300; | ||||
| 		case NotificationLevel::ErrorNotificationLevel: 			return 0; | ||||
| 		case NotificationLevel::WarningNotificationLevel:			return 0; | ||||
| 		case NotificationLevel::ImportantNotificationLevel:			return 0; | ||||
| 		case NotificationLevel::ProgressBarNotificationLevel:		return 2; | ||||
| 		case NotificationLevel::PrintInfoShortNotificationLevel:	return 5; | ||||
| 		case NotificationLevel::RegularNotificationLevel: 			return 10; | ||||
| 		case NotificationLevel::PrintInfoNotificationLevel:			return 10; | ||||
| 		case NotificationLevel::HintNotificationLevel:				return 300; | ||||
| 		default: return 10; | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -1777,6 +1777,15 @@ void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bo | |||
|     } | ||||
| } | ||||
| 
 | ||||
| bool ObjectDataViewModel::HasWarningIcon(const wxDataViewItem& item) const | ||||
| { | ||||
|     if (!item.IsOk()) | ||||
|         return false; | ||||
| 
 | ||||
|     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID()); | ||||
|     return node->has_warning_icon(); | ||||
| } | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -240,6 +240,7 @@ public: | |||
|     bool 		valid(); | ||||
| #endif /* NDEBUG */ | ||||
|     bool        invalid() const { return m_idx < -1; } | ||||
|     bool        has_warning_icon() const { return !m_warning_icon_name.empty(); } | ||||
| 
 | ||||
| private: | ||||
|     friend class ObjectDataViewModel; | ||||
|  | @ -388,6 +389,7 @@ public: | |||
|                               const std::string& warning_icon_name = std::string()); | ||||
|     void        AddWarningIcon(const wxDataViewItem& item, const std::string& warning_name); | ||||
|     void        DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); | ||||
|     bool        HasWarningIcon(const wxDataViewItem& item) const; | ||||
|     t_layer_height_range    GetLayerRangeByItem(const wxDataViewItem& item) const; | ||||
| 
 | ||||
|     bool        UpdateColumValues(unsigned col); | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ namespace Slic3r { | |||
| namespace GUI { | ||||
| 
 | ||||
| // A safe wrapper around glGetString to report a "N/A" string in case glGetString returns nullptr.
 | ||||
| inline std::string gl_get_string_safe(GLenum param, const std::string& default_value) | ||||
| std::string gl_get_string_safe(GLenum param, const std::string& default_value) | ||||
| { | ||||
|     const char* value = (const char*)::glGetString(param); | ||||
|     return std::string((value != nullptr) ? value : default_value); | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ class wxGLContext; | |||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| class OpenGLManager | ||||
| { | ||||
| public: | ||||
|  |  | |||
|  | @ -27,7 +27,11 @@ | |||
| #include <wx/numdlg.h> | ||||
| #include <wx/debug.h> | ||||
| #include <wx/busyinfo.h> | ||||
| #ifdef _WIN32 | ||||
| #include <wx/richtooltip.h> | ||||
| #include <wx/custombgwin.h> | ||||
| #include <wx/popupwin.h> | ||||
| #endif | ||||
| 
 | ||||
| #include "libslic3r/libslic3r.h" | ||||
| #include "libslic3r/Format/STL.hpp" | ||||
|  | @ -609,7 +613,6 @@ struct Sidebar::priv | |||
| 
 | ||||
|     wxButton *btn_export_gcode; | ||||
|     wxButton *btn_reslice; | ||||
|     wxString btn_reslice_tip; | ||||
|     ScalableButton *btn_send_gcode; | ||||
|     //ScalableButton *btn_eject_device;
 | ||||
| 	ScalableButton* btn_export_gcode_removable; //exports to removable drives (appears only if removable drive is connected)
 | ||||
|  | @ -621,7 +624,12 @@ struct Sidebar::priv | |||
|     ~priv(); | ||||
| 
 | ||||
|     void show_preset_comboboxes(); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     wxString btn_reslice_tip; | ||||
|     void show_rich_tip(const wxString& tooltip, wxButton* btn); | ||||
|     void hide_rich_tip(wxButton* btn); | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| Sidebar::priv::~priv() | ||||
|  | @ -650,6 +658,7 @@ void Sidebar::priv::show_preset_comboboxes() | |||
|     scrolled->Refresh(); | ||||
| } | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| void Sidebar::priv::show_rich_tip(const wxString& tooltip, wxButton* btn) | ||||
| {    | ||||
|     if (tooltip.IsEmpty()) | ||||
|  | @ -659,10 +668,20 @@ void Sidebar::priv::show_rich_tip(const wxString& tooltip, wxButton* btn) | |||
|     tip.SetTipKind(wxTipKind_BottomRight); | ||||
|     tip.SetTitleFont(wxGetApp().normal_font()); | ||||
|     tip.SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
|     tip.SetTimeout(1200); | ||||
|     tip.ShowFor(btn); | ||||
| } | ||||
| 
 | ||||
| void Sidebar::priv::hide_rich_tip(wxButton* btn) | ||||
| { | ||||
|     auto children = btn->GetChildren(); | ||||
|     using wxRichToolTipPopup = wxCustomBackgroundWindow<wxPopupTransientWindow>; | ||||
|     for (auto child : children) { | ||||
|         if (wxRichToolTipPopup* popup = dynamic_cast<wxRichToolTipPopup*>(child)) | ||||
|             popup->Dismiss(); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // Sidebar / public
 | ||||
| 
 | ||||
| Sidebar::Sidebar(Plater *parent) | ||||
|  | @ -797,10 +816,18 @@ Sidebar::Sidebar(Plater *parent) | |||
|         ScalableBitmap bmp = ScalableBitmap(this, icon_name, bmp_px_cnt); | ||||
|         *btn = new ScalableButton(this, wxID_ANY, bmp, "", wxBU_EXACTFIT); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|         (*btn)->Bind(wxEVT_ENTER_WINDOW, [tooltip, btn, this](wxMouseEvent& event) { | ||||
|             p->show_rich_tip(tooltip, *btn); | ||||
|             event.Skip(); | ||||
|         }); | ||||
|         (*btn)->Bind(wxEVT_LEAVE_WINDOW, [btn, this](wxMouseEvent& event) { | ||||
|             p->hide_rich_tip(*btn); | ||||
|             event.Skip(); | ||||
|         }); | ||||
| #else | ||||
|         (*btn)->SetToolTip(tooltip); | ||||
| #endif // _WIN32
 | ||||
|         (*btn)->Hide(); | ||||
|     }; | ||||
| 
 | ||||
|  | @ -860,10 +887,17 @@ Sidebar::Sidebar(Plater *parent) | |||
|         p->plater->select_view_3D("Preview"); | ||||
|     }); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     p->btn_reslice->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& event) { | ||||
|         p->show_rich_tip(p->btn_reslice_tip, p->btn_reslice); | ||||
|         event.Skip(); | ||||
|     }); | ||||
|     p->btn_reslice->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) { | ||||
|         p->hide_rich_tip(p->btn_reslice); | ||||
|         event.Skip(); | ||||
|     }); | ||||
| #endif // _WIN32
 | ||||
| 
 | ||||
|     p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); | ||||
| //    p->btn_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
 | ||||
| 	p->btn_export_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(true); }); | ||||
|  | @ -991,7 +1025,11 @@ void Sidebar::update_reslice_btn_tooltip() const | |||
|     wxString tooltip = wxString("Slice") + " [" + GUI::shortkey_ctrl_prefix() + "R]"; | ||||
|     if (m_mode != comSimple) | ||||
|         tooltip += wxString("\n") + _L("Hold Shift to Slice & Export G-code"); | ||||
| #ifdef _WIN32 | ||||
|     p->btn_reslice_tip = tooltip; | ||||
| #else | ||||
|     p->btn_reslice->SetToolTip(tooltip); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void Sidebar::msw_rescale() | ||||
|  | @ -3097,15 +3135,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool | |||
|     } | ||||
| 
 | ||||
| 	//actualizate warnings
 | ||||
| 	if (invalidated != Print::APPLY_STATUS_UNCHANGED) { | ||||
| 	if (invalidated != Print::APPLY_STATUS_UNCHANGED || background_process.empty()) { | ||||
|         if (background_process.empty()) | ||||
|             process_validation_warning(std::string()); | ||||
| 		actualize_slicing_warnings(*this->background_process.current_print()); | ||||
|         actualize_object_warnings(*this->background_process.current_print()); | ||||
| 		show_warning_dialog = false; | ||||
| 		process_completed_with_error = false; | ||||
|          | ||||
| 	} | ||||
| 		process_completed_with_error = false;   | ||||
| 	}  | ||||
| 
 | ||||
|     if (invalidated != Print::APPLY_STATUS_UNCHANGED && was_running && ! this->background_process.running() && | ||||
|         (return_state & UPDATE_BACKGROUND_PROCESS_RESTART) == 0) { | ||||
|  |  | |||
							
								
								
									
										647
									
								
								src/slic3r/GUI/SendSystemInfoDialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										647
									
								
								src/slic3r/GUI/SendSystemInfoDialog.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,647 @@ | |||
| #include "SendSystemInfoDialog.hpp" | ||||
| 
 | ||||
| #include "libslic3r/AppConfig.hpp" | ||||
| #include "libslic3r/Platform.hpp" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/format.hpp" | ||||
| #include "slic3r/Utils/Http.hpp" | ||||
| 
 | ||||
| #include "GUI_App.hpp" | ||||
| #include "GUI_Utils.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "MainFrame.hpp" | ||||
| #include "MsgDialog.hpp" | ||||
| #include "OpenGLManager.hpp" | ||||
| 
 | ||||
| #include <boost/algorithm/hex.hpp> | ||||
| #include <boost/algorithm/string/split.hpp> | ||||
| #include <boost/algorithm/string/trim_all.hpp> | ||||
| #include <boost/property_tree/json_parser.hpp> | ||||
| #include <boost/uuid/detail/md5.hpp> | ||||
| 
 | ||||
| #include "GL/glew.h" | ||||
| 
 | ||||
| #include <wx/display.h> | ||||
| #include <wx/htmllbox.h> | ||||
| #include <wx/stattext.h> | ||||
| #include <wx/timer.h> | ||||
| #include <wx/utils.h> | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <thread> | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     #include <windows.h> | ||||
|     #include <Iphlpapi.h> | ||||
|     #pragma comment(lib, "iphlpapi.lib") | ||||
| #elif __APPLE__ | ||||
| #import <IOKit/IOKitLib.h> | ||||
| #endif | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Declaration of a free function defined in OpenGLManager.cpp:
 | ||||
| std::string gl_get_string_safe(GLenum param, const std::string& default_value); | ||||
| 
 | ||||
| 
 | ||||
| // A dialog with the information text and buttons send/dont send/ask later.
 | ||||
| class SendSystemInfoDialog : public DPIDialog | ||||
| { | ||||
|     enum { | ||||
|         MIN_WIDTH = 80, | ||||
|         MIN_HEIGHT = 50 | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     SendSystemInfoDialog(wxWindow* parent); | ||||
| 
 | ||||
| private: | ||||
|     bool send_info(); | ||||
|     const std::string m_system_info_json; | ||||
|     wxButton* m_btn_send; | ||||
|     wxButton* m_btn_dont_send; | ||||
|     wxButton* m_btn_ask_later; | ||||
| 
 | ||||
|     void on_dpi_changed(const wxRect&) override; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // A dialog to show when the upload is in progress (with a Cancel button).
 | ||||
| class SendSystemInfoProgressDialog : public wxDialog | ||||
| { | ||||
| public: | ||||
|     SendSystemInfoProgressDialog(wxWindow* parent, const wxString& message) | ||||
|         : wxDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION) | ||||
|     { | ||||
|         auto* text = new wxStaticText(this, wxID_ANY, message, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); | ||||
|         auto* btn = new wxButton(this, wxID_CANCEL, _L("Cancel")); | ||||
|         auto* vsizer = new wxBoxSizer(wxVERTICAL); | ||||
|         auto *top_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|         vsizer->Add(text, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL); | ||||
|         vsizer->AddSpacer(5); | ||||
|         vsizer->Add(btn, 0, wxALIGN_CENTER_HORIZONTAL); | ||||
|         top_sizer->Add(vsizer, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 10); | ||||
|         SetSizer(top_sizer); | ||||
|         #ifdef _WIN32 | ||||
|             wxGetApp().UpdateDlgDarkUI(this); | ||||
|         #endif | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // A dialog with multiline read-only text control to show the JSON.
 | ||||
| class ShowJsonDialog : public wxDialog | ||||
| { | ||||
| public: | ||||
|     ShowJsonDialog(wxWindow* parent, const wxString& json, const wxSize& size) | ||||
|         : wxDialog(parent, wxID_ANY, _L("Data to send"), wxDefaultPosition, size, wxCAPTION|wxRESIZE_BORDER) | ||||
|     { | ||||
|         auto* text = new wxTextCtrl(this, wxID_ANY, json, | ||||
|                                     wxDefaultPosition, wxDefaultSize, | ||||
|                                     wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); | ||||
|         text->SetFont(wxGetApp().code_font()); | ||||
|         text->ShowPosition(0); | ||||
| 
 | ||||
|         auto* btn = new wxButton(this, wxID_CANCEL, _L("Close")); | ||||
|         auto* vsizer = new wxBoxSizer(wxVERTICAL); | ||||
|         auto *top_sizer = new wxBoxSizer(wxVERTICAL); | ||||
|         vsizer->Add(text, 1, wxEXPAND); | ||||
|         vsizer->AddSpacer(5); | ||||
|         vsizer->Add(btn, 0, wxALIGN_CENTER_HORIZONTAL); | ||||
|         top_sizer->Add(vsizer, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT | wxBOTTOM, 10); | ||||
|         SetSizer(top_sizer); | ||||
|         #ifdef _WIN32 | ||||
|             wxGetApp().UpdateDlgDarkUI(this); | ||||
|         #endif | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Last version where the info was sent / dialog dismissed is saved in appconfig.
 | ||||
| // Only show the dialog when this info is not found (e.g. fresh install) or when
 | ||||
| // current version is newer. Only major and minor versions are compared.
 | ||||
| static bool should_dialog_be_shown() | ||||
| { | ||||
|     return false; | ||||
| 
 | ||||
|     std::string last_sent_version = wxGetApp().app_config->get("version_system_info_sent"); | ||||
|     Semver semver_current(SLIC3R_VERSION); | ||||
|     Semver semver_last_sent; | ||||
|     if (! last_sent_version.empty()) | ||||
|         semver_last_sent = Semver(last_sent_version); | ||||
| 
 | ||||
|     if (semver_current.prerelease() && std::string(semver_current.prerelease()) == "alpha") | ||||
|         return false; // Don't show in alphas.
 | ||||
| 
 | ||||
|     // Show the dialog if current > last, but they differ in more than just patch.
 | ||||
|     return ((semver_current.maj() > semver_last_sent.maj()) | ||||
|         || (semver_current.maj() == semver_last_sent.maj() && semver_current.min() > semver_last_sent.min() )); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // Following function saves current PrusaSlicer version into app config.
 | ||||
| // It will be later used to decide whether to open the dialog or not.
 | ||||
| static void save_version() | ||||
| { | ||||
|     wxGetApp().app_config->set("version_system_info_sent", std::string(SLIC3R_VERSION)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| static std::map<std::string, std::string> get_cpu_info_from_registry() | ||||
| { | ||||
|     std::map<std::string, std::string> out; | ||||
| 
 | ||||
|     int idx = -1; | ||||
|     constexpr DWORD bufsize_ = 200; | ||||
|     DWORD bufsize = bufsize_; | ||||
|     char buf[bufsize_] = ""; | ||||
|     const std::string reg_dir = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\"; | ||||
|     std::string reg_path = reg_dir; | ||||
| 
 | ||||
|     // Look into that reg dir and possibly into subdirs called 0, 1, 2, etc.
 | ||||
|     // If the latter, count them.
 | ||||
| 
 | ||||
|     while (true) { | ||||
|         if (RegGetValueA(HKEY_LOCAL_MACHINE, reg_path.c_str(), "ProcessorNameString", | ||||
|             RRF_RT_REG_SZ, NULL, &buf, &bufsize) == ERROR_SUCCESS) { | ||||
|             out["Model"] = buf; | ||||
|             out["Cores"] = std::to_string(std::max(1, idx + 1)); | ||||
|             if (RegGetValueA(HKEY_LOCAL_MACHINE, reg_path.c_str(), | ||||
|                 "VendorIdentifier", RRF_RT_REG_SZ, NULL, &buf, &bufsize) == ERROR_SUCCESS) | ||||
|                 out["Vendor"] = buf; | ||||
|         } | ||||
|         else { | ||||
|             if (idx >= 0) | ||||
|                 break; | ||||
|         } | ||||
|         ++idx; | ||||
|         reg_path = reg_dir + std::to_string(idx) + "\\"; | ||||
|         bufsize = bufsize_; | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
| #else // Apple, Linux, BSD
 | ||||
| static std::map<std::string, std::string> parse_lscpu_etc(const std::string& name, char delimiter) | ||||
| { | ||||
|     std::map<std::string, std::string> out; | ||||
|     constexpr size_t max_len = 100; | ||||
|     char cline[max_len] = ""; | ||||
|     FILE* fp = popen(name.data(), "r"); | ||||
|     if (fp != NULL) { | ||||
|         while (fgets(cline, max_len, fp) != NULL) { | ||||
|             std::string line(cline); | ||||
|             line.erase(std::remove_if(line.begin(), line.end(), | ||||
|                 [](char c) { return c == '\"' || c == '\r' || c == '\n'; }), | ||||
|                 line.end()); | ||||
|             size_t pos = line.find(delimiter); | ||||
|             if (pos < line.size() - 1) { | ||||
|                 std::string key = line.substr(0, pos); | ||||
|                 std::string value = line.substr(pos + 1); | ||||
|                 boost::trim_all(key); // remove leading and trailing spaces
 | ||||
|                 boost::trim_all(value); | ||||
|                 out[key] = value; | ||||
|             } | ||||
|         } | ||||
|         pclose(fp); | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static std::string get_unique_id() | ||||
| { | ||||
|     std::vector<unsigned char> unique; | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     // On Windows, get the MAC address of a network adaptor (preferably Ethernet
 | ||||
|     // or IEEE 802.11 wireless
 | ||||
| 
 | ||||
|     DWORD dwBufLen = sizeof(IP_ADAPTER_INFO); | ||||
|     PIP_ADAPTER_INFO AdapterInfo = (PIP_ADAPTER_INFO)malloc(dwBufLen); | ||||
| 
 | ||||
|     if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_BUFFER_OVERFLOW) { | ||||
|         free(AdapterInfo); | ||||
|         AdapterInfo = (IP_ADAPTER_INFO*)malloc(dwBufLen); | ||||
|     }     | ||||
|     if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == NO_ERROR) { | ||||
|         const IP_ADAPTER_INFO* pAdapterInfo = AdapterInfo; | ||||
|         std::vector<std::vector<unsigned char>> macs; | ||||
|         bool ethernet_seen = false; | ||||
|         while (pAdapterInfo) { | ||||
|             macs.emplace_back(); | ||||
|             for (unsigned char i = 0; i < pAdapterInfo->AddressLength; ++i) | ||||
|                 macs.back().emplace_back(pAdapterInfo->Address[i]); | ||||
|             // Prefer Ethernet and IEEE 802.11 wireless
 | ||||
|             if (! ethernet_seen) { | ||||
|                 if ((pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET && (ethernet_seen = true)) | ||||
|                  ||  pAdapterInfo->Type == IF_TYPE_IEEE80211) | ||||
|                     std::swap(macs.front(), macs.back()); | ||||
|             } | ||||
|             pAdapterInfo = pAdapterInfo->Next; | ||||
|         } | ||||
|         if (! macs.empty()) | ||||
|             unique = macs.front(); | ||||
|     } | ||||
|     free(AdapterInfo); | ||||
| #elif __APPLE__ | ||||
|     constexpr int buf_size = 100; | ||||
|     char buf[buf_size] = ""; | ||||
|     memset(&buf, 0, sizeof(buf)); | ||||
|     io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); | ||||
|     CFStringRef uuidCf = (CFStringRef)IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); | ||||
|     IOObjectRelease(ioRegistryRoot); | ||||
|     CFStringGetCString(uuidCf, buf, buf_size, kCFStringEncodingMacRoman); | ||||
|     CFRelease(uuidCf); | ||||
|     // Now convert the string to std::vector<unsigned char>.
 | ||||
|     for (char* c = buf; *c != 0; ++c) | ||||
|         unique.emplace_back((unsigned char)(*c)); | ||||
| #else // Linux/BSD
 | ||||
|     constexpr size_t max_len = 100; | ||||
|     char cline[max_len] = ""; | ||||
|     FILE* fp = popen("cat /etc/machine-id", "r"); | ||||
|     if (fp != NULL) { | ||||
|         // Maybe the only way to silence -Wunused-result on gcc...
 | ||||
|         // cline is simply not modified on failure, who cares.
 | ||||
|         [[maybe_unused]]auto dummy = fgets(cline, max_len, fp); | ||||
|         pclose(fp); | ||||
|     } | ||||
|     // Now convert the string to std::vector<unsigned char>.
 | ||||
|     for (char* c = cline; *c != 0; ++c) | ||||
|         unique.emplace_back((unsigned char)(*c)); | ||||
| #endif | ||||
| 
 | ||||
|     // In case that we did not manage to get the unique info, just return an empty
 | ||||
|     // string, so it is easily detectable and not masked by the hashing.
 | ||||
|     if (unique.empty()) | ||||
|         return ""; | ||||
| 
 | ||||
|     // We should have a unique vector<unsigned char>. Append a long prime to be
 | ||||
|     // absolutely safe against unhashing.
 | ||||
|     uint64_t prime = 1171432692373; | ||||
|     size_t beg = unique.size(); | ||||
|     unique.resize(beg + 8); | ||||
|     memcpy(&unique[beg], &prime, 8); | ||||
| 
 | ||||
|     // Compute an MD5 hash and convert to std::string.
 | ||||
|     using boost::uuids::detail::md5; | ||||
|     md5 hash; | ||||
|     md5::digest_type digest; | ||||
|     hash.process_bytes(unique.data(), unique.size()); | ||||
|     hash.get_digest(digest); | ||||
|     const unsigned char* charDigest = reinterpret_cast<const unsigned char*>(&digest); | ||||
|     std::string result; | ||||
|     boost::algorithm::hex(charDigest, charDigest + sizeof(md5::digest_type), std::back_inserter(result)); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Following function generates one string that will be shown in the preview
 | ||||
| // and later sent if confirmed by the user.
 | ||||
| static std::string generate_system_info_json() | ||||
| { | ||||
|     // Calculate hash of username so it is possible to identify duplicates.
 | ||||
|     // The result is mod 10000 so most of the information is lost and it is
 | ||||
|     // not possible to unhash the username. It is more than enough to help
 | ||||
|     // identify duplicate entries.
 | ||||
|     std::string unique_id = get_unique_id(); | ||||
| 
 | ||||
|     // Get system language.
 | ||||
|     std::string sys_language = "Unknown"; | ||||
|     const wxLanguage lang_system = wxLanguage(wxLocale::GetSystemLanguage()); | ||||
|     if (lang_system != wxLANGUAGE_UNKNOWN) | ||||
|         sys_language = wxLocale::GetLanguageInfo(lang_system)->CanonicalName.ToUTF8().data(); | ||||
| 
 | ||||
|     // Build a property tree with all the information.
 | ||||
|     namespace pt = boost::property_tree; | ||||
| 
 | ||||
|     pt::ptree data_node; | ||||
|     data_node.put("PrusaSlicerVersion", SLIC3R_VERSION); | ||||
|     data_node.put("BuildID", SLIC3R_BUILD_ID); | ||||
|     data_node.put("UniqueID", unique_id); | ||||
|     data_node.put("Platform", platform_to_string(platform())); | ||||
|     data_node.put("PlatformFlavor", platform_flavor_to_string(platform_flavor())); | ||||
|     data_node.put("OSDescription", wxPlatformInfo::Get().GetOperatingSystemDescription().ToUTF8().data()); | ||||
| #ifdef __linux__ | ||||
|     std::string distro_id = wxGetLinuxDistributionInfo().Id.ToUTF8().data(); // uses lsb-release
 | ||||
|     std::string distro_ver = wxGetLinuxDistributionInfo().Release.ToUTF8().data(); | ||||
|     if (distro_id.empty()) { // lsb-release probably not available
 | ||||
|         std::map<std::string, std::string> dist_info = parse_lscpu_etc("cat /etc/*release", '='); | ||||
|         distro_id = dist_info["ID"]; | ||||
|         distro_ver = dist_info["VERSION_ID"]; | ||||
|     } | ||||
|     data_node.put("Linux_DistroID", distro_id); | ||||
|     data_node.put("Linux_DistroVer", distro_ver); | ||||
|     data_node.put("Linux_Wayland", wxGetEnv("WAYLAND_DISPLAY", nullptr)); | ||||
| #endif | ||||
|     data_node.put("wxWidgets", wxVERSION_NUM_DOT_STRING); | ||||
| #ifdef __WXGTK__ | ||||
|     data_node.put("GTK", | ||||
|     #if defined(__WXGTK2__) | ||||
|         2 | ||||
|     #elif defined(__WXGTK3__) | ||||
|         3 | ||||
|     #elif defined(__WXGTK4__) | ||||
|         4 | ||||
|     #elif defined(__WXGTK5__) | ||||
|         5 | ||||
|     #else | ||||
|         "Unknown" | ||||
|     #endif | ||||
|     ); | ||||
| #endif // __WXGTK__
 | ||||
|     data_node.put("SystemLanguage", sys_language); | ||||
|     data_node.put("TranslationLanguage: ", wxGetApp().app_config->get("translation_language")); | ||||
| 
 | ||||
|     pt::ptree hw_node; | ||||
|     hw_node.put("ArchName", wxPlatformInfo::Get().GetArchName()); | ||||
|     hw_node.put("RAM_MB", size_t(Slic3r::total_physical_memory()/1000000)); | ||||
| 
 | ||||
|     // Now get some CPU info:
 | ||||
|     pt::ptree cpu_node; | ||||
| #ifdef _WIN32 | ||||
|     std::map<std::string, std::string> cpu_info = get_cpu_info_from_registry(); | ||||
|     cpu_node.put("Cores",  cpu_info["Cores"]); | ||||
|     cpu_node.put("Model",  cpu_info["Model"]); | ||||
|     cpu_node.put("Vendor", cpu_info["Vendor"]); | ||||
| #elif __APPLE__ | ||||
|      std::map<std::string, std::string> sysctl = parse_lscpu_etc("sysctl -a", ':'); | ||||
|      cpu_node.put("Cores",  sysctl["hw.ncpu"]); | ||||
|      cpu_node.put("Model",  sysctl["machdep.cpu.brand_string"]); | ||||
|      cpu_node.put("Vendor", sysctl["machdep.cpu.vendor"]); | ||||
| #else // linux/BSD
 | ||||
|     std::map<std::string, std::string> lscpu = parse_lscpu_etc("lscpu", ':'); | ||||
|     cpu_node.put("Arch",   lscpu["Architecture"]); | ||||
|     cpu_node.put("Cores",  lscpu["CPU(s)"]); | ||||
|     cpu_node.put("Model",  lscpu["Model name"]); | ||||
|     cpu_node.put("Vendor", lscpu["Vendor ID"]); | ||||
| #endif | ||||
|     hw_node.add_child("CPU", cpu_node); | ||||
| 
 | ||||
|     pt::ptree monitors_node; | ||||
|     for (int i=0; i<int(wxDisplay::GetCount()); ++i) { | ||||
|         wxDisplay display(i); | ||||
|         double scaling = -1.; | ||||
|         #if wxCHECK_VERSION(3, 1, 2) // we have wxDisplag::GetPPI
 | ||||
|             int std_ppi = 96; | ||||
|             #ifdef __WXOSX__ // see impl of wxDisplay::GetStdPPIValue from 3.1.5
 | ||||
|                 std_ppi = 72; | ||||
|             #endif | ||||
|             scaling = double(display.GetPPI().GetWidth()) / std_ppi; | ||||
|         #endif | ||||
|         pt::ptree monitor_node; // Create an unnamed node containing the value
 | ||||
|         monitor_node.put("width", display.GetGeometry().GetWidth()); | ||||
|         monitor_node.put("height", display.GetGeometry().GetHeight()); | ||||
|         std::stringstream ss; | ||||
|         ss << std::setprecision(3) << scaling; | ||||
|         monitor_node.put("scaling", ss.str() ); | ||||
|         monitors_node.push_back(std::make_pair("", monitor_node)); | ||||
|     } | ||||
|     hw_node.add_child("Monitors", monitors_node); | ||||
|     data_node.add_child("Hardware", hw_node); | ||||
| 
 | ||||
|     pt::ptree opengl_node; | ||||
|     opengl_node.put("Version", OpenGLManager::get_gl_info().get_version()); | ||||
|     opengl_node.put("GLSLVersion", OpenGLManager::get_gl_info().get_glsl_version()); | ||||
|     opengl_node.put("Vendor", OpenGLManager::get_gl_info().get_vendor()); | ||||
|     opengl_node.put("Renderer", OpenGLManager::get_gl_info().get_renderer()); | ||||
|     // Generate list of OpenGL extensions:
 | ||||
|     std::string extensions_str = gl_get_string_safe(GL_EXTENSIONS, ""); | ||||
|     std::vector<std::string> extensions_list; | ||||
|     boost::split(extensions_list, extensions_str, boost::is_any_of(" "), boost::token_compress_off); | ||||
|     std::sort(extensions_list.begin(), extensions_list.end()); | ||||
|     pt::ptree extensions_node; | ||||
|     for (const std::string& s : extensions_list) { | ||||
|         if (s.empty()) | ||||
|             continue; | ||||
|         pt::ptree ext_node; // Create an unnamed node containing the value
 | ||||
|         ext_node.put("", s); | ||||
|         extensions_node.push_back(std::make_pair("", ext_node)); // Add this node to the list.
 | ||||
|     } | ||||
|     opengl_node.add_child("Extensions", extensions_node); | ||||
|     data_node.add_child("OpenGL", opengl_node); | ||||
| 
 | ||||
|     pt::ptree root; | ||||
|     root.add_child("data", data_node); | ||||
| 
 | ||||
|     // Serialize the tree into JSON and return it.
 | ||||
|     std::stringstream ss; | ||||
|     pt::write_json(ss, root); | ||||
|     return ss.str(); | ||||
| 
 | ||||
|     // FURTHER THINGS TO CONSIDER:
 | ||||
|     //std::cout << wxPlatformInfo::Get().GetOperatingSystemFamilyName() << std::endl;          // Unix
 | ||||
|     // ? CPU, GPU, UNKNOWN ?
 | ||||
|     // printers? will they be installed already?
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| SendSystemInfoDialog::SendSystemInfoDialog(wxWindow* parent) | ||||
|     : m_system_info_json{generate_system_info_json()}, | ||||
|     GUI::DPIDialog(parent, wxID_ANY, _L("Send system info"), wxDefaultPosition, wxDefaultSize, | ||||
|            wxDEFAULT_DIALOG_STYLE) | ||||
| { | ||||
|     // Get current PrusaSliver version info.
 | ||||
|     std::string app_name; | ||||
|     { | ||||
|         Semver semver(SLIC3R_VERSION); | ||||
|         bool is_alpha = std::string{semver.prerelease()}.find("alpha") != std::string::npos; | ||||
|         bool is_beta = std::string{semver.prerelease()}.find("beta") != std::string::npos; | ||||
|         app_name = std::string(SLIC3R_APP_NAME) + " " + std::to_string(semver.maj()) | ||||
|                                + "." + std::to_string(semver.min()) + " " | ||||
|                                + (is_alpha ? "Alpha" : is_beta ? "Beta" : ""); | ||||
|     } | ||||
| 
 | ||||
|     // Get current source file name.
 | ||||
|     std::string filename(__FILE__); | ||||
|     size_t last_slash_idx = filename.find_last_of("/\\"); | ||||
|     if (last_slash_idx != std::string::npos) | ||||
|         filename = filename.substr(last_slash_idx+1); | ||||
| 
 | ||||
|     // Set dialog background color, fonts, etc.
 | ||||
|     SetFont(wxGetApp().normal_font()); | ||||
|     wxColour bgr_clr = wxGetApp().get_window_default_clr(); | ||||
|     SetBackgroundColour(bgr_clr); | ||||
|     const auto text_clr = wxGetApp().get_label_clr_default(); | ||||
|     auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); | ||||
|     auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); | ||||
| 
 | ||||
| 
 | ||||
|     auto *topSizer = new wxBoxSizer(wxVERTICAL); | ||||
|     auto *vsizer = new wxBoxSizer(wxVERTICAL); | ||||
| 
 | ||||
|     wxString text0 = GUI::format_wxstr(_L("This is the first time you are running %1%. We would like to " | ||||
|            "ask you to send some of your system information to us. This will only " | ||||
|            "happen once and we will not ask you to do this again (only after you " | ||||
|            "upgrade to the next version)."), app_name ); | ||||
|     wxString text1 = _L("If we know your hardware, operating system, etc., it will greatly help us " | ||||
|         "in development and prioritization, because we will be able to focus our effort more efficiently " | ||||
|         "and spend time on features that are needed the most."); | ||||
|     wxString label2 = _L("Is it safe?"); | ||||
|     wxString text2 = GUI::format_wxstr( | ||||
|         _L("We do not send any personal information nor anything that would allow us " | ||||
|            "to identify you later. To detect duplicate entries, a unique number derived " | ||||
|            "from your system is sent, but the source information cannot be reconstructed. " | ||||
|            "Apart from that, only general data about your OS, hardware and OpenGL " | ||||
|            "installation are sent. PrusaSlicer is open source, if you want to " | ||||
|            "inspect the code actually performing the communication, see %1%."), | ||||
|            std::string("<i>") + filename + "</i>"); | ||||
|     wxString label3 = _L("Show verbatim data that will be sent"); | ||||
| 
 | ||||
|     auto* html_window = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER); | ||||
|     wxString html = GUI::format_wxstr( | ||||
|             "<html><body bgcolor=%1%><font color=%2%>" | ||||
|             "<table><tr><td>" | ||||
|             "<img src = \"" + resources_dir() + "/icons/PrusaSlicer_192px.png\" />" | ||||
|             "</td><td align=\"left\">" | ||||
|             + text0 + "<br / ><br / >" | ||||
|             + text1 + "<br /><br />" | ||||
|             "</td></tr></table>" | ||||
|             + "<b>" + label2 + "</b><br />" | ||||
|             + text2 + "<br /><br />" | ||||
|             + "<b><a href=\"show\">" + label3 + "</a></b><br />" | ||||
|             + "</font></body></html>", bgr_clr_str, text_clr_str); | ||||
|     html_window->SetPage(html); | ||||
|     html_window->Bind(wxEVT_HTML_LINK_CLICKED, [this](wxHtmlLinkEvent &evt) { | ||||
|                                                    ShowJsonDialog dlg(this, m_system_info_json, GetSize().Scale(0.9, 0.7)); | ||||
|                                                    dlg.ShowModal(); | ||||
|     }); | ||||
| 
 | ||||
|     vsizer->Add(html_window, 1, wxEXPAND); | ||||
| 
 | ||||
|     m_btn_ask_later = new wxButton(this, wxID_ANY, _L("Ask me next time")); | ||||
|     m_btn_dont_send = new wxButton(this, wxID_ANY, _L("Do not send anything")); | ||||
|     m_btn_send = new wxButton(this, wxID_ANY, _L("Send system info")); | ||||
| 
 | ||||
|     auto* hsizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|     const int em = GUI::wxGetApp().em_unit(); | ||||
|     hsizer->Add(m_btn_ask_later); | ||||
|     hsizer->AddSpacer(em); | ||||
|     hsizer->Add(m_btn_dont_send); | ||||
|     hsizer->AddSpacer(em); | ||||
|     hsizer->Add(m_btn_send); | ||||
| 
 | ||||
|     vsizer->Add(hsizer, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 10); | ||||
|     topSizer->Add(vsizer, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 10); | ||||
| 
 | ||||
|     SetSizer(topSizer); | ||||
|     topSizer->SetSizeHints(this); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     wxGetApp().UpdateDlgDarkUI(this); | ||||
| #endif | ||||
| 
 | ||||
|     const auto size = GetSize(); | ||||
|     SetSize(std::max(size.GetWidth(), MIN_WIDTH * em), | ||||
|             std::max(size.GetHeight(), MIN_HEIGHT * em)); | ||||
| 
 | ||||
|     m_btn_send->Bind(wxEVT_BUTTON, [this](const wxEvent&) | ||||
|                                     { | ||||
|                                         if (send_info()) { | ||||
|                                             save_version(); | ||||
|                                             EndModal(0); | ||||
|                                         } | ||||
|                                     }); | ||||
|     m_btn_dont_send->Bind(wxEVT_BUTTON, [this](const wxEvent&) | ||||
|                                          { | ||||
|                                              save_version(); | ||||
|                                              EndModal(0); | ||||
|                                          }); | ||||
|     m_btn_ask_later->Bind(wxEVT_BUTTON, [this](const wxEvent&) { EndModal(0); }); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void SendSystemInfoDialog::on_dpi_changed(const wxRect&) | ||||
| { | ||||
|     const int& em = em_unit(); | ||||
|     msw_buttons_rescale(this, em, { m_btn_send->GetId(), | ||||
|                                     m_btn_dont_send->GetId(), | ||||
|                                     m_btn_ask_later->GetId() }); | ||||
|     SetMinSize(wxSize(MIN_WIDTH * em, MIN_HEIGHT * em)); | ||||
|     Fit(); | ||||
|     Refresh(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // This actually sends the info.
 | ||||
| bool SendSystemInfoDialog::send_info() | ||||
| { | ||||
|     std::atomic<int> job_done = false; // Flag to communicate between threads.
 | ||||
|     struct Result { | ||||
|         enum { | ||||
|             Success, | ||||
|             Cancelled, | ||||
|             Error | ||||
|         } value; | ||||
|         wxString str; | ||||
|     } result; // No synchronization needed, UI thread reads only after worker is joined.
 | ||||
| 
 | ||||
|     auto send = [&job_done, &result](const std::string& data) { | ||||
|         const std::string url = "https://files.prusa3d.com/wp-json/v1/ps"; | ||||
|         Http http = Http::post(url); | ||||
|         http.header("Content-Type", "application/json") | ||||
|             .set_post_body(data) | ||||
|             .on_complete([&result](std::string body, unsigned status) { | ||||
|                 result = { Result::Success, _L("System info sent successfully. Thank you.") }; | ||||
|             }) | ||||
|             .on_error([&result](std::string body, std::string error, unsigned status) { | ||||
|                 result = { Result::Error, GUI::format_wxstr(_L("Sending system info failed! Status: %1%"), status) }; | ||||
|             }) | ||||
|             .on_progress([&job_done, &result](Http::Progress, bool &cancel) { | ||||
|                 if (job_done) // UI thread wants us to cancel.
 | ||||
|                     cancel = true; | ||||
|                 if (cancel) | ||||
|                     result = { Result::Cancelled, _L("Sending system info was cancelled.") }; | ||||
|             }) | ||||
|             .perform_sync(); | ||||
|         job_done = true; // So that the dialog knows we are done.
 | ||||
|     }; | ||||
| 
 | ||||
|     std::thread sending_thread(send, m_system_info_json); | ||||
|     SendSystemInfoProgressDialog dlg(this, _L("Sending system info...")); | ||||
|     wxTimer timer(&dlg); // Periodically check the status of the other thread, close dialog when done.
 | ||||
|     dlg.Bind(wxEVT_TIMER, [&dlg, &job_done](wxTimerEvent&){ if (job_done) dlg.EndModal(0); }); | ||||
|     timer.Start(50); | ||||
|     dlg.ShowModal(); | ||||
|     // The dialog is closed, either by user, or by the now terminated worker thread.
 | ||||
|     job_done = true;       // In case the user closed the dialog, let the other thread know
 | ||||
|     sending_thread.join(); // and wait until it terminates.
 | ||||
| 
 | ||||
|     InfoDialog info_dlg(wxGetApp().mainframe, wxEmptyString, result.str); | ||||
|     info_dlg.ShowModal(); | ||||
|     return result.value == Result::Success; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // The only function callable from outside this unit.
 | ||||
| void show_send_system_info_dialog_if_needed() | ||||
| { | ||||
|     if (wxGetApp().is_gcode_viewer() || ! should_dialog_be_shown()) | ||||
|         return; | ||||
| 
 | ||||
|     SendSystemInfoDialog dlg(wxGetApp().mainframe); | ||||
|     dlg.ShowModal(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
							
								
								
									
										14
									
								
								src/slic3r/GUI/SendSystemInfoDialog.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/slic3r/GUI/SendSystemInfoDialog.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #ifndef slic3r_SendSystemInfoDialog_hpp_ | ||||
| #define slic3r_SendSystemInfoDialog_hpp_ | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
| void show_send_system_info_dialog_if_needed(); | ||||
| 
 | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| #endif // slic3r_SendSystemInfoDialog_hpp_
 | ||||
|  | @ -9,6 +9,8 @@ | |||
| 
 | ||||
| #include <libslic3r/format.hpp> | ||||
| 
 | ||||
| #include <wx/string.h> | ||||
| 
 | ||||
| namespace Slic3r {  | ||||
| namespace GUI {  | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 enricoturri1966
						enricoturri1966