Merge remote-tracking branch 'remotes/prusa/master' into dev
@ -397,6 +397,7 @@ endif ()
|
|||||||
|
|
||||||
find_package(PNG REQUIRED)
|
find_package(PNG REQUIRED)
|
||||||
|
|
||||||
|
set(OpenGL_GL_PREFERENCE "LEGACY")
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
# Find glew or use bundled version
|
# Find glew or use bundled version
|
||||||
@ -513,9 +514,13 @@ endif()
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
||||||
elseif (SLIC3R_FHS)
|
elseif (SLIC3R_FHS)
|
||||||
|
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
|
||||||
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/SuperSlicer")
|
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/SuperSlicer")
|
||||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${SLIC3R_FHS_RESOURCES}")
|
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${SLIC3R_FHS_RESOURCES}")
|
||||||
|
install(FILES src/platform/unix/SuperSlicer.desktop DESTINATION ${SLIC3R_FHS_RESOURCES}/applications)
|
||||||
else ()
|
else ()
|
||||||
|
install(FILES src/platform/unix/SuperSlicer.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/resources/applications)
|
||||||
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
install(DIRECTORY "${SLIC3R_RESOURCES_DIR}/" DESTINATION "${CMAKE_INSTALL_PREFIX}/resources")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
configure_file(${LIBDIR}/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp)
|
configure_file(${LIBDIR}/platform/unix/fhs.hpp.in ${LIBDIR_BIN}/platform/unix/fhs.hpp)
|
||||||
|
2
deps/PNG/PNG.cmake
vendored
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
prusaslicer_add_cmake_project(PNG
|
prusaslicer_add_cmake_project(PNG
|
||||||
GIT_REPOSITORY https://github.com/glennrp/libpng.git
|
GIT_REPOSITORY https://github.com/glennrp/libpng.git
|
||||||
GIT_TAG v1.6.35
|
GIT_TAG v1.6.35
|
||||||
@ -5,6 +6,7 @@ prusaslicer_add_cmake_project(PNG
|
|||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
-DPNG_SHARED=OFF
|
-DPNG_SHARED=OFF
|
||||||
-DPNG_STATIC=ON
|
-DPNG_STATIC=ON
|
||||||
|
-DPNG_PREFIX=prusaslicer_
|
||||||
-DPNG_TESTS=OFF
|
-DPNG_TESTS=OFF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 15 KiB |
BIN
resources/icons/PrusaSlicer-gcodeviewer_32px.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
13
resources/icons/white/exit.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.0" id="exit" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||||
|
<path fill="#ED6B21" d="M63.4,45.46l-20-15c-2.51-1.88-6.06-1.37-7.94,1.13c-1.88,2.5-1.37,6.06,1.13,7.94l6.39,4.79H10
|
||||||
|
c-3.13,0-5.67,2.54-5.67,5.67s2.54,5.67,5.67,5.67h32.99l-6.39,4.8c-2.5,1.88-3.01,5.43-1.13,7.94c1.11,1.49,2.82,2.27,4.54,2.27
|
||||||
|
c1.18,0,2.38-0.37,3.4-1.13l20-15c1.43-1.07,2.27-2.75,2.27-4.54C65.67,48.22,64.83,46.54,63.4,45.46z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M90,92.83H40c-1.57,0-2.83-1.27-2.83-2.83V80c0-1.57,1.27-2.83,2.83-2.83s2.83,1.27,2.83,2.83v7.17h44.33
|
||||||
|
V12.83H42.83V20c0,1.57-1.27,2.83-2.83,2.83s-2.83-1.27-2.83-2.83V10c0-1.57,1.27-2.83,2.83-2.83h50c1.57,0,2.83,1.27,2.83,2.83v80
|
||||||
|
C92.83,91.57,91.57,92.83,90,92.83z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 997 B |
52
resources/icons/white/switch_presets.svg
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.0" id="change_x5F_profile_copy" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||||
|
<rect x="-45" y="5" display="none" fill="#FFFFFF" width="55" height="90"/>
|
||||||
|
<rect x="90" y="5" transform="matrix(-1 -1.224647e-16 1.224647e-16 -1 235 100)" display="none" fill="#FFFFFF" width="55" height="90"/>
|
||||||
|
<path fill="#ED6B21" d="M88.52,28.64c-1.25-0.94-3.03-0.69-3.97,0.57l-1.72,2.29V15c0-1.57-1.27-2.83-2.83-2.83H65
|
||||||
|
c-1.57,0-2.83,1.27-2.83,2.83s1.27,2.83,2.83,2.83h12.17V31.5l-1.72-2.29c-0.94-1.25-2.72-1.5-3.97-0.57
|
||||||
|
c-1.25,0.94-1.51,2.72-0.57,3.97l6.82,9.09c0.54,0.71,1.38,1.13,2.27,1.13s1.73-0.42,2.27-1.13l6.82-9.09
|
||||||
|
C90.03,31.36,89.77,29.58,88.52,28.64z"/>
|
||||||
|
<path fill="#ED6B21" d="M35,82.17H22.83V68.5l1.72,2.29c0.56,0.74,1.41,1.13,2.27,1.13c0.59,0,1.19-0.18,1.7-0.57
|
||||||
|
c1.25-0.94,1.51-2.72,0.57-3.97l-6.82-9.09c-0.54-0.71-1.38-1.13-2.27-1.13s-1.73,0.42-2.27,1.13l-6.82,9.09
|
||||||
|
c-0.94,1.25-0.69,3.03,0.57,3.97c1.25,0.94,3.03,0.69,3.97-0.57l1.72-2.29V85c0,1.57,1.27,2.83,2.83,2.83h15
|
||||||
|
c1.57,0,2.83-1.27,2.83-2.83S36.57,82.17,35,82.17z"/>
|
||||||
|
<polyline display="none" fill="none" stroke="#ED6B21" stroke-width="11.3386" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
|
||||||
|
35,65 15,50 35,35 "/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M50.01,41.11c0-0.75-0.3-1.47-0.83-2l-1.99-1.99H50c1.57,0,2.83-1.27,2.83-2.83v-8.57
|
||||||
|
c0-1.57-1.27-2.83-2.83-2.83h-2.81l1.99-1.99c0.53-0.53,0.83-1.25,0.83-2s-0.3-1.47-0.83-2l-6.06-6.06c-1.06-1.06-2.95-1.06-4.01,0
|
||||||
|
l-1.99,1.99V10c0-1.57-1.27-2.83-2.83-2.83h-8.57c-1.57,0-2.83,1.27-2.83,2.83v2.81l-1.99-1.99c-0.53-0.53-1.25-0.83-2-0.83
|
||||||
|
s-1.47,0.3-2,0.83l-6.06,6.06c-0.53,0.53-0.83,1.25-0.83,2s0.3,1.47,0.83,2l1.99,1.99H10c-1.57,0-2.83,1.27-2.83,2.83v8.57
|
||||||
|
c0,1.57,1.27,2.83,2.83,2.83h2.81l-1.99,1.99c-0.53,0.53-0.83,1.25-0.83,2s0.3,1.47,0.83,2l6.06,6.06c1.11,1.11,2.9,1.11,4.01,0
|
||||||
|
l1.99-1.99V50c0,1.57,1.27,2.83,2.83,2.83h8.57c1.57,0,2.83-1.27,2.83-2.83v-2.81l1.99,1.99c1.11,1.11,2.9,1.11,4.01,0l6.06-6.06
|
||||||
|
C49.71,42.58,50.01,41.86,50.01,41.11z M47.17,31.45h-2.05c-1.27,0-2.38,0.84-2.73,2.06c-0.27,0.96-0.66,1.89-1.14,2.76
|
||||||
|
c-0.62,1.11-0.43,2.49,0.47,3.39l1.45,1.45l-2.05,2.05l-1.45-1.45c-0.9-0.9-2.28-1.09-3.39-0.47c-0.87,0.49-1.8,0.87-2.76,1.14
|
||||||
|
c-1.22,0.35-2.06,1.46-2.06,2.73v2.05h-2.9v-2.05c0-1.27-0.84-2.38-2.06-2.73c-0.96-0.27-1.89-0.66-2.76-1.14
|
||||||
|
c-1.11-0.62-2.49-0.43-3.39,0.47l-1.45,1.45l-2.05-2.05l1.45-1.45c0.9-0.9,1.09-2.28,0.47-3.39c-0.49-0.87-0.87-1.8-1.14-2.76
|
||||||
|
c-0.35-1.22-1.46-2.06-2.73-2.06h-2.05v-2.9h2.05c1.27,0,2.38-0.84,2.73-2.06c0.27-0.96,0.66-1.89,1.14-2.76
|
||||||
|
c0.62-1.11,0.43-2.49-0.47-3.39l-1.45-1.45l2.05-2.05l1.45,1.45c0.9,0.9,2.28,1.09,3.39,0.47c0.87-0.49,1.8-0.87,2.76-1.14
|
||||||
|
c1.22-0.35,2.06-1.46,2.06-2.73v-2.05h2.9v2.05c0,1.27,0.84,2.38,2.06,2.73c0.96,0.27,1.89,0.66,2.76,1.14
|
||||||
|
c1.11,0.62,2.49,0.43,3.39-0.47l1.45-1.45l2.05,2.05l-1.45,1.45c-0.9,0.9-1.09,2.28-0.47,3.39c0.49,0.87,0.87,1.8,1.14,2.76
|
||||||
|
c0.35,1.22,1.46,2.06,2.73,2.06h2.05V31.45z"/>
|
||||||
|
<path fill="#FFFFFF" d="M90,62.88h-2.81l1.99-1.99c1.11-1.11,1.11-2.9,0-4.01l-6.06-6.06c-1.11-1.11-2.9-1.11-4.01,0l-1.99,1.99V50
|
||||||
|
c0-1.57-1.27-2.83-2.83-2.83h-8.57c-1.57,0-2.83,1.27-2.83,2.83v2.81l-1.99-1.99c-1.11-1.11-2.9-1.11-4.01,0l-6.06,6.06
|
||||||
|
c-1.11,1.11-1.11,2.9,0,4.01l1.99,1.99H50c-1.57,0-2.83,1.27-2.83,2.83v8.57c0,1.57,1.27,2.83,2.83,2.83h2.81l-1.99,1.99
|
||||||
|
c-1.11,1.11-1.11,2.9,0,4.01l6.06,6.06c1.11,1.11,2.9,1.11,4.01,0l1.99-1.99V90c0,1.57,1.27,2.83,2.83,2.83h8.57
|
||||||
|
c1.57,0,2.83-1.27,2.83-2.83v-2.81l1.99,1.99c1.11,1.11,2.9,1.11,4.01,0l6.06-6.06c1.11-1.11,1.11-2.9,0-4.01l-1.99-1.99H90
|
||||||
|
c1.57,0,2.83-1.27,2.83-2.83v-8.57C92.83,64.15,91.57,62.88,90,62.88z M87.17,71.45h-2.05c-1.27,0-2.38,0.84-2.73,2.06
|
||||||
|
c-0.27,0.96-0.66,1.89-1.14,2.76c-0.62,1.11-0.43,2.49,0.47,3.39l1.45,1.45l-2.05,2.05l-1.45-1.45c-0.9-0.9-2.28-1.09-3.39-0.47
|
||||||
|
c-0.87,0.49-1.8,0.87-2.76,1.15c-1.22,0.35-2.06,1.46-2.06,2.73v2.05h-2.9v-2.05c0-1.27-0.84-2.38-2.06-2.73
|
||||||
|
c-0.96-0.27-1.89-0.66-2.76-1.15c-1.11-0.62-2.49-0.43-3.39,0.47l-1.45,1.45l-2.05-2.05l1.45-1.45c0.9-0.9,1.09-2.28,0.47-3.39
|
||||||
|
c-0.49-0.87-0.87-1.8-1.14-2.76c-0.35-1.22-1.46-2.06-2.73-2.06h-2.05v-2.9h2.05c1.27,0,2.38-0.84,2.73-2.06
|
||||||
|
c0.27-0.96,0.66-1.89,1.14-2.76c0.62-1.11,0.43-2.49-0.47-3.39l-1.45-1.45l2.05-2.05l1.45,1.45c0.9,0.9,2.28,1.09,3.39,0.47
|
||||||
|
c0.87-0.49,1.8-0.87,2.76-1.14c1.22-0.35,2.06-1.46,2.06-2.73v-2.05h2.9v2.05c0,1.27,0.84,2.38,2.06,2.73
|
||||||
|
c0.96,0.27,1.89,0.66,2.76,1.14c1.11,0.62,2.49,0.43,3.39-0.47l1.45-1.45l2.05,2.05l-1.45,1.45c-0.9,0.9-1.09,2.28-0.47,3.39
|
||||||
|
c0.49,0.87,0.87,1.8,1.14,2.76c0.35,1.22,1.46,2.06,2.73,2.06h2.05V71.45z"/>
|
||||||
|
<path fill="#FFFFFF" d="M30,22.17c-4.32,0-7.83,3.51-7.83,7.83s3.51,7.83,7.83,7.83s7.83-3.51,7.83-7.83S34.32,22.17,30,22.17z
|
||||||
|
M30,32.17c-1.19,0-2.17-0.97-2.17-2.17s0.97-2.17,2.17-2.17s2.17,0.97,2.17,2.17S31.19,32.17,30,32.17z"/>
|
||||||
|
<path fill="#FFFFFF" d="M70,62.17c-4.32,0-7.83,3.51-7.83,7.83s3.51,7.83,7.83,7.83s7.83-3.51,7.83-7.83S74.32,62.17,70,62.17z
|
||||||
|
M70,72.17c-1.19,0-2.17-0.97-2.17-2.17s0.97-2.17,2.17-2.17s2.17,0.97,2.17,2.17S71.19,72.17,70,72.17z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.2 KiB |
@ -1,5 +1,4 @@
|
|||||||
src/slic3r/GUI/AboutDialog.cpp
|
src/slic3r/GUI/AboutDialog.cpp
|
||||||
src/slic3r/GUI/AppConfig.cpp
|
|
||||||
src/slic3r/GUI/BackgroundSlicingProcess.cpp
|
src/slic3r/GUI/BackgroundSlicingProcess.cpp
|
||||||
src/slic3r/GUI/BedShapeDialog.cpp
|
src/slic3r/GUI/BedShapeDialog.cpp
|
||||||
src/slic3r/GUI/BedShapeDialog.hpp
|
src/slic3r/GUI/BedShapeDialog.hpp
|
||||||
@ -9,45 +8,60 @@ src/slic3r/GUI/ConfigManipulation.cpp
|
|||||||
src/slic3r/GUI/ConfigSnapshotDialog.cpp
|
src/slic3r/GUI/ConfigSnapshotDialog.cpp
|
||||||
src/slic3r/GUI/ConfigWizard.cpp
|
src/slic3r/GUI/ConfigWizard.cpp
|
||||||
src/slic3r/GUI/DoubleSlider.cpp
|
src/slic3r/GUI/DoubleSlider.cpp
|
||||||
|
src/slic3r/GUI/ExtraRenderers.cpp
|
||||||
src/slic3r/GUI/ExtruderSequenceDialog.cpp
|
src/slic3r/GUI/ExtruderSequenceDialog.cpp
|
||||||
src/slic3r/GUI/Field.cpp
|
src/slic3r/GUI/Field.cpp
|
||||||
src/slic3r/GUI/FirmwareDialog.cpp
|
src/slic3r/GUI/FirmwareDialog.cpp
|
||||||
|
src/slic3r/GUI/GCodeViewer.cpp
|
||||||
src/slic3r/GUI/GLCanvas3D.cpp
|
src/slic3r/GUI/GLCanvas3D.cpp
|
||||||
src/slic3r/GUI/GLCanvas3DManager.cpp
|
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
|
||||||
|
src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
|
||||||
|
src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
|
src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
|
||||||
src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
|
src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
|
||||||
|
src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
|
||||||
src/slic3r/GUI/GUI.cpp
|
src/slic3r/GUI/GUI.cpp
|
||||||
src/slic3r/GUI/GUI_App.cpp
|
src/slic3r/GUI/GUI_App.cpp
|
||||||
|
src/slic3r/GUI/GUI_Init.cpp
|
||||||
src/slic3r/GUI/GUI_ObjectLayers.cpp
|
src/slic3r/GUI/GUI_ObjectLayers.cpp
|
||||||
src/slic3r/GUI/GUI_ObjectList.cpp
|
src/slic3r/GUI/GUI_ObjectList.cpp
|
||||||
src/slic3r/GUI/GUI_ObjectManipulation.cpp
|
src/slic3r/GUI/GUI_ObjectManipulation.cpp
|
||||||
src/slic3r/GUI/GUI_ObjectSettings.cpp
|
src/slic3r/GUI/GUI_ObjectSettings.cpp
|
||||||
src/slic3r/GUI/GUI_Preview.cpp
|
src/slic3r/GUI/GUI_Preview.cpp
|
||||||
src/slic3r/GUI/Job.hpp
|
src/slic3r/GUI/ImGuiWrapper.cpp
|
||||||
|
src/slic3r/GUI/Jobs/ArrangeJob.cpp
|
||||||
|
src/slic3r/GUI/Jobs/Job.cpp
|
||||||
|
src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
|
||||||
|
src/slic3r/GUI/Jobs/SLAImportJob.cpp
|
||||||
src/slic3r/GUI/KBShortcutsDialog.cpp
|
src/slic3r/GUI/KBShortcutsDialog.cpp
|
||||||
src/slic3r/GUI/MainFrame.cpp
|
src/slic3r/GUI/MainFrame.cpp
|
||||||
src/slic3r/GUI/Mouse3DController.cpp
|
src/slic3r/GUI/Mouse3DController.cpp
|
||||||
src/slic3r/GUI/MsgDialog.cpp
|
src/slic3r/GUI/MsgDialog.cpp
|
||||||
|
src/slic3r/GUI/NotificationManager.hpp
|
||||||
|
src/slic3r/GUI/NotificationManager.cpp
|
||||||
src/slic3r/GUI/ObjectDataViewModel.cpp
|
src/slic3r/GUI/ObjectDataViewModel.cpp
|
||||||
|
src/slic3r/GUI/OpenGLManager.cpp
|
||||||
src/slic3r/GUI/OptionsGroup.cpp
|
src/slic3r/GUI/OptionsGroup.cpp
|
||||||
|
src/slic3r/GUI/PhysicalPrinterDialog.cpp
|
||||||
src/slic3r/GUI/Plater.cpp
|
src/slic3r/GUI/Plater.cpp
|
||||||
src/slic3r/GUI/Preferences.cpp
|
src/slic3r/GUI/Preferences.cpp
|
||||||
src/slic3r/GUI/Preset.cpp
|
src/slic3r/GUI/PresetComboBoxes.cpp
|
||||||
src/slic3r/GUI/PresetBundle.cpp
|
|
||||||
src/slic3r/GUI/PresetHints.cpp
|
src/slic3r/GUI/PresetHints.cpp
|
||||||
src/slic3r/GUI/PrintHostDialogs.cpp
|
src/slic3r/GUI/PrintHostDialogs.cpp
|
||||||
src/slic3r/GUI/ProgressStatusBar.cpp
|
src/slic3r/GUI/ProgressStatusBar.cpp
|
||||||
src/slic3r/GUI/RammingChart.cpp
|
src/slic3r/GUI/RammingChart.cpp
|
||||||
|
src/slic3r/GUI/SavePresetDialog.cpp
|
||||||
|
src/slic3r/GUI/Search.cpp
|
||||||
src/slic3r/GUI/Selection.cpp
|
src/slic3r/GUI/Selection.cpp
|
||||||
src/slic3r/GUI/SysInfoDialog.cpp
|
src/slic3r/GUI/SysInfoDialog.cpp
|
||||||
src/slic3r/GUI/Tab.cpp
|
src/slic3r/GUI/Tab.cpp
|
||||||
src/slic3r/GUI/Tab.hpp
|
src/slic3r/GUI/Tab.hpp
|
||||||
|
src/slic3r/GUI/UnsavedChangesDialog.cpp
|
||||||
src/slic3r/GUI/UpdateDialogs.cpp
|
src/slic3r/GUI/UpdateDialogs.cpp
|
||||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||||
src/slic3r/GUI/wxExtensions.cpp
|
src/slic3r/GUI/wxExtensions.cpp
|
||||||
@ -57,18 +71,22 @@ src/slic3r/Utils/FixModelByWin10.cpp
|
|||||||
src/slic3r/Utils/FlashAir.cpp
|
src/slic3r/Utils/FlashAir.cpp
|
||||||
src/slic3r/Utils/OctoPrint.cpp
|
src/slic3r/Utils/OctoPrint.cpp
|
||||||
src/slic3r/Utils/PresetUpdater.cpp
|
src/slic3r/Utils/PresetUpdater.cpp
|
||||||
src/libslic3r/SLA/Pad.cpp
|
src/slic3r/Utils/Http.cpp
|
||||||
src/libslic3r/SLA/Hollowing.cpp
|
src/slic3r/Utils/Process.cpp
|
||||||
src/libslic3r/Zipper.cpp
|
|
||||||
src/libslic3r/GCode.cpp
|
src/libslic3r/GCode.cpp
|
||||||
src/libslic3r/ExtrusionEntity.cpp
|
src/libslic3r/ExtrusionEntity.cpp
|
||||||
src/libslic3r/Flow.cpp
|
src/libslic3r/Flow.cpp
|
||||||
src/libslic3r/Format/3mf.cpp
|
src/libslic3r/Format/3mf.cpp
|
||||||
src/libslic3r/Format/AMF.cpp
|
src/libslic3r/Format/AMF.cpp
|
||||||
|
src/libslic3r/GCode/PreviewData.cpp
|
||||||
|
src/libslic3r/miniz_extension.cpp
|
||||||
|
src/libslic3r/Preset.cpp
|
||||||
src/libslic3r/Print.cpp
|
src/libslic3r/Print.cpp
|
||||||
|
src/libslic3r/SLA/Pad.cpp
|
||||||
|
src/libslic3r/SLA/Hollowing.cpp
|
||||||
src/libslic3r/SLAPrint.cpp
|
src/libslic3r/SLAPrint.cpp
|
||||||
src/libslic3r/SLAPrintSteps.cpp
|
src/libslic3r/SLAPrintSteps.cpp
|
||||||
src/libslic3r/PrintBase.cpp
|
src/libslic3r/PrintBase.cpp
|
||||||
src/libslic3r/PrintConfig.cpp
|
src/libslic3r/PrintConfig.cpp
|
||||||
|
src/libslic3r/Zipper.cpp
|
||||||
src/libslic3r/PrintObject.cpp
|
src/libslic3r/PrintObject.cpp
|
||||||
src/libslic3r/GCode/PreviewData.cpp
|
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
|
min_slic3r_version = 2.3.0-alpha2
|
||||||
|
0.0.2 Added Anycubic Predator
|
||||||
min_slic3r_version = 2.3.0-alpha0
|
min_slic3r_version = 2.3.0-alpha0
|
||||||
0.0.1 Initial Version
|
0.0.1 Initial Version
|
||||||
|
BIN
resources/profiles/Anycubic/PREDATOR_thumbnail.png
Normal file
After Width: | Height: | Size: 50 KiB |
@ -7,7 +7,7 @@ name = BIBO
|
|||||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||||
config_version = 0.0.5
|
config_version = 0.0.5
|
||||||
# Where to get the updates from?
|
# Where to get the updates from?
|
||||||
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/BIBO/
|
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/BIBO/
|
||||||
|
|
||||||
# The printer models will be shown by the Configuration Wizard in this order,
|
# The printer models will be shown by the Configuration Wizard in this order,
|
||||||
# also the first model installed & the first nozzle installed will be activated after install.
|
# also the first model installed & the first nozzle installed will be activated after install.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Vendor name will be shown by the Config Wizard.
|
# Vendor name will be shown by the Config Wizard.
|
||||||
name = LulzBot
|
name = LulzBot
|
||||||
config_version = 0.0.3
|
config_version = 0.0.3
|
||||||
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/LulzBot/
|
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/LulzBot/
|
||||||
|
|
||||||
[printer_model:MINI_AERO]
|
[printer_model:MINI_AERO]
|
||||||
name = Mini Aero
|
name = Mini Aero
|
||||||
|
@ -204,11 +204,11 @@ if (WIN32)
|
|||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# This has to be a separate target due to the windows command line lenght limits
|
# This has to be a separate target due to the windows command line lenght limits
|
||||||
add_custom_target(slic3rDllsCopy ALL DEPENDS slic3r)
|
add_custom_target(slic3rDllsCopy ALL DEPENDS slic3r)
|
||||||
prusaslicer_copy_dlls(slic3rDllsCopy)
|
prusaslicer_copy_dlls(slic3rDllsCopy)
|
||||||
|
|
||||||
else ()
|
else ()
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# On OSX, the name of the binary matches the name of the Application.
|
# On OSX, the name of the binary matches the name of the Application.
|
||||||
@ -247,4 +247,7 @@ if (WIN32)
|
|||||||
endif ()
|
endif ()
|
||||||
else ()
|
else ()
|
||||||
install(TARGETS slic3r RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
install(TARGETS slic3r RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||||
|
|
||||||
|
# Install the symlink for gcodeviewer
|
||||||
|
install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink prusa-slicer prusa-gcodeviewer WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})")
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -40,23 +40,21 @@
|
|||||||
#include "libslic3r/Format/OBJ.hpp"
|
#include "libslic3r/Format/OBJ.hpp"
|
||||||
#include "libslic3r/Format/SL1.hpp"
|
#include "libslic3r/Format/SL1.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/AppConfig.hpp"
|
#include "libslic3r/Thread.hpp"
|
||||||
|
|
||||||
#include "PrusaSlicer.hpp"
|
#include "PrusaSlicer.hpp"
|
||||||
|
|
||||||
#ifdef SLIC3R_GUI
|
#ifdef SLIC3R_GUI
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI_Init.hpp"
|
||||||
#include "slic3r/GUI/GUI_App.hpp"
|
|
||||||
#include "slic3r/GUI/3DScene.hpp"
|
|
||||||
#include "slic3r/GUI/InstanceCheck.hpp"
|
|
||||||
#include "slic3r/GUI/MainFrame.hpp"
|
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
|
||||||
#endif /* SLIC3R_GUI */
|
#endif /* SLIC3R_GUI */
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
int CLI::run(int argc, char **argv)
|
int CLI::run(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
// Mark the main thread for the debugger and for runtime checks.
|
||||||
|
set_current_thread_name("slic3r_main");
|
||||||
|
|
||||||
#ifdef __WXGTK__
|
#ifdef __WXGTK__
|
||||||
// On Linux, wxGTK has no support for Wayland, and the app crashes on
|
// On Linux, wxGTK has no support for Wayland, and the app crashes on
|
||||||
// startup if gtk3 is used. This env var has to be set explicitly to
|
// startup if gtk3 is used. This env var has to be set explicitly to
|
||||||
@ -151,7 +149,7 @@ int CLI::run(int argc, char **argv)
|
|||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
for (const std::string& file : m_input_files) {
|
for (const std::string& file : m_input_files) {
|
||||||
std::string ext = boost::filesystem::path(file).extension().string();
|
std::string ext = boost::filesystem::path(file).extension().string();
|
||||||
if (boost::filesystem::path(file).extension().string() == ".gcode") {
|
if (ext == ".gcode" || ext == ".g") {
|
||||||
if (boost::filesystem::exists(file)) {
|
if (boost::filesystem::exists(file)) {
|
||||||
start_as_gcodeviewer = true;
|
start_as_gcodeviewer = true;
|
||||||
break;
|
break;
|
||||||
@ -573,75 +571,20 @@ int CLI::run(int argc, char **argv)
|
|||||||
|
|
||||||
if (start_gui) {
|
if (start_gui) {
|
||||||
#ifdef SLIC3R_GUI
|
#ifdef SLIC3R_GUI
|
||||||
// #ifdef USE_WX
|
Slic3r::GUI::GUI_InitParams params;
|
||||||
#if ENABLE_GCODE_VIEWER
|
params.argc = argc;
|
||||||
GUI::GUI_App* gui = new GUI::GUI_App(start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
|
params.argv = argv;
|
||||||
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
|
params.load_configs = load_configs;
|
||||||
// G-code viewer is currently not performing instance check, a new G-code viewer is started every time.
|
params.extra_config = std::move(m_extra_config);
|
||||||
bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1";
|
params.input_files = std::move(m_input_files);
|
||||||
if (Slic3r::instance_check(argc, argv, gui_single_instance_setting)) {
|
params.start_as_gcodeviewer = start_as_gcodeviewer;
|
||||||
//TODO: do we have delete gui and other stuff?
|
return Slic3r::GUI::GUI_Run(params);
|
||||||
return -1;
|
#else // SLIC3R_GUI
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
GUI::GUI_App *gui = new GUI::GUI_App();
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
|
|
||||||
// gui->autosave = m_config.opt_string("autosave");
|
|
||||||
GUI::GUI_App::SetInstance(gui);
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files, start_as_gcodeviewer);
|
|
||||||
#else
|
|
||||||
gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files);
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
/*
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
gui->CallAfter([gui, this, &load_configs, start_as_gcodeviewer] {
|
|
||||||
#else
|
|
||||||
gui->CallAfter([gui, this, &load_configs] {
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
if (!gui->initialized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
if (start_as_gcodeviewer) {
|
|
||||||
if (!m_input_files.empty())
|
|
||||||
gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str()));
|
|
||||||
} else {
|
|
||||||
#endif // ENABLE_GCODE_VIEWER_AS
|
|
||||||
#if 0
|
|
||||||
// Load the cummulative config over the currently active profiles.
|
|
||||||
//FIXME if multiple configs are loaded, only the last one will have an effect.
|
|
||||||
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
|
|
||||||
// As of now only the full configs are supported here.
|
|
||||||
if (!m_print_config.empty())
|
|
||||||
gui->mainframe->load_config(m_print_config);
|
|
||||||
#endif
|
|
||||||
if (!load_configs.empty())
|
|
||||||
// Load the last config to give it a name at the UI. The name of the preset may be later
|
|
||||||
// changed by loading an AMF or 3MF.
|
|
||||||
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
|
|
||||||
gui->mainframe->load_config_file(load_configs.back());
|
|
||||||
// If loading a 3MF file, the config is loaded from the last one.
|
|
||||||
if (!m_input_files.empty())
|
|
||||||
gui->plater()->load_files(m_input_files, true, true);
|
|
||||||
if (!m_extra_config.empty())
|
|
||||||
gui->mainframe->load_config(m_extra_config);
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
}
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
int result = wxEntry(argc, argv);
|
|
||||||
return result;
|
|
||||||
#else /* SLIC3R_GUI */
|
|
||||||
// No GUI support. Just print out a help.
|
// No GUI support. Just print out a help.
|
||||||
this->print_help(false);
|
this->print_help(false);
|
||||||
// If started without a parameter, consider it to be OK, otherwise report an error code (no action etc).
|
// If started without a parameter, consider it to be OK, otherwise report an error code (no action etc).
|
||||||
return (argc == 0) ? 0 : 1;
|
return (argc == 0) ? 0 : 1;
|
||||||
#endif /* SLIC3R_GUI */
|
#endif // SLIC3R_GUI
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -42,10 +42,16 @@
|
|||||||
#include <linux/hidraw.h>
|
#include <linux/hidraw.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <libudev.h>
|
|
||||||
|
|
||||||
#include "hidapi.h"
|
#include "hidapi.h"
|
||||||
|
|
||||||
|
// Declare udev structures needed in this module. They are passed by pointers
|
||||||
|
// to udev functions and not used directly.
|
||||||
|
struct udev_device;
|
||||||
|
struct udev_list_entry;
|
||||||
|
struct udev_enumerate;
|
||||||
|
struct udev;
|
||||||
|
|
||||||
typedef const char* (*hid_wrapper_udev_device_get_devnode_type)(struct udev_device *udev_device);
|
typedef const char* (*hid_wrapper_udev_device_get_devnode_type)(struct udev_device *udev_device);
|
||||||
typedef struct udev_device* (*hid_wrapper_udev_device_get_parent_with_subsystem_devtype_type)(struct udev_device *udev_device, const char *subsystem, const char *devtype);
|
typedef struct udev_device* (*hid_wrapper_udev_device_get_parent_with_subsystem_devtype_type)(struct udev_device *udev_device, const char *subsystem, const char *devtype);
|
||||||
typedef const char* (*hid_wrapper_udev_device_get_sysattr_value_type)(struct udev_device *udev_device, const char *sysattr);
|
typedef const char* (*hid_wrapper_udev_device_get_sysattr_value_type)(struct udev_device *udev_device, const char *sysattr);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "AppConfig.hpp"
|
#include "AppConfig.hpp"
|
||||||
#include "Exception.hpp"
|
#include "Exception.hpp"
|
||||||
|
#include "Thread.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -80,9 +81,9 @@ void AppConfig::set_defaults()
|
|||||||
set("single_instance",
|
set("single_instance",
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
"1"
|
"1"
|
||||||
#else __APPLE__
|
#else // __APPLE__
|
||||||
"0"
|
"0"
|
||||||
#endif __APPLE__
|
#endif // __APPLE__
|
||||||
);
|
);
|
||||||
|
|
||||||
if (get("remember_output_path").empty())
|
if (get("remember_output_path").empty())
|
||||||
@ -218,6 +219,13 @@ std::string AppConfig::load()
|
|||||||
|
|
||||||
void AppConfig::save()
|
void AppConfig::save()
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
// Returns "undefined" if the thread naming functionality is not supported by the operating system.
|
||||||
|
std::optional<std::string> current_thread_name = get_current_thread_name();
|
||||||
|
if (current_thread_name && *current_thread_name != "slic3r_main")
|
||||||
|
throw CriticalException("Calling AppConfig::save() from a worker thread!");
|
||||||
|
}
|
||||||
|
|
||||||
// The config is first written to a file with a PID suffix and then moved
|
// The config is first written to a file with a PID suffix and then moved
|
||||||
// to avoid race conditions with multiple instances of Slic3r
|
// to avoid race conditions with multiple instances of Slic3r
|
||||||
const auto path = config_path();
|
const auto path = config_path();
|
||||||
|
@ -209,6 +209,8 @@ add_library(libslic3r STATIC
|
|||||||
Utils.hpp
|
Utils.hpp
|
||||||
Time.cpp
|
Time.cpp
|
||||||
Time.hpp
|
Time.hpp
|
||||||
|
Thread.cpp
|
||||||
|
Thread.hpp
|
||||||
TriangleSelector.cpp
|
TriangleSelector.cpp
|
||||||
TriangleSelector.hpp
|
TriangleSelector.hpp
|
||||||
MTUtils.hpp
|
MTUtils.hpp
|
||||||
|
@ -828,7 +828,8 @@ void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_
|
|||||||
|
|
||||||
std::error_code err_code;
|
std::error_code err_code;
|
||||||
if (rename_file(path_tmp, path))
|
if (rename_file(path_tmp, path))
|
||||||
if (copy_file(path_tmp, path, true) != SUCCESS)
|
if (copy_file(path_tmp, path, ("Failed to rename the output G-code file from " + path_tmp + " to " + path + '\n' +
|
||||||
|
"Is " + path_tmp + " locked? " + err_code.message() + '\n'), true) != CopyFileResult::SUCCESS)
|
||||||
throw Slic3r::RuntimeError(
|
throw Slic3r::RuntimeError(
|
||||||
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
|
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
|
||||||
"Is " + path_tmp + " locked? " + err_code.message() + '\n');
|
"Is " + path_tmp + " locked? " + err_code.message() + '\n');
|
||||||
@ -1880,16 +1881,22 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
|
|||||||
while (*ptr != 0) {
|
while (*ptr != 0) {
|
||||||
// Skip whitespaces.
|
// Skip whitespaces.
|
||||||
for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
||||||
if (*ptr == 'M') {
|
if (*ptr == 'M' || // Line starts with 'M'. It is a machine command.
|
||||||
// Line starts with 'M'. It is a machine command.
|
(*ptr == 'G' && include_g10)) { // Only check for G10 if requested
|
||||||
|
bool is_gcode = *ptr == 'G';
|
||||||
++ ptr;
|
++ ptr;
|
||||||
// Parse the M code value.
|
// Parse the M or G code value.
|
||||||
char *endptr = nullptr;
|
char *endptr = nullptr;
|
||||||
int mcode = int(strtol(ptr, &endptr, 10));
|
int mgcode = int(strtol(ptr, &endptr, 10));
|
||||||
if (endptr != nullptr && endptr != ptr && (mcode == mcode_set_temp_dont_wait || mcode == mcode_set_temp_and_wait)) {
|
if (endptr != nullptr && endptr != ptr &&
|
||||||
|
is_gcode ?
|
||||||
|
// G10 found
|
||||||
|
mgcode == 10 :
|
||||||
// M104/M109 or M140/M190 found.
|
// M104/M109 or M140/M190 found.
|
||||||
|
(mgcode == mcode_set_temp_dont_wait || mgcode == mcode_set_temp_and_wait)) {
|
||||||
ptr = endptr;
|
ptr = endptr;
|
||||||
// Let the caller know that the custom G-code sets the temperature.
|
if (! is_gcode)
|
||||||
|
// Let the caller know that the custom M-code sets the temperature.
|
||||||
temp_set_by_gcode = true;
|
temp_set_by_gcode = true;
|
||||||
// Now try to parse the temperature value.
|
// Now try to parse the temperature value.
|
||||||
// While not at the end of the line:
|
// While not at the end of the line:
|
||||||
@ -1905,6 +1912,10 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
|
|||||||
if (endptr > ptr) {
|
if (endptr > ptr) {
|
||||||
ptr = endptr;
|
ptr = endptr;
|
||||||
temp_out = temp_parsed;
|
temp_out = temp_parsed;
|
||||||
|
// Let the caller know that the custom G-code sets the temperature
|
||||||
|
// Only do this after successfully parsing temperature since G10
|
||||||
|
// can be used for other reasons
|
||||||
|
temp_set_by_gcode = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Skip this word.
|
// Skip this word.
|
||||||
@ -1912,41 +1923,7 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (*ptr == 'G' && include_g10) { // Only check for G10 if requested
|
|
||||||
// Line starts with 'G'.
|
|
||||||
++ ptr;
|
|
||||||
// Parse the G code value.
|
|
||||||
char *endptr = nullptr;
|
|
||||||
int gcode = int(strtol(ptr, &endptr, 10));
|
|
||||||
if (endptr != nullptr && endptr != ptr && gcode == 10 /* G10 */) {
|
|
||||||
// G10 code found
|
|
||||||
ptr = endptr;
|
|
||||||
// Now try to parse the temperature value.
|
|
||||||
// While not at the end of the line:
|
|
||||||
while (strchr(";\r\n\0", *ptr) == nullptr) {
|
|
||||||
// Skip whitespaces.
|
|
||||||
for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
|
||||||
if (*ptr == 'S') {
|
|
||||||
// Skip whitespaces.
|
|
||||||
for (++ ptr; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
|
||||||
// Parse an int.
|
|
||||||
endptr = nullptr;
|
|
||||||
long temp_parsed = strtol(ptr, &endptr, 10);
|
|
||||||
if (endptr > ptr) {
|
|
||||||
ptr = endptr;
|
|
||||||
temp_out = temp_parsed;
|
|
||||||
// Let the caller know that the custom G-code sets the temperature
|
|
||||||
// Only do this after successfully parsing temperature since G10
|
|
||||||
// can be used for other reasons
|
|
||||||
temp_set_by_gcode = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Skip this word.
|
|
||||||
for (; strchr(" \t;\r\n\0", *ptr) == nullptr; ++ ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Skip the rest of the line.
|
// Skip the rest of the line.
|
||||||
for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr);
|
for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr);
|
||||||
// Skip the end of line indicators.
|
// Skip the end of line indicators.
|
||||||
@ -2035,11 +2012,13 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s
|
|||||||
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
||||||
// M104 - Set Extruder Temperature
|
// M104 - Set Extruder Temperature
|
||||||
// M109 - Set Extruder Temperature and Wait
|
// M109 - Set Extruder Temperature and Wait
|
||||||
|
// RepRapFirmware: G10 Sxx
|
||||||
void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||||
{
|
{
|
||||||
// Is the bed temperature set by the provided custom G-code?
|
// Is the bed temperature set by the provided custom G-code?
|
||||||
int temp_by_gcode = -1;
|
int temp_by_gcode = -1;
|
||||||
if (custom_gcode_sets_temperature(gcode, 104, 109, true, temp_by_gcode)) {
|
bool include_g10 = print.config().gcode_flavor == gcfRepRap;
|
||||||
|
if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
|
||||||
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
|
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
|
||||||
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
|
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
|
||||||
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||||
|
@ -400,7 +400,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
|||||||
const TimeMachine& machine = machines[i];
|
const TimeMachine& machine = machines[i];
|
||||||
if (machine.enabled && g1_lines_counter < machine.g1_times_cache.size()) {
|
if (machine.enabled && g1_lines_counter < machine.g1_times_cache.size()) {
|
||||||
float elapsed_time = machine.g1_times_cache[g1_lines_counter];
|
float elapsed_time = machine.g1_times_cache[g1_lines_counter];
|
||||||
std::pair<int, int> to_export = { int(::roundf(100.0f * elapsed_time / machine.time)),
|
std::pair<int, int> to_export = { int(100.0f * elapsed_time / machine.time),
|
||||||
time_in_minutes(machine.time - elapsed_time) };
|
time_in_minutes(machine.time - elapsed_time) };
|
||||||
if (last_exported[i] != to_export) {
|
if (last_exported[i] != to_export) {
|
||||||
export_line += format_line_M73(machine.line_m73_mask.c_str(),
|
export_line += format_line_M73(machine.line_m73_mask.c_str(),
|
||||||
@ -461,7 +461,8 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
|
|||||||
|
|
||||||
std::error_code err_code;
|
std::error_code err_code;
|
||||||
if (err_code = rename_file(out_path, filename))
|
if (err_code = rename_file(out_path, filename))
|
||||||
if(copy_file(out_path, filename, true) != SUCCESS)
|
if(copy_file(out_path, filename, (std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' +
|
||||||
|
"Is " + out_path + " locked? (gcp)" + err_code.message() + '\n'), true) != SUCCESS)
|
||||||
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' +
|
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' +
|
||||||
"Is " + out_path + " locked? (gcp)" + err_code.message() + '\n');
|
"Is " + out_path + " locked? (gcp)" + err_code.message() + '\n');
|
||||||
}
|
}
|
||||||
@ -691,7 +692,7 @@ void GCodeProcessor::reset()
|
|||||||
m_global_positioning_type = EPositioningType::Absolute;
|
m_global_positioning_type = EPositioningType::Absolute;
|
||||||
m_e_local_positioning_type = EPositioningType::Absolute;
|
m_e_local_positioning_type = EPositioningType::Absolute;
|
||||||
m_extruder_offsets = std::vector<Vec3f>(Min_Extruder_Count, Vec3f::Zero());
|
m_extruder_offsets = std::vector<Vec3f>(Min_Extruder_Count, Vec3f::Zero());
|
||||||
m_flavor = gcfRepRap;
|
m_flavor = gcfSprinter;
|
||||||
|
|
||||||
m_start_position = { 0.0f, 0.0f, 0.0f, 0.0f };
|
m_start_position = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f };
|
m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
@ -1128,6 +1129,8 @@ bool GCodeProcessor::process_cura_tags(const std::string& comment)
|
|||||||
m_flavor = gcfRepetier;
|
m_flavor = gcfRepetier;
|
||||||
else if (flavor == "RepRap")
|
else if (flavor == "RepRap")
|
||||||
m_flavor = gcfRepRap;
|
m_flavor = gcfRepRap;
|
||||||
|
else if (flavor == "Sprinter")
|
||||||
|
m_flavor = gcfSprinter;
|
||||||
else if (flavor == "Marlin")
|
else if (flavor == "Marlin")
|
||||||
m_flavor = gcfMarlin;
|
m_flavor = gcfMarlin;
|
||||||
else
|
else
|
||||||
@ -1832,7 +1835,7 @@ void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||||
float factor = (m_flavor != gcfRepRap && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
|
float factor = ((m_flavor != gcfSprinter && m_flavor != gcfRepRap) && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
|
||||||
|
|
||||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||||
if (line.has_x())
|
if (line.has_x())
|
||||||
|
@ -100,7 +100,7 @@ std::string GCodeWriter::set_temperature(const unsigned int temperature, bool wa
|
|||||||
return "";
|
return "";
|
||||||
|
|
||||||
std::string code, comment;
|
std::string code, comment;
|
||||||
if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRap) && FLAVOR_IS_NOT(gcfSprinter)) {
|
if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRap)) {
|
||||||
code = "M109";
|
code = "M109";
|
||||||
comment = "set temperature and wait for it to be reached";
|
comment = "set temperature and wait for it to be reached";
|
||||||
} else {
|
} else {
|
||||||
@ -124,7 +124,9 @@ std::string GCodeWriter::set_temperature(const unsigned int temperature, bool wa
|
|||||||
gcode << temp_w_offset;
|
gcode << temp_w_offset;
|
||||||
bool multiple_tools = this->multiple_extruders && ! m_single_extruder_multi_material;
|
bool multiple_tools = this->multiple_extruders && ! m_single_extruder_multi_material;
|
||||||
if (tool != -1 && (multiple_tools || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
|
if (tool != -1 && (multiple_tools || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
|
||||||
if (FLAVOR_IS_NOT(gcfRepRap)) {
|
if (FLAVOR_IS(gcfRepRap)) {
|
||||||
|
gcode << " P" << tool;
|
||||||
|
} else {
|
||||||
gcode << " T" << tool;
|
gcode << " T" << tool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <CGAL/Exact_integer.h>
|
#include <CGAL/Exact_integer.h>
|
||||||
#include <CGAL/Surface_mesh.h>
|
#include <CGAL/Surface_mesh.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
|
||||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/remesh.h>
|
#include <CGAL/Polygon_mesh_processing/remesh.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||||
|
@ -1055,6 +1055,7 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial
|
|||||||
|
|
||||||
ModelVolume* vol = new_object->add_volume(mesh);
|
ModelVolume* vol = new_object->add_volume(mesh);
|
||||||
vol->name = volume->name;
|
vol->name = volume->name;
|
||||||
|
vol->set_type(volume->type());
|
||||||
// Don't copy the config's ID.
|
// Don't copy the config's ID.
|
||||||
vol->config.assign_config(volume->config);
|
vol->config.assign_config(volume->config);
|
||||||
assert(vol->config.id().valid());
|
assert(vol->config.id().valid());
|
||||||
@ -1065,7 +1066,7 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial
|
|||||||
if (volume_idxs.empty() ||
|
if (volume_idxs.empty() ||
|
||||||
std::find(volume_idxs.begin(), volume_idxs.end(), vol_idx) != volume_idxs.end()) {
|
std::find(volume_idxs.begin(), volume_idxs.end(), vol_idx) != volume_idxs.end()) {
|
||||||
vol->scale_geometry_after_creation(versor);
|
vol->scale_geometry_after_creation(versor);
|
||||||
vol->set_offset(versor.cwiseProduct(vol->get_offset()));
|
vol->set_offset(versor.cwiseProduct(volume->get_offset()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
vol->set_offset(volume->get_offset());
|
vol->set_offset(volume->get_offset());
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "ShortestPath.hpp"
|
#include "ShortestPath.hpp"
|
||||||
#include "SupportMaterial.hpp"
|
#include "SupportMaterial.hpp"
|
||||||
|
#include "Thread.hpp"
|
||||||
#include "GCode.hpp"
|
#include "GCode.hpp"
|
||||||
#include "GCode/WipeTower.hpp"
|
#include "GCode/WipeTower.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
@ -1696,6 +1697,8 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
|
|||||||
// Slicing process, running at a background thread.
|
// Slicing process, running at a background thread.
|
||||||
void Print::process()
|
void Print::process()
|
||||||
{
|
{
|
||||||
|
name_tbb_thread_pool_threads();
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
||||||
for (PrintObject *obj : m_objects)
|
for (PrintObject *obj : m_objects)
|
||||||
obj->make_perimeters();
|
obj->make_perimeters();
|
||||||
|
@ -38,17 +38,18 @@ namespace FillAdaptive {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Print step IDs for keeping track of the print state.
|
// Print step IDs for keeping track of the print state.
|
||||||
|
// The Print steps are applied in this order.
|
||||||
enum PrintStep {
|
enum PrintStep {
|
||||||
psSkirt,
|
|
||||||
psBrim,
|
|
||||||
// Synonym for the last step before the Wipe Tower / Tool Ordering, for the G-code preview slider to understand that
|
|
||||||
// all the extrusions are there for the layer slider to add color changes etc.
|
|
||||||
psExtrusionPaths = psBrim,
|
|
||||||
psWipeTower,
|
psWipeTower,
|
||||||
|
// Ordering of the tools on PrintObjects for a multi-material print.
|
||||||
// psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering,
|
// psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering,
|
||||||
// while if printing without the Wipe Tower, the ToolOrdering is calculated as well.
|
// while if printing without the Wipe Tower, the ToolOrdering is calculated as well.
|
||||||
psToolOrdering = psWipeTower,
|
psToolOrdering = psWipeTower,
|
||||||
psSlicingFinished = psToolOrdering,
|
psSkirt,
|
||||||
|
psBrim,
|
||||||
|
// Last step before G-code export, after this step is finished, the initial extrusion path preview
|
||||||
|
// should be refreshed.
|
||||||
|
psSlicingFinished = psBrim,
|
||||||
psGCodeExport,
|
psGCodeExport,
|
||||||
psCount,
|
psCount,
|
||||||
};
|
};
|
||||||
|
@ -1778,7 +1778,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->enum_values.push_back("sprinter");
|
def->enum_values.push_back("sprinter");
|
||||||
def->enum_values.push_back("lerdge");
|
def->enum_values.push_back("lerdge");
|
||||||
def->enum_values.push_back("no-extrusion");
|
def->enum_values.push_back("no-extrusion");
|
||||||
def->enum_labels.push_back("RepRap");
|
def->enum_labels.push_back("RepRapFirmware");
|
||||||
def->enum_labels.push_back("Repetier");
|
def->enum_labels.push_back("Repetier");
|
||||||
def->enum_labels.push_back("Teacup");
|
def->enum_labels.push_back("Teacup");
|
||||||
def->enum_labels.push_back("MakerWare (MakerBot)");
|
def->enum_labels.push_back("MakerWare (MakerBot)");
|
||||||
@ -1792,7 +1792,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->enum_labels.push_back("Lerdge");
|
def->enum_labels.push_back("Lerdge");
|
||||||
def->enum_labels.push_back(L("No extrusion"));
|
def->enum_labels.push_back(L("No extrusion"));
|
||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionEnum<GCodeFlavor>(gcfRepRap));
|
def->set_default_value(new ConfigOptionEnum<GCodeFlavor>(gcfSprinter));
|
||||||
|
|
||||||
def = this->add("gcode_label_objects", coBool);
|
def = this->add("gcode_label_objects", coBool);
|
||||||
def->label = L("Label objects");
|
def->label = L("Label objects");
|
||||||
|
@ -861,14 +861,14 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
|
|||||||
|
|
||||||
// propagate to dependent steps
|
// propagate to dependent steps
|
||||||
if (step == posPerimeters) {
|
if (step == posPerimeters) {
|
||||||
invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill });
|
invalidated |= this->invalidate_steps({ posPrepareInfill, posInfill, posIroning });
|
||||||
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
||||||
} else if (step == posPrepareInfill) {
|
} else if (step == posPrepareInfill) {
|
||||||
invalidated |= this->invalidate_step(posInfill);
|
invalidated |= this->invalidate_steps({ posInfill, posIroning });
|
||||||
} else if (step == posInfill) {
|
} else if (step == posInfill) {
|
||||||
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
||||||
} else if (step == posSlice) {
|
} else if (step == posSlice) {
|
||||||
invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posSupportMaterial });
|
invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posIroning, posSupportMaterial });
|
||||||
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
||||||
this->m_slicing_params.valid = false;
|
this->m_slicing_params.valid = false;
|
||||||
} else if (step == posSupportMaterial) {
|
} else if (step == posSupportMaterial) {
|
||||||
@ -2228,12 +2228,6 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||||||
|
|
||||||
m_typed_slices = false;
|
m_typed_slices = false;
|
||||||
|
|
||||||
#ifdef SLIC3R_PROFILE
|
|
||||||
// Disable parallelization so the Shiny profiler works
|
|
||||||
static tbb::task_scheduler_init *tbb_init = nullptr;
|
|
||||||
tbb_init = new tbb::task_scheduler_init(1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 1) Initialize layers and their slice heights.
|
// 1) Initialize layers and their slice heights.
|
||||||
std::vector<float> slice_zs;
|
std::vector<float> slice_zs;
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "MTUtils.hpp"
|
#include "MTUtils.hpp"
|
||||||
|
#include "Thread.hpp"
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@ -689,7 +690,10 @@ bool SLAPrint::invalidate_step(SLAPrintStep step)
|
|||||||
|
|
||||||
void SLAPrint::process()
|
void SLAPrint::process()
|
||||||
{
|
{
|
||||||
if(m_objects.empty()) return;
|
if (m_objects.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
name_tbb_thread_pool_threads();
|
||||||
|
|
||||||
// Assumption: at this point the print objects should be populated only with
|
// Assumption: at this point the print objects should be populated only with
|
||||||
// the model objects we have to process and the instances are also filtered
|
// the model objects we have to process and the instances are also filtered
|
||||||
|
@ -57,4 +57,5 @@
|
|||||||
#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
|
#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
|
||||||
#define ENABLE_GCODE_VIEWER_DATA_CHECKING (0 && ENABLE_GCODE_VIEWER)
|
#define ENABLE_GCODE_VIEWER_DATA_CHECKING (0 && ENABLE_GCODE_VIEWER)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
238
src/libslic3r/Thread.cpp
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <boost/nowide/convert.hpp>
|
||||||
|
#else
|
||||||
|
// any posix system
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
|
#include <tbb/tbb_thread.h>
|
||||||
|
#include <tbb/task_scheduler_init.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "Thread.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// The new API is better than the old SEH style thread naming since the names also show up in crash dumpsand ETW traces.
|
||||||
|
// Because the new API is only available on newer Windows 10, look it up dynamically.
|
||||||
|
|
||||||
|
typedef HRESULT(__stdcall* SetThreadDescriptionType)(HANDLE, PCWSTR);
|
||||||
|
typedef HRESULT(__stdcall* GetThreadDescriptionType)(HANDLE, PWSTR*);
|
||||||
|
|
||||||
|
static bool s_SetGetThreadDescriptionInitialized = false;
|
||||||
|
static HMODULE s_hKernel32 = nullptr;
|
||||||
|
static SetThreadDescriptionType s_fnSetThreadDescription = nullptr;
|
||||||
|
static GetThreadDescriptionType s_fnGetThreadDescription = nullptr;
|
||||||
|
|
||||||
|
static bool WindowsGetSetThreadNameAPIInitialize()
|
||||||
|
{
|
||||||
|
if (! s_SetGetThreadDescriptionInitialized) {
|
||||||
|
// Not thread safe! It is therefore a good idea to name the main thread before spawning worker threads
|
||||||
|
// to initialize
|
||||||
|
s_hKernel32 = LoadLibraryW(L"Kernel32.dll");
|
||||||
|
if (s_hKernel32) {
|
||||||
|
s_fnSetThreadDescription = (SetThreadDescriptionType)::GetProcAddress(s_hKernel32, "SetThreadDescription");
|
||||||
|
s_fnGetThreadDescription = (GetThreadDescriptionType)::GetProcAddress(s_hKernel32, "GetThreadDescription");
|
||||||
|
}
|
||||||
|
s_SetGetThreadDescriptionInitialized = true;
|
||||||
|
}
|
||||||
|
return s_fnSetThreadDescription && s_fnGetThreadDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Use the old way by throwing an exception, so at least in Debug mode the thread names are shown by the debugger.
|
||||||
|
static constexpr DWORD MSVC_SEH_EXCEPTION_NAME_THREAD = 0x406D1388;
|
||||||
|
|
||||||
|
#pragma pack(push,8)
|
||||||
|
typedef struct tagTHREADNAME_INFO
|
||||||
|
{
|
||||||
|
DWORD dwType; // Must be 0x1000.
|
||||||
|
LPCSTR szName; // Pointer to name (in user addr space).
|
||||||
|
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||||
|
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||||
|
} THREADNAME_INFO;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static void WindowsSetThreadNameSEH(HANDLE hThread, const char* thread_name)
|
||||||
|
{
|
||||||
|
THREADNAME_INFO info;
|
||||||
|
info.dwType = 0x1000;
|
||||||
|
info.szName = thread_name;
|
||||||
|
info.dwThreadID = ::GetThreadId(hThread);
|
||||||
|
info.dwFlags = 0;
|
||||||
|
__try {
|
||||||
|
RaiseException(MSVC_SEH_EXCEPTION_NAME_THREAD, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
static bool WindowsSetThreadName(HANDLE hThread, const char *thread_name)
|
||||||
|
{
|
||||||
|
if (! WindowsGetSetThreadNameAPIInitialize()) {
|
||||||
|
#ifdef NDEBUG
|
||||||
|
return false;
|
||||||
|
#else // NDEBUG
|
||||||
|
// Running on Windows 7 or old Windows 7 in debug mode,
|
||||||
|
// inform the debugger about the thread name by throwing an SEH.
|
||||||
|
WindowsSetThreadNameSEH(hThread, thread_name);
|
||||||
|
return true;
|
||||||
|
#endif // NDEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(thread_name);
|
||||||
|
if (len < 1024) {
|
||||||
|
// Allocate the temp string on stack.
|
||||||
|
wchar_t buf[1024];
|
||||||
|
s_fnSetThreadDescription(hThread, boost::nowide::widen(buf, 1024, thread_name));
|
||||||
|
} else {
|
||||||
|
// Allocate dynamically.
|
||||||
|
s_fnSetThreadDescription(hThread, boost::nowide::widen(thread_name).c_str());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_thread_name(std::thread &thread, const char *thread_name)
|
||||||
|
{
|
||||||
|
return WindowsSetThreadName(static_cast<HANDLE>(thread.native_handle()), thread_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_thread_name(boost::thread &thread, const char *thread_name)
|
||||||
|
{
|
||||||
|
return WindowsSetThreadName(static_cast<HANDLE>(thread.native_handle()), thread_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_current_thread_name(const char *thread_name)
|
||||||
|
{
|
||||||
|
return WindowsSetThreadName(::GetCurrentThread(), thread_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_current_thread_name()
|
||||||
|
{
|
||||||
|
if (! WindowsGetSetThreadNameAPIInitialize())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
wchar_t *ptr = nullptr;
|
||||||
|
s_fnGetThreadDescription(::GetCurrentThread(), &ptr);
|
||||||
|
return (ptr == nullptr) ? std::string() : boost::nowide::narrow(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
// Appe screwed the Posix norm.
|
||||||
|
bool set_thread_name(std::thread &thread, const char *thread_name)
|
||||||
|
{
|
||||||
|
// not supported
|
||||||
|
// pthread_setname_np(thread.native_handle(), thread_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_thread_name(boost::thread &thread, const char *thread_name)
|
||||||
|
{
|
||||||
|
// not supported
|
||||||
|
// pthread_setname_np(thread.native_handle(), thread_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_current_thread_name(const char *thread_name)
|
||||||
|
{
|
||||||
|
pthread_setname_np(thread_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_current_thread_name()
|
||||||
|
{
|
||||||
|
// not supported
|
||||||
|
// char buf[16];
|
||||||
|
// return std::string(thread_getname_np(buf, 16) == 0 ? buf : "");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// posix
|
||||||
|
bool set_thread_name(std::thread &thread, const char *thread_name)
|
||||||
|
{
|
||||||
|
pthread_setname_np(thread.native_handle(), thread_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_thread_name(boost::thread &thread, const char *thread_name)
|
||||||
|
{
|
||||||
|
pthread_setname_np(thread.native_handle(), thread_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_current_thread_name(const char *thread_name)
|
||||||
|
{
|
||||||
|
pthread_setname_np(pthread_self(), thread_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_current_thread_name()
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
return std::string(pthread_getname_np(pthread_self(), buf, 16) == 0 ? buf : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
// Spawn (n - 1) worker threads on Intel TBB thread pool and name them by an index and a system thread ID.
|
||||||
|
void name_tbb_thread_pool_threads()
|
||||||
|
{
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized)
|
||||||
|
return;
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
const size_t nthreads_hw = std::thread::hardware_concurrency();
|
||||||
|
size_t nthreads = nthreads_hw;
|
||||||
|
|
||||||
|
#ifdef SLIC3R_PROFILE
|
||||||
|
// Shiny profiler is not thread safe, thus disable parallelization.
|
||||||
|
nthreads = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (nthreads != nthreads_hw)
|
||||||
|
new tbb::task_scheduler_init(int(nthreads));
|
||||||
|
|
||||||
|
std::atomic<size_t> nthreads_running(0);
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::mutex cv_m;
|
||||||
|
auto master_thread_id = tbb::this_tbb_thread::get_id();
|
||||||
|
tbb::parallel_for(
|
||||||
|
tbb::blocked_range<size_t>(0, nthreads, 1),
|
||||||
|
[&nthreads_running, nthreads, &master_thread_id, &cv, &cv_m](const tbb::blocked_range<size_t> &range) {
|
||||||
|
assert(range.begin() + 1 == range.end());
|
||||||
|
if (nthreads_running.fetch_add(1) + 1 == nthreads) {
|
||||||
|
// All threads are spinning.
|
||||||
|
// Wake them up.
|
||||||
|
cv.notify_all();
|
||||||
|
} else {
|
||||||
|
// Wait for the last thread to wake the others.
|
||||||
|
std::unique_lock<std::mutex> lk(cv_m);
|
||||||
|
cv.wait(lk, [&nthreads_running, nthreads]{return nthreads_running == nthreads;});
|
||||||
|
}
|
||||||
|
auto thread_id = tbb::this_tbb_thread::get_id();
|
||||||
|
if (thread_id == master_thread_id) {
|
||||||
|
// The calling thread runs the 0'th task.
|
||||||
|
assert(range.begin() == 0);
|
||||||
|
} else {
|
||||||
|
assert(range.begin() > 0);
|
||||||
|
std::ostringstream name;
|
||||||
|
name << "slic3r_tbb_" << range.begin();
|
||||||
|
set_current_thread_name(name.str().c_str());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
src/libslic3r/Thread.hpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef GUI_THREAD_HPP
|
||||||
|
#define GUI_THREAD_HPP
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
// Set / get thread name.
|
||||||
|
// Returns false if the API is not supported.
|
||||||
|
//
|
||||||
|
// It is a good idea to name the main thread before spawning children threads, because dynamic linking is used on Windows 10
|
||||||
|
// to initialize Get/SetThreadDescription functions, which is not thread safe.
|
||||||
|
//
|
||||||
|
// pthread_setname_np supports maximum 15 character thread names! (16th character is the null terminator)
|
||||||
|
//
|
||||||
|
// Methods taking the thread as an argument are not supported by OSX.
|
||||||
|
// Naming threads is only supported on newer Windows 10.
|
||||||
|
|
||||||
|
bool set_thread_name(std::thread &thread, const char *thread_name);
|
||||||
|
inline bool set_thread_name(std::thread &thread, const std::string &thread_name) { return set_thread_name(thread, thread_name.c_str()); }
|
||||||
|
bool set_thread_name(boost::thread &thread, const char *thread_name);
|
||||||
|
inline bool set_thread_name(boost::thread &thread, const std::string &thread_name) { return set_thread_name(thread, thread_name.c_str()); }
|
||||||
|
bool set_current_thread_name(const char *thread_name);
|
||||||
|
inline bool set_current_thread_name(const std::string &thread_name) { return set_current_thread_name(thread_name.c_str()); }
|
||||||
|
|
||||||
|
// Returns nullopt if not supported.
|
||||||
|
// Not supported by OSX.
|
||||||
|
// Naming threads is only supported on newer Windows 10.
|
||||||
|
std::optional<std::string> get_current_thread_name();
|
||||||
|
|
||||||
|
// To be called somewhere before the TBB threads are spinned for the first time, to
|
||||||
|
// give them names recognizible in the debugger.
|
||||||
|
void name_tbb_thread_pool_threads();
|
||||||
|
|
||||||
|
template<class Fn>
|
||||||
|
inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn)
|
||||||
|
{
|
||||||
|
// Duplicating the stack allocation size of Thread Building Block worker
|
||||||
|
// threads of the thread pool: allocate 4MB on a 64bit system, allocate 2MB
|
||||||
|
// on a 32bit system by default.
|
||||||
|
|
||||||
|
attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024));
|
||||||
|
return boost::thread{attrs, std::forward<Fn>(fn)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Fn> inline boost::thread create_thread(Fn &&fn)
|
||||||
|
{
|
||||||
|
boost::thread::attributes attrs;
|
||||||
|
return create_thread(attrs, std::forward<Fn>(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GUI_THREAD_HPP
|
@ -7,6 +7,8 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
|
|
||||||
namespace boost { namespace filesystem { class directory_entry; }}
|
namespace boost { namespace filesystem { class directory_entry; }}
|
||||||
@ -73,11 +75,12 @@ enum CopyFileResult {
|
|||||||
FAIL_CHECK_TARGET_NOT_OPENED
|
FAIL_CHECK_TARGET_NOT_OPENED
|
||||||
};
|
};
|
||||||
// Copy a file, adjust the access attributes, so that the target is writable.
|
// Copy a file, adjust the access attributes, so that the target is writable.
|
||||||
CopyFileResult copy_file_inner(const std::string &from, const std::string &to);
|
CopyFileResult copy_file_inner(const std::string &from, const std::string &to, std::string& error_message);
|
||||||
// Copy file to a temp file first, then rename it to the final file name.
|
// Copy file to a temp file first, then rename it to the final file name.
|
||||||
// If with_check is true, then the content of the copied file is compared to the content
|
// If with_check is true, then the content of the copied file is compared to the content
|
||||||
// of the source file before renaming.
|
// of the source file before renaming.
|
||||||
extern CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check = false);
|
// Additional error info is passed in error message.
|
||||||
|
extern CopyFileResult copy_file(const std::string &from, const std::string &to, std::string& error_message, const bool with_check = false);
|
||||||
|
|
||||||
// Compares two files if identical.
|
// Compares two files if identical.
|
||||||
extern CopyFileResult check_copy(const std::string& origin, const std::string& copy);
|
extern CopyFileResult check_copy(const std::string& origin, const std::string& copy);
|
||||||
|
@ -417,7 +417,7 @@ std::error_code rename_file(const std::string &from, const std::string &to)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyFileResult copy_file_inner(const std::string& from, const std::string& to)
|
CopyFileResult copy_file_inner(const std::string& from, const std::string& to, std::string& error_message)
|
||||||
{
|
{
|
||||||
const boost::filesystem::path source(from);
|
const boost::filesystem::path source(from);
|
||||||
const boost::filesystem::path target(to);
|
const boost::filesystem::path target(to);
|
||||||
@ -429,20 +429,31 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to)
|
|||||||
// the copy_file() function will fail appropriately and we don't want the permission()
|
// the copy_file() function will fail appropriately and we don't want the permission()
|
||||||
// calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.)
|
// calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.)
|
||||||
// or when the target file doesn't exist.
|
// or when the target file doesn't exist.
|
||||||
|
|
||||||
|
//This error code is ignored
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
|
|
||||||
boost::filesystem::permissions(target, perms, ec);
|
boost::filesystem::permissions(target, perms, ec);
|
||||||
|
//if (ec)
|
||||||
|
// BOOST_LOG_TRIVIAL(error) << "Copy file permisions before copy error message: " << ec.message();
|
||||||
|
// This error code is passed up
|
||||||
|
ec.clear();
|
||||||
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
|
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
|
error_message = ec.message();
|
||||||
return FAIL_COPY_FILE;
|
return FAIL_COPY_FILE;
|
||||||
}
|
}
|
||||||
|
//ec.clear();
|
||||||
boost::filesystem::permissions(target, perms, ec);
|
boost::filesystem::permissions(target, perms, ec);
|
||||||
|
//if (ec)
|
||||||
|
// BOOST_LOG_TRIVIAL(error) << "Copy file permisions after copy error message: " << ec.message();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check)
|
CopyFileResult copy_file(const std::string &from, const std::string &to, std::string& error_message, const bool with_check)
|
||||||
{
|
{
|
||||||
std::string to_temp = to + ".tmp";
|
std::string to_temp = to + ".tmp";
|
||||||
CopyFileResult ret_val = copy_file_inner(from,to_temp);
|
CopyFileResult ret_val = copy_file_inner(from, to_temp, error_message);
|
||||||
if(ret_val == SUCCESS)
|
if(ret_val == SUCCESS)
|
||||||
{
|
{
|
||||||
if (with_check)
|
if (with_check)
|
||||||
|
9
src/platform/unix/PrusaSlicer.desktop
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=PrusaSlicer
|
||||||
|
Exec=prusa-slicer %F
|
||||||
|
Icon=PrusaSlicer
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;
|
||||||
|
Categories=Graphics;3DGraphics;
|
||||||
|
Keywords=3D;Printing;Slicer;
|
@ -91,6 +91,8 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/PresetHints.hpp
|
GUI/PresetHints.hpp
|
||||||
GUI/GUI.cpp
|
GUI/GUI.cpp
|
||||||
GUI/GUI.hpp
|
GUI/GUI.hpp
|
||||||
|
GUI/GUI_Init.cpp
|
||||||
|
GUI/GUI_Init.hpp
|
||||||
GUI/GUI_Preview.cpp
|
GUI/GUI_Preview.cpp
|
||||||
GUI/GUI_Preview.hpp
|
GUI/GUI_Preview.hpp
|
||||||
GUI/GUI_App.cpp
|
GUI/GUI_App.cpp
|
||||||
@ -105,6 +107,8 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/Plater.hpp
|
GUI/Plater.hpp
|
||||||
GUI/PresetComboBoxes.hpp
|
GUI/PresetComboBoxes.hpp
|
||||||
GUI/PresetComboBoxes.cpp
|
GUI/PresetComboBoxes.cpp
|
||||||
|
GUI/SavePresetDialog.hpp
|
||||||
|
GUI/SavePresetDialog.cpp
|
||||||
GUI/PhysicalPrinterDialog.hpp
|
GUI/PhysicalPrinterDialog.hpp
|
||||||
GUI/PhysicalPrinterDialog.cpp
|
GUI/PhysicalPrinterDialog.cpp
|
||||||
GUI/GUI_ObjectList.cpp
|
GUI/GUI_ObjectList.cpp
|
||||||
@ -220,7 +224,6 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
Utils/UndoRedo.hpp
|
Utils/UndoRedo.hpp
|
||||||
Utils/HexFile.cpp
|
Utils/HexFile.cpp
|
||||||
Utils/HexFile.hpp
|
Utils/HexFile.hpp
|
||||||
Utils/Thread.hpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "libslic3r/GCode/PreviewData.hpp"
|
#include "libslic3r/GCode/PreviewData.hpp"
|
||||||
#endif // !ENABLE_GCODE_VIEWER
|
#endif // !ENABLE_GCODE_VIEWER
|
||||||
#include "libslic3r/Format/SL1.hpp"
|
#include "libslic3r/Format/SL1.hpp"
|
||||||
|
#include "libslic3r/Thread.hpp"
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -36,7 +37,6 @@
|
|||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "RemovableDriveManager.hpp"
|
#include "RemovableDriveManager.hpp"
|
||||||
|
|
||||||
#include "slic3r/Utils/Thread.hpp"
|
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@ -45,7 +45,7 @@ bool SlicingProcessCompletedEvent::critical_error() const
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
this->rethrow_exception();
|
this->rethrow_exception();
|
||||||
} catch (const Slic3r::SlicingError &ex) {
|
} catch (const Slic3r::SlicingError &) {
|
||||||
// Exception derived from SlicingError is non-critical.
|
// Exception derived from SlicingError is non-critical.
|
||||||
return false;
|
return false;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -138,11 +138,12 @@ void BackgroundSlicingProcess::process_fff()
|
|||||||
//FIXME localize the messages
|
//FIXME localize the messages
|
||||||
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
||||||
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
|
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
|
||||||
int copy_ret_val = copy_file(m_temp_output_path, export_path, m_export_path_on_removable_media);
|
std::string error_message;
|
||||||
|
int copy_ret_val = copy_file(m_temp_output_path, export_path, error_message, m_export_path_on_removable_media);
|
||||||
switch (copy_ret_val) {
|
switch (copy_ret_val) {
|
||||||
case SUCCESS: break; // no error
|
case SUCCESS: break; // no error
|
||||||
case FAIL_COPY_FILE:
|
case FAIL_COPY_FILE:
|
||||||
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
|
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
|
||||||
break;
|
break;
|
||||||
case FAIL_FILES_DIFFERENT:
|
case FAIL_FILES_DIFFERENT:
|
||||||
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
|
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
|
||||||
@ -157,7 +158,8 @@ void BackgroundSlicingProcess::process_fff()
|
|||||||
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
|
throw Slic3r::RuntimeError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
|
throw Slic3r::RuntimeError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,6 +234,9 @@ void BackgroundSlicingProcess::process_sla()
|
|||||||
|
|
||||||
void BackgroundSlicingProcess::thread_proc()
|
void BackgroundSlicingProcess::thread_proc()
|
||||||
{
|
{
|
||||||
|
set_current_thread_name("slic3r_BgSlcPcs");
|
||||||
|
name_tbb_thread_pool_threads();
|
||||||
|
|
||||||
assert(m_print != nullptr);
|
assert(m_print != nullptr);
|
||||||
assert(m_print == m_fff_print || m_print == m_sla_print);
|
assert(m_print == m_fff_print || m_print == m_sla_print);
|
||||||
std::unique_lock<std::mutex> lck(m_mutex);
|
std::unique_lock<std::mutex> lck(m_mutex);
|
||||||
@ -527,7 +532,8 @@ void BackgroundSlicingProcess::prepare_upload()
|
|||||||
|
|
||||||
if (m_print == m_fff_print) {
|
if (m_print == m_fff_print) {
|
||||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||||
if (copy_file(m_temp_output_path, source_path.string()) != SUCCESS) {
|
std::string error_message;
|
||||||
|
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS) {
|
||||||
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
|
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
|
||||||
}
|
}
|
||||||
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
run_post_process_scripts(source_path.string(), m_fff_print->config());
|
||||||
|
@ -916,7 +916,7 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
|||||||
const std::string& type = list_type->get_data(sel_type);
|
const std::string& type = list_type->get_data(sel_type);
|
||||||
const std::string& vendor = list_vendor->get_data(sel_vendor);
|
const std::string& vendor = list_vendor->get_data(sel_vendor);
|
||||||
// finst printer preset
|
// finst printer preset
|
||||||
std::vector<std::pair<std::reference_wrapper<const std::string>, bool>> to_list;
|
std::vector<ProfilePrintData> to_list;
|
||||||
for (size_t i = 0; i < sel_printers_count; i++) {
|
for (size_t i = 0; i < sel_printers_count; i++) {
|
||||||
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
||||||
const Preset* printer = nullptr;
|
const Preset* printer = nullptr;
|
||||||
@ -931,16 +931,19 @@ void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
|||||||
bool was_checked = false;
|
bool was_checked = false;
|
||||||
//size_t printer_counter = materials->get_printer_counter(p);
|
//size_t printer_counter = materials->get_printer_counter(p);
|
||||||
int cur_i = list_profile->find(p->alias);
|
int cur_i = list_profile->find(p->alias);
|
||||||
|
bool emplace_to_to_list = false;
|
||||||
if (cur_i == wxNOT_FOUND) {
|
if (cur_i == wxNOT_FOUND) {
|
||||||
cur_i = list_profile->append(p->alias + (materials->get_omnipresent(p) ? "" : " *"), &p->alias);
|
cur_i = list_profile->append(p->alias + (materials->get_omnipresent(p) ? "" : " *"), &p->alias);
|
||||||
to_list.emplace_back(p->alias, materials->get_omnipresent(p));
|
emplace_to_to_list = true;
|
||||||
} else
|
} else
|
||||||
was_checked = list_profile->IsChecked(cur_i);
|
was_checked = list_profile->IsChecked(cur_i);
|
||||||
|
|
||||||
const std::string& section = materials->appconfig_section();
|
const std::string& section = materials->appconfig_section();
|
||||||
|
|
||||||
const bool checked = wizard_p()->appconfig_new.has(section, p->name);
|
const bool checked = wizard_p()->appconfig_new.has(section, p->name);
|
||||||
list_profile->Check(cur_i, checked | was_checked);
|
list_profile->Check(cur_i, checked || was_checked);
|
||||||
|
if (emplace_to_to_list)
|
||||||
|
to_list.emplace_back(p->alias, materials->get_omnipresent(p), checked || was_checked);
|
||||||
|
|
||||||
/* Update preset selection in config.
|
/* Update preset selection in config.
|
||||||
* If one preset from aliases bundle is selected,
|
* If one preset from aliases bundle is selected,
|
||||||
@ -1018,33 +1021,39 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
|
|||||||
list->append(item, &const_cast<std::string&>(item.get()));
|
list->append(item, &const_cast<std::string&>(item.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageMaterials::sort_list_data(PresetList* list, const std::vector<std::pair<std::reference_wrapper<const std::string>, bool>>& data)
|
void PageMaterials::sort_list_data(PresetList* list, const std::vector<ProfilePrintData>& data)
|
||||||
{
|
{
|
||||||
// sort data
|
// sort data
|
||||||
// then prusa profiles
|
// then prusa profiles
|
||||||
// then the rest
|
// then the rest
|
||||||
// in alphabetical order
|
// in alphabetical order
|
||||||
std::vector<std::pair<std::reference_wrapper<const std::string>, bool>> prusa_profiles;
|
std::vector<ProfilePrintData> prusa_profiles;
|
||||||
std::vector<std::pair<std::reference_wrapper<const std::string>, bool>> other_profiles;
|
std::vector<ProfilePrintData> other_profiles;
|
||||||
//for (int i = 0; i < data.size(); ++i) {
|
//for (int i = 0; i < data.size(); ++i) {
|
||||||
for (const auto& item : data) {
|
for (const auto& item : data) {
|
||||||
const std::string& name = item.first;
|
const std::string& name = item.name;
|
||||||
if (name.find("Prusa") != std::string::npos)
|
if (name.find("Prusa") != std::string::npos)
|
||||||
prusa_profiles.emplace_back(item);
|
prusa_profiles.emplace_back(item);
|
||||||
else
|
else
|
||||||
other_profiles.emplace_back(item);
|
other_profiles.emplace_back(item);
|
||||||
}
|
}
|
||||||
std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](std::pair<std::reference_wrapper<const std::string>, bool> a, std::pair<std::reference_wrapper<const std::string>, bool> b) {
|
std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](ProfilePrintData a, ProfilePrintData b) {
|
||||||
return a.first.get() < b.first.get();
|
return a.name.get() < b.name.get();
|
||||||
});
|
});
|
||||||
std::sort(other_profiles.begin(), other_profiles.end(), [](std::pair<std::reference_wrapper<const std::string>, bool> a, std::pair<std::reference_wrapper<const std::string>, bool> b) {
|
std::sort(other_profiles.begin(), other_profiles.end(), [](ProfilePrintData a, ProfilePrintData b) {
|
||||||
return a.first.get() < b.first.get();
|
return a.name.get() < b.name.get();
|
||||||
});
|
});
|
||||||
list->Clear();
|
list->Clear();
|
||||||
for (const auto& item : prusa_profiles)
|
//for (const auto& item : prusa_profiles)
|
||||||
list->append(std::string(item.first) + (item.second ? "" : " *"), &const_cast<std::string&>(item.first.get()));
|
for (int i = 0; i < prusa_profiles.size(); ++i) {
|
||||||
for (const auto& item : other_profiles)
|
list->append(std::string(prusa_profiles[i].name) + (prusa_profiles[i].omnipresent ? "" : " *"), &const_cast<std::string&>(prusa_profiles[i].name.get()));
|
||||||
list->append(std::string(item.first) + (item.second ? "" : " *"), &const_cast<std::string&>(item.first.get()));
|
list->Check(i, prusa_profiles[i].checked);
|
||||||
|
}
|
||||||
|
//for (const auto& item : other_profiles)
|
||||||
|
for (int i = 0; i < other_profiles.size(); ++i) {
|
||||||
|
list->append(std::string(other_profiles[i].name) + (other_profiles[i].omnipresent ? "" : " *"), &const_cast<std::string&>(other_profiles[i].name.get()));
|
||||||
|
list->Check(i + prusa_profiles.size(), other_profiles[i].checked);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageMaterials::select_material(int i)
|
void PageMaterials::select_material(int i)
|
||||||
|
@ -315,6 +315,14 @@ template<class T, class D> struct DataList : public T
|
|||||||
typedef DataList<wxListBox, std::string> StringList;
|
typedef DataList<wxListBox, std::string> StringList;
|
||||||
typedef DataList<wxCheckListBox, std::string> PresetList;
|
typedef DataList<wxCheckListBox, std::string> PresetList;
|
||||||
|
|
||||||
|
struct ProfilePrintData
|
||||||
|
{
|
||||||
|
std::reference_wrapper<const std::string> name;
|
||||||
|
bool omnipresent;
|
||||||
|
bool checked;
|
||||||
|
ProfilePrintData(const std::string& n, bool o, bool c) : name(n), omnipresent(o), checked(c) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct PageMaterials: ConfigWizardPage
|
struct PageMaterials: ConfigWizardPage
|
||||||
{
|
{
|
||||||
Materials *materials;
|
Materials *materials;
|
||||||
@ -345,7 +353,7 @@ struct PageMaterials: ConfigWizardPage
|
|||||||
void clear_compatible_printers_label();
|
void clear_compatible_printers_label();
|
||||||
|
|
||||||
void sort_list_data(StringList* list, bool add_All_item, bool material_type_ordering);
|
void sort_list_data(StringList* list, bool add_All_item, bool material_type_ordering);
|
||||||
void sort_list_data(PresetList* list, const std::vector<std::pair<std::reference_wrapper<const std::string>, bool>>& data);
|
void sort_list_data(PresetList* list, const std::vector<ProfilePrintData>& data);
|
||||||
|
|
||||||
void on_paint();
|
void on_paint();
|
||||||
void on_mouse_move_on_profiles(wxMouseEvent& evt);
|
void on_mouse_move_on_profiles(wxMouseEvent& evt);
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "ExtruderSequenceDialog.hpp"
|
#include "ExtruderSequenceDialog.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
#include "libslic3r/AppConfig.hpp"
|
||||||
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
|
||||||
#include <wx/button.h>
|
#include <wx/button.h>
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
@ -45,17 +48,18 @@ static std::string gcode(Type type)
|
|||||||
{
|
{
|
||||||
const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config();
|
const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ColorChange:
|
case ColorChange: return config.color_change_gcode;
|
||||||
return config.color_change_gcode;
|
case PausePrint: return config.pause_print_gcode;
|
||||||
case PausePrint:
|
case Template: return config.template_custom_gcode;
|
||||||
return config.pause_print_gcode;
|
default: return "";
|
||||||
case Template:
|
|
||||||
return config.template_custom_gcode;
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_lower_thumb_editable()
|
||||||
|
{
|
||||||
|
return Slic3r::GUI::get_app_config()->get("seq_top_layer_only") == "0";
|
||||||
|
}
|
||||||
|
|
||||||
Control::Control( wxWindow *parent,
|
Control::Control( wxWindow *parent,
|
||||||
wxWindowID id,
|
wxWindowID id,
|
||||||
int lowerValue,
|
int lowerValue,
|
||||||
@ -963,7 +967,7 @@ int Control::get_value_from_position(const wxCoord x, const wxCoord y)
|
|||||||
bool Control::detect_selected_slider(const wxPoint& pt)
|
bool Control::detect_selected_slider(const wxPoint& pt)
|
||||||
{
|
{
|
||||||
if (is_point_in_rect(pt, m_rect_lower_thumb))
|
if (is_point_in_rect(pt, m_rect_lower_thumb))
|
||||||
m_selection = m_lower_editable ? ssLower : ssUndef;
|
m_selection = is_lower_thumb_editable() ? ssLower : ssUndef;
|
||||||
else if(is_point_in_rect(pt, m_rect_higher_thumb))
|
else if(is_point_in_rect(pt, m_rect_higher_thumb))
|
||||||
m_selection = ssHigher;
|
m_selection = ssHigher;
|
||||||
else
|
else
|
||||||
@ -1419,7 +1423,7 @@ void Control::OnWheel(wxMouseEvent& event)
|
|||||||
ssLower : ssHigher;
|
ssLower : ssHigher;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_selection == ssLower && !m_lower_editable)
|
if (m_selection == ssLower && !is_lower_thumb_editable())
|
||||||
m_selection = ssUndef;
|
m_selection = ssUndef;
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
@ -1472,7 +1476,7 @@ void Control::OnKeyDown(wxKeyEvent &event)
|
|||||||
else if (key == WXK_UP || key == WXK_DOWN) {
|
else if (key == WXK_UP || key == WXK_DOWN) {
|
||||||
if (key == WXK_UP)
|
if (key == WXK_UP)
|
||||||
m_selection = ssHigher;
|
m_selection = ssHigher;
|
||||||
else if (key == WXK_DOWN && m_lower_editable)
|
else if (key == WXK_DOWN && is_lower_thumb_editable())
|
||||||
m_selection = ssLower;
|
m_selection = ssLower;
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
@ -1487,7 +1491,7 @@ void Control::OnKeyDown(wxKeyEvent &event)
|
|||||||
if (key == WXK_LEFT || key == WXK_RIGHT) {
|
if (key == WXK_LEFT || key == WXK_RIGHT) {
|
||||||
if (key == WXK_LEFT)
|
if (key == WXK_LEFT)
|
||||||
m_selection = ssHigher;
|
m_selection = ssHigher;
|
||||||
else if (key == WXK_RIGHT && m_lower_editable)
|
else if (key == WXK_RIGHT && is_lower_thumb_editable())
|
||||||
m_selection = ssLower;
|
m_selection = ssLower;
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
@ -2006,13 +2010,11 @@ void Control::move_current_thumb_to_pos(wxPoint pos)
|
|||||||
const int mouse_val = tick_val >= 0 && m_draw_mode == dmRegular ? tick_val :
|
const int mouse_val = tick_val >= 0 && m_draw_mode == dmRegular ? tick_val :
|
||||||
get_value_from_position(pos);
|
get_value_from_position(pos);
|
||||||
if (mouse_val >= 0) {
|
if (mouse_val >= 0) {
|
||||||
// if (abs(mouse_val - m_lower_value) < abs(mouse_val - m_higher_value)) {
|
|
||||||
// if (mouse_val <= m_lower_value) {
|
|
||||||
if (m_selection == ssLower) {
|
if (m_selection == ssLower) {
|
||||||
SetLowerValue(mouse_val);
|
SetLowerValue(mouse_val);
|
||||||
correct_lower_value();
|
correct_lower_value();
|
||||||
}
|
}
|
||||||
else if (m_selection == ssHigher) {
|
else { // even m_selection is ssUndef, upper thumb should be selected
|
||||||
SetHigherValue(mouse_val);
|
SetHigherValue(mouse_val);
|
||||||
correct_higher_value();
|
correct_higher_value();
|
||||||
}
|
}
|
||||||
@ -2099,7 +2101,7 @@ void Control::jump_to_print_z()
|
|||||||
|
|
||||||
void Control::post_ticks_changed_event(Type type /*= Custom*/)
|
void Control::post_ticks_changed_event(Type type /*= Custom*/)
|
||||||
{
|
{
|
||||||
m_force_mode_apply = type != ToolChange;
|
// m_force_mode_apply = type != ToolChange; // It looks like this condition is no needed now. Leave it for the testing
|
||||||
|
|
||||||
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,6 @@ public:
|
|||||||
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
|
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
|
||||||
void SetExtruderColors(const std::vector<std::string>& extruder_colors);
|
void SetExtruderColors(const std::vector<std::string>& extruder_colors);
|
||||||
|
|
||||||
void set_lower_editable(bool editable) { m_lower_editable = editable; }
|
|
||||||
void set_render_as_disabled(bool value) { m_render_as_disabled = value; }
|
void set_render_as_disabled(bool value) { m_render_as_disabled = value; }
|
||||||
bool is_rendering_as_disabled() const { return m_render_as_disabled; }
|
bool is_rendering_as_disabled() const { return m_render_as_disabled; }
|
||||||
|
|
||||||
@ -340,7 +339,6 @@ private:
|
|||||||
int m_lower_value;
|
int m_lower_value;
|
||||||
int m_higher_value;
|
int m_higher_value;
|
||||||
|
|
||||||
bool m_lower_editable{ true };
|
|
||||||
bool m_render_as_disabled{ false };
|
bool m_render_as_disabled{ false };
|
||||||
|
|
||||||
ScalableBitmap m_bmp_thumb_higher;
|
ScalableBitmap m_bmp_thumb_higher;
|
||||||
|
@ -2328,6 +2328,7 @@ void GCodeViewer::render_legend() const
|
|||||||
m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
|
m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
|
||||||
// update buffers' render paths
|
// update buffers' render paths
|
||||||
refresh_render_paths(false, false);
|
refresh_render_paths(false, false);
|
||||||
|
wxGetApp().plater()->update_preview_moves_slider();
|
||||||
wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
|
wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
|
||||||
wxGetApp().plater()->update_preview_bottom_toolbar();
|
wxGetApp().plater()->update_preview_bottom_toolbar();
|
||||||
}
|
}
|
||||||
@ -2600,7 +2601,7 @@ void GCodeViewer::render_legend() const
|
|||||||
|
|
||||||
// items
|
// items
|
||||||
add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions"));
|
add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions"));
|
||||||
add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Unretractions"));
|
add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions"));
|
||||||
add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes"));
|
add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes"));
|
||||||
add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes"));
|
add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes"));
|
||||||
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Pause prints"));
|
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Pause prints"));
|
||||||
|
@ -2812,8 +2812,7 @@ void GLCanvas3D::load_preview(const std::vector<std::string>& str_tool_colors, c
|
|||||||
|
|
||||||
void GLCanvas3D::bind_event_handlers()
|
void GLCanvas3D::bind_event_handlers()
|
||||||
{
|
{
|
||||||
if (m_canvas != nullptr)
|
if (m_canvas != nullptr) {
|
||||||
{
|
|
||||||
m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
|
m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
|
||||||
m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
|
m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
|
||||||
m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
|
m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
|
||||||
@ -2835,13 +2834,14 @@ void GLCanvas3D::bind_event_handlers()
|
|||||||
m_canvas->Bind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
|
m_canvas->Bind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
|
||||||
m_canvas->Bind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
|
m_canvas->Bind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
|
||||||
m_canvas->Bind(wxEVT_SET_FOCUS, &GLCanvas3D::on_set_focus, this);
|
m_canvas->Bind(wxEVT_SET_FOCUS, &GLCanvas3D::on_set_focus, this);
|
||||||
|
|
||||||
|
m_event_handlers_bound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::unbind_event_handlers()
|
void GLCanvas3D::unbind_event_handlers()
|
||||||
{
|
{
|
||||||
if (m_canvas != nullptr)
|
if (m_canvas != nullptr && m_event_handlers_bound) {
|
||||||
{
|
|
||||||
m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
|
m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
|
||||||
m_canvas->Unbind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
|
m_canvas->Unbind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
|
||||||
m_canvas->Unbind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
|
m_canvas->Unbind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
|
||||||
@ -2863,6 +2863,8 @@ void GLCanvas3D::unbind_event_handlers()
|
|||||||
m_canvas->Unbind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
|
m_canvas->Unbind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
|
||||||
m_canvas->Unbind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
|
m_canvas->Unbind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
|
||||||
m_canvas->Unbind(wxEVT_SET_FOCUS, &GLCanvas3D::on_set_focus, this);
|
m_canvas->Unbind(wxEVT_SET_FOCUS, &GLCanvas3D::on_set_focus, this);
|
||||||
|
|
||||||
|
m_event_handlers_bound = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2888,8 +2890,7 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
|||||||
|
|
||||||
_refresh_if_shown_on_screen();
|
_refresh_if_shown_on_screen();
|
||||||
|
|
||||||
if (m_extra_frame_requested || mouse3d_controller_applied)
|
if (m_extra_frame_requested || mouse3d_controller_applied) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
m_extra_frame_requested = false;
|
m_extra_frame_requested = false;
|
||||||
evt.RequestMore();
|
evt.RequestMore();
|
||||||
@ -2941,7 +2942,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||||||
post_event(SimpleEvent(EVT_GLTOOLBAR_COPY));
|
post_event(SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
case WXK_CONTROL_M:
|
case WXK_CONTROL_M:
|
||||||
{
|
{
|
||||||
Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller();
|
Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller();
|
||||||
@ -3512,40 +3513,35 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
|
#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_main_toolbar.on_mouse(evt, *this))
|
if (m_main_toolbar.on_mouse(evt, *this)) {
|
||||||
{
|
|
||||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
m_mouse.set_start_position_3D_as_invalid();
|
m_mouse.set_start_position_3D_as_invalid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_undoredo_toolbar.on_mouse(evt, *this))
|
if (m_undoredo_toolbar.on_mouse(evt, *this)) {
|
||||||
{
|
|
||||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
m_mouse.set_start_position_3D_as_invalid();
|
m_mouse.set_start_position_3D_as_invalid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxGetApp().plater()->get_collapse_toolbar().on_mouse(evt, *this))
|
if (wxGetApp().plater()->get_collapse_toolbar().on_mouse(evt, *this)) {
|
||||||
{
|
|
||||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
m_mouse.set_start_position_3D_as_invalid();
|
m_mouse.set_start_position_3D_as_invalid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxGetApp().plater()->get_view_toolbar().on_mouse(evt, *this))
|
if (wxGetApp().plater()->get_view_toolbar().on_mouse(evt, *this)) {
|
||||||
{
|
|
||||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
m_mouse.set_start_position_3D_as_invalid();
|
m_mouse.set_start_position_3D_as_invalid();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_gizmos.on_mouse(evt))
|
if (m_gizmos.on_mouse(evt)) {
|
||||||
{
|
|
||||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
|
|
||||||
@ -3554,12 +3550,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool any_gizmo_active = m_gizmos.get_current() != nullptr;
|
||||||
|
|
||||||
int selected_object_idx = m_selection.get_object_idx();
|
int selected_object_idx = m_selection.get_object_idx();
|
||||||
int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1;
|
int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1;
|
||||||
m_layers_editing.select_object(*m_model, layer_editing_object_idx);
|
m_layers_editing.select_object(*m_model, layer_editing_object_idx);
|
||||||
|
|
||||||
if (m_mouse.drag.move_requires_threshold && m_mouse.is_move_start_threshold_position_2D_defined() && m_mouse.is_move_threshold_met(pos))
|
if (m_mouse.drag.move_requires_threshold && m_mouse.is_move_start_threshold_position_2D_defined() && m_mouse.is_move_threshold_met(pos)) {
|
||||||
{
|
|
||||||
m_mouse.drag.move_requires_threshold = false;
|
m_mouse.drag.move_requires_threshold = false;
|
||||||
m_mouse.set_move_start_threshold_position_2D_as_invalid();
|
m_mouse.set_move_start_threshold_position_2D_as_invalid();
|
||||||
}
|
}
|
||||||
@ -3568,8 +3565,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
// Grab keyboard focus on any mouse click event.
|
// Grab keyboard focus on any mouse click event.
|
||||||
m_canvas->SetFocus();
|
m_canvas->SetFocus();
|
||||||
|
|
||||||
if (evt.Entering())
|
if (evt.Entering()) {
|
||||||
{
|
|
||||||
//#if defined(__WXMSW__) || defined(__linux__)
|
//#if defined(__WXMSW__) || defined(__linux__)
|
||||||
// // On Windows and Linux needs focus in order to catch key events
|
// // On Windows and Linux needs focus in order to catch key events
|
||||||
// Set focus in order to remove it from sidebar fields
|
// Set focus in order to remove it from sidebar fields
|
||||||
@ -3594,49 +3590,41 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
m_mouse.set_start_position_2D_as_invalid();
|
m_mouse.set_start_position_2D_as_invalid();
|
||||||
//#endif
|
//#endif
|
||||||
}
|
}
|
||||||
else if (evt.Leaving())
|
else if (evt.Leaving()) {
|
||||||
{
|
|
||||||
_deactivate_undo_redo_toolbar_items();
|
_deactivate_undo_redo_toolbar_items();
|
||||||
|
|
||||||
// to remove hover on objects when the mouse goes out of this canvas
|
// to remove hover on objects when the mouse goes out of this canvas
|
||||||
m_mouse.position = Vec2d(-1.0, -1.0);
|
m_mouse.position = Vec2d(-1.0, -1.0);
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown())
|
else if (evt.LeftDown() || evt.RightDown() || evt.MiddleDown()) {
|
||||||
{
|
|
||||||
if (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item())
|
if (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If user pressed left or right button we first check whether this happened
|
// If user pressed left or right button we first check whether this happened
|
||||||
// on a volume or not.
|
// on a volume or not.
|
||||||
m_layers_editing.state = LayersEditing::Unknown;
|
m_layers_editing.state = LayersEditing::Unknown;
|
||||||
if ((layer_editing_object_idx != -1) && m_layers_editing.bar_rect_contains(*this, pos(0), pos(1)))
|
if (layer_editing_object_idx != -1 && m_layers_editing.bar_rect_contains(*this, pos(0), pos(1))) {
|
||||||
{
|
|
||||||
// A volume is selected and the mouse is inside the layer thickness bar.
|
// A volume is selected and the mouse is inside the layer thickness bar.
|
||||||
// Start editing the layer height.
|
// Start editing the layer height.
|
||||||
m_layers_editing.state = LayersEditing::Editing;
|
m_layers_editing.state = LayersEditing::Editing;
|
||||||
_perform_layer_editing_action(&evt);
|
_perform_layer_editing_action(&evt);
|
||||||
}
|
}
|
||||||
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
|
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled) {
|
||||||
{
|
|
||||||
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports
|
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports
|
||||||
&& m_gizmos.get_current_type() != GLGizmosManager::FdmSupports
|
&& m_gizmos.get_current_type() != GLGizmosManager::FdmSupports
|
||||||
&& m_gizmos.get_current_type() != GLGizmosManager::Seam)
|
&& m_gizmos.get_current_type() != GLGizmosManager::Seam) {
|
||||||
{
|
|
||||||
m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
|
m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect);
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Select volume in this 3D canvas.
|
// Select volume in this 3D canvas.
|
||||||
// Don't deselect a volume if layer editing is enabled. We want the object to stay selected
|
// Don't deselect a volume if layer editing is enabled or any gizmo is active. We want the object to stay selected
|
||||||
// during the scene manipulation.
|
// during the scene manipulation.
|
||||||
|
|
||||||
if (m_picking_enabled && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled()))
|
if (m_picking_enabled && (!any_gizmo_active || !evt.CmdDown()) && (!m_hover_volume_idxs.empty() || !is_layers_editing_enabled())) {
|
||||||
{
|
if (evt.LeftDown() && !m_hover_volume_idxs.empty()) {
|
||||||
if (evt.LeftDown() && !m_hover_volume_idxs.empty())
|
|
||||||
{
|
|
||||||
int volume_idx = get_first_hover_volume_idx();
|
int volume_idx = get_first_hover_volume_idx();
|
||||||
bool already_selected = m_selection.contains_volume(volume_idx);
|
bool already_selected = m_selection.contains_volume(volume_idx);
|
||||||
bool ctrl_down = evt.CmdDown();
|
bool ctrl_down = evt.CmdDown();
|
||||||
@ -3645,8 +3633,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
|
|
||||||
if (already_selected && ctrl_down)
|
if (already_selected && ctrl_down)
|
||||||
m_selection.remove(volume_idx);
|
m_selection.remove(volume_idx);
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
m_selection.add(volume_idx, !ctrl_down, true);
|
m_selection.add(volume_idx, !ctrl_down, true);
|
||||||
m_mouse.drag.move_requires_threshold = !already_selected;
|
m_mouse.drag.move_requires_threshold = !already_selected;
|
||||||
if (already_selected)
|
if (already_selected)
|
||||||
@ -3656,8 +3643,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// propagate event through callback
|
// propagate event through callback
|
||||||
if (curr_idxs != m_selection.get_volume_idxs())
|
if (curr_idxs != m_selection.get_volume_idxs()) {
|
||||||
{
|
|
||||||
if (m_selection.is_empty())
|
if (m_selection.is_empty())
|
||||||
m_gizmos.reset_all_states();
|
m_gizmos.reset_all_states();
|
||||||
else
|
else
|
||||||
@ -3670,16 +3656,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_hover_volume_idxs.empty())
|
if (!m_hover_volume_idxs.empty()) {
|
||||||
{
|
if (evt.LeftDown() && m_moving_enabled && m_mouse.drag.move_volume_idx == -1) {
|
||||||
if (evt.LeftDown() && m_moving_enabled && (m_mouse.drag.move_volume_idx == -1))
|
|
||||||
{
|
|
||||||
// Only accept the initial position, if it is inside the volume bounding box.
|
// Only accept the initial position, if it is inside the volume bounding box.
|
||||||
int volume_idx = get_first_hover_volume_idx();
|
int volume_idx = get_first_hover_volume_idx();
|
||||||
BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box();
|
BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box();
|
||||||
volume_bbox.offset(1.0);
|
volume_bbox.offset(1.0);
|
||||||
if (volume_bbox.contains(m_mouse.scene_position))
|
if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position)) {
|
||||||
{
|
|
||||||
m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None;
|
m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None;
|
||||||
// The dragging operation is initiated.
|
// The dragging operation is initiated.
|
||||||
m_mouse.drag.move_volume_idx = volume_idx;
|
m_mouse.drag.move_volume_idx = volume_idx;
|
||||||
@ -3691,18 +3674,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && evt.LeftIsDown() && (m_layers_editing.state == LayersEditing::Unknown) && (m_mouse.drag.move_volume_idx != -1))
|
else if (evt.Dragging() && evt.LeftIsDown() && m_layers_editing.state == LayersEditing::Unknown && m_mouse.drag.move_volume_idx != -1) {
|
||||||
{
|
if (!m_mouse.drag.move_requires_threshold) {
|
||||||
if (!m_mouse.drag.move_requires_threshold)
|
|
||||||
{
|
|
||||||
m_mouse.dragging = true;
|
m_mouse.dragging = true;
|
||||||
Vec3d cur_pos = m_mouse.drag.start_position_3D;
|
Vec3d cur_pos = m_mouse.drag.start_position_3D;
|
||||||
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
|
// we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag
|
||||||
if (m_selection.contains_volume(get_first_hover_volume_idx()))
|
if (m_selection.contains_volume(get_first_hover_volume_idx())) {
|
||||||
{
|
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
if (std::abs(camera.get_dir_forward()(2)) < EPSILON)
|
if (std::abs(camera.get_dir_forward()(2)) < EPSILON) {
|
||||||
{
|
|
||||||
// side view -> move selected volumes orthogonally to camera view direction
|
// side view -> move selected volumes orthogonally to camera view direction
|
||||||
Linef3 ray = mouse_ray(pos);
|
Linef3 ray = mouse_ray(pos);
|
||||||
Vec3d dir = ray.unit_vector();
|
Vec3d dir = ray.unit_vector();
|
||||||
@ -3724,8 +3703,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
// apply offset
|
// apply offset
|
||||||
cur_pos = m_mouse.drag.start_position_3D + projection_x * camera_right + projection_z * camera_up;
|
cur_pos = m_mouse.drag.start_position_3D + projection_x * camera_right + projection_z * camera_up;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Generic view
|
// Generic view
|
||||||
// Get new position at the same Z of the initial click point.
|
// Get new position at the same Z of the initial click point.
|
||||||
float z0 = 0.0f;
|
float z0 = 0.0f;
|
||||||
@ -3739,35 +3717,28 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging())
|
else if (evt.Dragging() && evt.LeftIsDown() && m_picking_enabled && m_rectangle_selection.is_dragging()) {
|
||||||
{
|
|
||||||
m_rectangle_selection.dragging(pos.cast<double>());
|
m_rectangle_selection.dragging(pos.cast<double>());
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
else if (evt.Dragging())
|
else if (evt.Dragging()) {
|
||||||
{
|
|
||||||
m_mouse.dragging = true;
|
m_mouse.dragging = true;
|
||||||
|
|
||||||
if ((m_layers_editing.state != LayersEditing::Unknown) && (layer_editing_object_idx != -1))
|
if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) {
|
||||||
{
|
if (m_layers_editing.state == LayersEditing::Editing) {
|
||||||
if (m_layers_editing.state == LayersEditing::Editing)
|
|
||||||
{
|
|
||||||
_perform_layer_editing_action(&evt);
|
_perform_layer_editing_action(&evt);
|
||||||
m_mouse.position = pos.cast<double>();
|
m_mouse.position = pos.cast<double>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// do not process the dragging if the left mouse was set down in another canvas
|
// do not process the dragging if the left mouse was set down in another canvas
|
||||||
else if (evt.LeftIsDown())
|
else if (evt.LeftIsDown()) {
|
||||||
{
|
|
||||||
// if dragging over blank area with left button, rotate
|
// if dragging over blank area with left button, rotate
|
||||||
if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
|
if ((any_gizmo_active || m_hover_volume_idxs.empty()) && m_mouse.is_start_position_3D_defined()) {
|
||||||
{
|
|
||||||
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
|
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
|
||||||
if (wxGetApp().app_config->get("use_free_camera") == "1")
|
if (wxGetApp().app_config->get("use_free_camera") == "1")
|
||||||
// Virtual track ball (similar to the 3DConnexion mouse).
|
// Virtual track ball (similar to the 3DConnexion mouse).
|
||||||
wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
|
wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation.
|
// Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation.
|
||||||
// It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(),
|
// It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(),
|
||||||
// which checks an atomics (flushes CPU caches).
|
// which checks an atomics (flushes CPU caches).
|
||||||
@ -3781,11 +3752,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
}
|
}
|
||||||
m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0);
|
m_mouse.drag.start_position_3D = Vec3d((double)pos(0), (double)pos(1), 0.0);
|
||||||
}
|
}
|
||||||
else if (evt.MiddleIsDown() || evt.RightIsDown())
|
else if (evt.MiddleIsDown() || evt.RightIsDown()) {
|
||||||
{
|
|
||||||
// If dragging over blank area with right button, pan.
|
// If dragging over blank area with right button, pan.
|
||||||
if (m_mouse.is_start_position_2D_defined())
|
if (m_mouse.is_start_position_2D_defined()) {
|
||||||
{
|
|
||||||
// get point in model space at Z = 0
|
// get point in model space at Z = 0
|
||||||
float z = 0.0f;
|
float z = 0.0f;
|
||||||
const Vec3d& cur_pos = _mouse_to_3d(pos, &z);
|
const Vec3d& cur_pos = _mouse_to_3d(pos, &z);
|
||||||
@ -3805,43 +3774,36 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
m_mouse.drag.start_position_2D = pos;
|
m_mouse.drag.start_position_2D = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
else if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) {
|
||||||
{
|
if (m_layers_editing.state != LayersEditing::Unknown) {
|
||||||
if (m_layers_editing.state != LayersEditing::Unknown)
|
|
||||||
{
|
|
||||||
m_layers_editing.state = LayersEditing::Unknown;
|
m_layers_editing.state = LayersEditing::Unknown;
|
||||||
_stop_timer();
|
_stop_timer();
|
||||||
m_layers_editing.accept_changes(*this);
|
m_layers_editing.accept_changes(*this);
|
||||||
}
|
}
|
||||||
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
|
else if (m_mouse.drag.move_volume_idx != -1 && m_mouse.dragging) {
|
||||||
{
|
|
||||||
do_move(L("Move Object"));
|
do_move(L("Move Object"));
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
// Let the plater know that the dragging finished, so a delayed refresh
|
// Let the plater know that the dragging finished, so a delayed refresh
|
||||||
// of the scene with the background processing data should be performed.
|
// of the scene with the background processing data should be performed.
|
||||||
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging())
|
else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging()) {
|
||||||
{
|
|
||||||
if (evt.ShiftDown() || evt.AltDown())
|
if (evt.ShiftDown() || evt.AltDown())
|
||||||
_update_selection_from_hover();
|
_update_selection_from_hover();
|
||||||
|
|
||||||
m_rectangle_selection.stop_dragging();
|
m_rectangle_selection.stop_dragging();
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled())
|
else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_hover_volume_idxs.empty() && !is_layers_editing_enabled()) {
|
||||||
{
|
|
||||||
// deselect and propagate event through callback
|
// deselect and propagate event through callback
|
||||||
if (!evt.ShiftDown() && m_picking_enabled)
|
if (!evt.ShiftDown() && (!any_gizmo_active || !evt.CmdDown()) && m_picking_enabled)
|
||||||
deselect_all();
|
deselect_all();
|
||||||
}
|
}
|
||||||
else if (evt.RightUp())
|
else if (evt.RightUp()) {
|
||||||
{
|
|
||||||
m_mouse.position = pos.cast<double>();
|
m_mouse.position = pos.cast<double>();
|
||||||
// forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while
|
// forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while
|
||||||
// the context menu is already shown
|
// the context menu is already shown
|
||||||
render();
|
render();
|
||||||
if (!m_hover_volume_idxs.empty())
|
if (!m_hover_volume_idxs.empty()) {
|
||||||
{
|
|
||||||
// if right clicking on volume, propagate event through callback (shows context menu)
|
// if right clicking on volume, propagate event through callback (shows context menu)
|
||||||
int volume_idx = get_first_hover_volume_idx();
|
int volume_idx = get_first_hover_volume_idx();
|
||||||
if (!m_volumes.volumes[volume_idx]->is_wipe_tower // no context menu for the wipe tower
|
if (!m_volumes.volumes[volume_idx]->is_wipe_tower // no context menu for the wipe tower
|
||||||
@ -3873,8 +3835,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
|
|
||||||
mouse_up_cleanup();
|
mouse_up_cleanup();
|
||||||
}
|
}
|
||||||
else if (evt.Moving())
|
else if (evt.Moving()) {
|
||||||
{
|
|
||||||
m_mouse.position = pos.cast<double>();
|
m_mouse.position = pos.cast<double>();
|
||||||
|
|
||||||
// updates gizmos overlay
|
// updates gizmos overlay
|
||||||
@ -5222,8 +5183,7 @@ void GLCanvas3D::_refresh_if_shown_on_screen()
|
|||||||
|
|
||||||
void GLCanvas3D::_picking_pass() const
|
void GLCanvas3D::_picking_pass() const
|
||||||
{
|
{
|
||||||
if (m_picking_enabled && !m_mouse.dragging && (m_mouse.position != Vec2d(DBL_MAX, DBL_MAX)))
|
if (m_picking_enabled && !m_mouse.dragging && m_mouse.position != Vec2d(DBL_MAX, DBL_MAX)) {
|
||||||
{
|
|
||||||
m_hover_volume_idxs.clear();
|
m_hover_volume_idxs.clear();
|
||||||
|
|
||||||
// Render the object for picking.
|
// Render the object for picking.
|
||||||
@ -5257,16 +5217,16 @@ void GLCanvas3D::_picking_pass() const
|
|||||||
|
|
||||||
GLubyte color[4] = { 0, 0, 0, 0 };
|
GLubyte color[4] = { 0, 0, 0, 0 };
|
||||||
const Size& cnv_size = get_canvas_size();
|
const Size& cnv_size = get_canvas_size();
|
||||||
bool inside = (0 <= m_mouse.position(0)) && (m_mouse.position(0) < cnv_size.get_width()) && (0 <= m_mouse.position(1)) && (m_mouse.position(1) < cnv_size.get_height());
|
bool inside = 0 <= m_mouse.position(0) && m_mouse.position(0) < cnv_size.get_width() && 0 <= m_mouse.position(1) && m_mouse.position(1) < cnv_size.get_height();
|
||||||
if (inside)
|
if (inside) {
|
||||||
{
|
|
||||||
glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
|
glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
|
||||||
if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3])
|
if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3])
|
||||||
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
|
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
|
||||||
volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
|
volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
|
||||||
}
|
}
|
||||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) {
|
||||||
{
|
// do not add the volume id if any gizmo is active and CTRL is pressed
|
||||||
|
if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL))
|
||||||
m_hover_volume_idxs.emplace_back(volume_id);
|
m_hover_volume_idxs.emplace_back(volume_id);
|
||||||
m_gizmos.set_hover_id(-1);
|
m_gizmos.set_hover_id(-1);
|
||||||
}
|
}
|
||||||
|
@ -474,6 +474,7 @@ private:
|
|||||||
// when true renders an extra frame by not resetting m_dirty to false
|
// when true renders an extra frame by not resetting m_dirty to false
|
||||||
// see request_extra_frame()
|
// see request_extra_frame()
|
||||||
bool m_extra_frame_requested;
|
bool m_extra_frame_requested;
|
||||||
|
bool m_event_handlers_bound{ false };
|
||||||
|
|
||||||
mutable GLVolumeCollection m_volumes;
|
mutable GLVolumeCollection m_volumes;
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "libslic3r/Technologies.hpp"
|
#include "libslic3r/Technologies.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
|
#include "GUI_Init.hpp"
|
||||||
#include "GUI_ObjectList.hpp"
|
#include "GUI_ObjectList.hpp"
|
||||||
#include "GUI_ObjectManipulation.hpp"
|
#include "GUI_ObjectManipulation.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
@ -24,7 +25,6 @@
|
|||||||
#include <wx/wupdlock.h>
|
#include <wx/wupdlock.h>
|
||||||
#include <wx/filefn.h>
|
#include <wx/filefn.h>
|
||||||
#include <wx/sysopt.h>
|
#include <wx/sysopt.h>
|
||||||
#include <wx/msgdlg.h>
|
|
||||||
#include <wx/richmsgdlg.h>
|
#include <wx/richmsgdlg.h>
|
||||||
#include <wx/log.h>
|
#include <wx/log.h>
|
||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
@ -71,7 +71,7 @@
|
|||||||
#include "InstanceCheck.hpp"
|
#include "InstanceCheck.hpp"
|
||||||
#include "NotificationManager.hpp"
|
#include "NotificationManager.hpp"
|
||||||
#include "UnsavedChangesDialog.hpp"
|
#include "UnsavedChangesDialog.hpp"
|
||||||
#include "PresetComboBoxes.hpp"
|
#include "SavePresetDialog.hpp"
|
||||||
|
|
||||||
#include "BitmapCache.hpp"
|
#include "BitmapCache.hpp"
|
||||||
|
|
||||||
@ -355,6 +355,63 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
bool static check_old_linux_datadir(const wxString& app_name) {
|
||||||
|
// If we are on Linux and the datadir does not exist yet, look into the old
|
||||||
|
// location where the datadir was before version 2.3. If we find it there,
|
||||||
|
// tell the user that he might wanna migrate to the new location.
|
||||||
|
// (https://github.com/prusa3d/PrusaSlicer/issues/2911)
|
||||||
|
// To be precise, the datadir should exist, it is created when single instance
|
||||||
|
// lock happens. Instead of checking for existence, check the contents.
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
std::string new_path = Slic3r::data_dir();
|
||||||
|
|
||||||
|
wxString dir;
|
||||||
|
if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() )
|
||||||
|
dir = wxFileName::GetHomeDir() + wxS("/.config");
|
||||||
|
std::string default_path = (dir + "/" + app_name).ToUTF8().data();
|
||||||
|
|
||||||
|
if (new_path != default_path) {
|
||||||
|
// This happens when the user specifies a custom --datadir.
|
||||||
|
// Do not show anything in that case.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path data_dir = fs::path(new_path);
|
||||||
|
if (! fs::is_directory(data_dir))
|
||||||
|
return true; // This should not happen.
|
||||||
|
|
||||||
|
int file_count = std::distance(fs::directory_iterator(data_dir), fs::directory_iterator());
|
||||||
|
|
||||||
|
if (file_count <= 1) { // just cache dir with an instance lock
|
||||||
|
std::string old_path = wxStandardPaths::Get().GetUserDataDir().ToUTF8().data();
|
||||||
|
|
||||||
|
if (fs::is_directory(old_path)) {
|
||||||
|
wxString msg = from_u8((boost::format(_u8L("Starting with %1% 2.3, configuration "
|
||||||
|
"directory on Linux has changed (according to XDG Base Directory Specification) to \n%2%.\n\n"
|
||||||
|
"This directory did not exist yet (maybe you run the new version for the first time).\nHowever, "
|
||||||
|
"an old %1% configuration directory was detected in \n%3%.\n\n"
|
||||||
|
"Consider moving the contents of the old directory to the new location in order to access "
|
||||||
|
"your profiles, etc.\nNote that if you decide to downgrade %1% in future, it will use the old "
|
||||||
|
"location again.\n\n"
|
||||||
|
"What do you want to do now?")) % SLIC3R_APP_NAME % new_path % old_path).str());
|
||||||
|
wxString caption = from_u8((boost::format(_u8L("%s - BREAKING CHANGE")) % SLIC3R_APP_NAME).str());
|
||||||
|
wxRichMessageDialog dlg(nullptr, msg, caption, wxYES_NO);
|
||||||
|
dlg.SetYesNoLabels(_L("Quit, I will move my data now"), _L("Start the application"));
|
||||||
|
if (dlg.ShowModal() != wxID_NO)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the new directory exists, be silent. The user likely already saw the message.
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||||
{
|
{
|
||||||
static const std::string defaults[FT_SIZE] = {
|
static const std::string defaults[FT_SIZE] = {
|
||||||
@ -545,15 +602,16 @@ static void generic_exception_handle()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI_App::AfterInitLoads::on_loads(GUI_App* gui)
|
void GUI_App::post_init()
|
||||||
{
|
{
|
||||||
if (!gui->initialized())
|
assert(initialized());
|
||||||
return;
|
if (! this->initialized())
|
||||||
|
throw Slic3r::RuntimeError("Calling post_init() while not yet initialized");
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
if (m_start_as_gcodeviewer) {
|
if (this->init_params->start_as_gcodeviewer) {
|
||||||
if (!m_input_files.empty())
|
if (! this->init_params->input_files.empty())
|
||||||
gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str()));
|
this->plater()->load_gcode(wxString::FromUTF8(this->init_params->input_files[0].c_str()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#endif // ENABLE_GCODE_VIEWER_AS
|
#endif // ENABLE_GCODE_VIEWER_AS
|
||||||
@ -563,22 +621,22 @@ void GUI_App::AfterInitLoads::on_loads(GUI_App* gui)
|
|||||||
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
|
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
|
||||||
// As of now only the full configs are supported here.
|
// As of now only the full configs are supported here.
|
||||||
if (!m_print_config.empty())
|
if (!m_print_config.empty())
|
||||||
gui->mainframe->load_config(m_print_config);
|
this->gui->mainframe->load_config(m_print_config);
|
||||||
#endif
|
#endif
|
||||||
if (!m_load_configs.empty())
|
if (! this->init_params->load_configs.empty())
|
||||||
// Load the last config to give it a name at the UI. The name of the preset may be later
|
// Load the last config to give it a name at the UI. The name of the preset may be later
|
||||||
// changed by loading an AMF or 3MF.
|
// changed by loading an AMF or 3MF.
|
||||||
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
|
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
|
||||||
gui->mainframe->load_config_file(m_load_configs.back());
|
this->mainframe->load_config_file(this->init_params->load_configs.back());
|
||||||
// If loading a 3MF file, the config is loaded from the last one.
|
// If loading a 3MF file, the config is loaded from the last one.
|
||||||
if (!m_input_files.empty())
|
if (! this->init_params->input_files.empty())
|
||||||
gui->plater()->load_files(m_input_files, true, true);
|
this->plater()->load_files(this->init_params->input_files, true, true);
|
||||||
if (!m_extra_config.empty())
|
if (! this->init_params->extra_config.empty())
|
||||||
gui->mainframe->load_config(m_extra_config);
|
this->mainframe->load_config(this->init_params->extra_config);
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
}
|
}
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_APP(GUI_App)
|
IMPLEMENT_APP(GUI_App)
|
||||||
|
|
||||||
@ -640,8 +698,18 @@ void GUI_App::init_app_config()
|
|||||||
// Windows : "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r"
|
// Windows : "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r"
|
||||||
// Mac : "~/Library/Application Support/Slic3r"
|
// Mac : "~/Library/Application Support/Slic3r"
|
||||||
|
|
||||||
if (data_dir().empty())
|
if (data_dir().empty()) {
|
||||||
set_data_dir(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data());
|
#ifndef __linux__
|
||||||
|
set_data_dir(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data());
|
||||||
|
#else
|
||||||
|
// Since version 2.3, config dir on Linux is in ${XDG_CONFIG_HOME}.
|
||||||
|
// https://github.com/prusa3d/PrusaSlicer/issues/2911
|
||||||
|
wxString dir;
|
||||||
|
if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() )
|
||||||
|
dir = wxFileName::GetHomeDir() + wxS("/.config");
|
||||||
|
set_data_dir((dir + "/" + GetAppName()).ToUTF8().data());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (!app_config)
|
if (!app_config)
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
@ -654,7 +722,6 @@ void GUI_App::init_app_config()
|
|||||||
m_app_conf_exists = app_config->exists();
|
m_app_conf_exists = app_config->exists();
|
||||||
if (m_app_conf_exists) {
|
if (m_app_conf_exists) {
|
||||||
std::string error = app_config->load();
|
std::string error = app_config->load();
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
if (!error.empty()) {
|
if (!error.empty()) {
|
||||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||||
if (is_editor()) {
|
if (is_editor()) {
|
||||||
@ -670,14 +737,6 @@ void GUI_App::init_app_config()
|
|||||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (!error.empty())
|
|
||||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
|
||||||
throw Slic3r::RuntimeError(
|
|
||||||
_u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
|
||||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
|
|
||||||
"\n\n" + AppConfig::config_path() + "\n\n" + error);
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,6 +763,13 @@ bool GUI_App::on_init_inner()
|
|||||||
wxCHECK_MSG(wxDirExists(resources_dir), false,
|
wxCHECK_MSG(wxDirExists(resources_dir), false,
|
||||||
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
|
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
if (! check_old_linux_datadir(GetAppName())) {
|
||||||
|
std::cerr << "Quitting, user chose to move his data to new location." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
|
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
|
||||||
// wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0);
|
// wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0);
|
||||||
// Enable this to disable Windows Vista themes for all wxNotebooks. The themes seem to lead to terrible
|
// Enable this to disable Windows Vista themes for all wxNotebooks. The themes seem to lead to terrible
|
||||||
@ -863,7 +929,7 @@ bool GUI_App::on_init_inner()
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
this->mainframe->register_win32_callbacks();
|
this->mainframe->register_win32_callbacks();
|
||||||
#endif
|
#endif
|
||||||
this->after_init_loads.on_loads(this);
|
this->post_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preset updating & Configwizard are done after the above initializations,
|
// Preset updating & Configwizard are done after the above initializations,
|
||||||
@ -1259,9 +1325,9 @@ void fatal_error(wxWindow* parent)
|
|||||||
|
|
||||||
// Called after the Preferences dialog is closed and the program settings are saved.
|
// Called after the Preferences dialog is closed and the program settings are saved.
|
||||||
// Update the UI based on the current preferences.
|
// Update the UI based on the current preferences.
|
||||||
void GUI_App::update_ui_from_settings()
|
void GUI_App::update_ui_from_settings(bool apply_free_camera_correction)
|
||||||
{
|
{
|
||||||
mainframe->update_ui_from_settings();
|
mainframe->update_ui_from_settings(apply_free_camera_correction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_maximized)
|
void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_maximized)
|
||||||
|
@ -24,6 +24,7 @@ class wxNotebook;
|
|||||||
struct wxLanguageInfo;
|
struct wxLanguageInfo;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class AppConfig;
|
class AppConfig;
|
||||||
class PresetBundle;
|
class PresetBundle;
|
||||||
class PresetUpdater;
|
class PresetUpdater;
|
||||||
@ -32,6 +33,7 @@ class PrintHostJobQueue;
|
|||||||
class Model;
|
class Model;
|
||||||
|
|
||||||
namespace GUI{
|
namespace GUI{
|
||||||
|
|
||||||
class RemovableDriveManager;
|
class RemovableDriveManager;
|
||||||
class OtherInstanceMessageHandler;
|
class OtherInstanceMessageHandler;
|
||||||
class MainFrame;
|
class MainFrame;
|
||||||
@ -41,6 +43,7 @@ class ObjectSettings;
|
|||||||
class ObjectList;
|
class ObjectList;
|
||||||
class ObjectLayers;
|
class ObjectLayers;
|
||||||
class Plater;
|
class Plater;
|
||||||
|
struct GUI_InitParams;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -142,37 +145,6 @@ private:
|
|||||||
std::string m_instance_hash_string;
|
std::string m_instance_hash_string;
|
||||||
size_t m_instance_hash_int;
|
size_t m_instance_hash_int;
|
||||||
|
|
||||||
// parameters needed for the after OnInit() loads
|
|
||||||
struct AfterInitLoads
|
|
||||||
{
|
|
||||||
std::vector<std::string> m_load_configs;
|
|
||||||
DynamicPrintConfig m_extra_config;
|
|
||||||
std::vector<std::string> m_input_files;
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
bool m_start_as_gcodeviewer;
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
|
|
||||||
void set_params(
|
|
||||||
const std::vector<std::string>& load_configs,
|
|
||||||
const DynamicPrintConfig& extra_config,
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
const std::vector<std::string>& input_files,
|
|
||||||
bool start_as_gcodeviewer
|
|
||||||
#else
|
|
||||||
const std::vector<std::string>& input_files
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
) {
|
|
||||||
m_load_configs = load_configs;
|
|
||||||
m_extra_config = extra_config;
|
|
||||||
m_input_files = input_files;
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
m_start_as_gcodeviewer = start_as_gcodeviewer;
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_loads(GUI_App* gui);
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool OnInit() override;
|
bool OnInit() override;
|
||||||
bool initialized() const { return m_initialized; }
|
bool initialized() const { return m_initialized; }
|
||||||
@ -191,6 +163,10 @@ public:
|
|||||||
bool is_recreating_gui() const { return m_is_recreating_gui; }
|
bool is_recreating_gui() const { return m_is_recreating_gui; }
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
|
||||||
|
// To be called after the GUI is fully built up.
|
||||||
|
// Process command line parameters cached in this->init_params,
|
||||||
|
// load configs, STLs etc.
|
||||||
|
void post_init();
|
||||||
static std::string get_gl_info(bool format_as_html, bool extensions);
|
static std::string get_gl_info(bool format_as_html, bool extensions);
|
||||||
wxGLContext* init_glcontext(wxGLCanvas& canvas);
|
wxGLContext* init_glcontext(wxGLCanvas& canvas);
|
||||||
bool init_opengl();
|
bool init_opengl();
|
||||||
@ -241,7 +217,7 @@ public:
|
|||||||
static bool catch_error(std::function<void()> cb, const std::string& err);
|
static bool catch_error(std::function<void()> cb, const std::string& err);
|
||||||
|
|
||||||
void persist_window_geometry(wxTopLevelWindow *window, bool default_maximized = false);
|
void persist_window_geometry(wxTopLevelWindow *window, bool default_maximized = false);
|
||||||
void update_ui_from_settings();
|
void update_ui_from_settings(bool apply_free_camera_correction = true);
|
||||||
|
|
||||||
bool switch_language();
|
bool switch_language();
|
||||||
bool load_language(wxString language, bool initial);
|
bool load_language(wxString language, bool initial);
|
||||||
@ -278,12 +254,14 @@ public:
|
|||||||
Model& model();
|
Model& model();
|
||||||
|
|
||||||
|
|
||||||
|
// Parameters extracted from the command line to be passed to GUI after initialization.
|
||||||
|
const GUI_InitParams* init_params { nullptr };
|
||||||
|
|
||||||
AppConfig* app_config{ nullptr };
|
AppConfig* app_config{ nullptr };
|
||||||
PresetBundle* preset_bundle{ nullptr };
|
PresetBundle* preset_bundle{ nullptr };
|
||||||
PresetUpdater* preset_updater{ nullptr };
|
PresetUpdater* preset_updater{ nullptr };
|
||||||
MainFrame* mainframe{ nullptr };
|
MainFrame* mainframe{ nullptr };
|
||||||
Plater* plater_{ nullptr };
|
Plater* plater_{ nullptr };
|
||||||
AfterInitLoads after_init_loads;
|
|
||||||
std::mutex not_modal_dialog_mutex;
|
std::mutex not_modal_dialog_mutex;
|
||||||
wxDialog* not_modal_dialog = nullptr;
|
wxDialog* not_modal_dialog = nullptr;
|
||||||
|
|
||||||
|
96
src/slic3r/GUI/GUI_Init.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "GUI_Init.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/AppConfig.hpp"
|
||||||
|
|
||||||
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
|
#include "slic3r/GUI/3DScene.hpp"
|
||||||
|
#include "slic3r/GUI/InstanceCheck.hpp"
|
||||||
|
#include "slic3r/GUI/format.hpp"
|
||||||
|
#include "slic3r/GUI/MainFrame.hpp"
|
||||||
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
|
|
||||||
|
// To show a message box if GUI initialization ends up with an exception thrown.
|
||||||
|
#include <wx/msgdlg.h>
|
||||||
|
|
||||||
|
#include <boost/nowide/iostream.hpp>
|
||||||
|
#include <boost/nowide/convert.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
int GUI_Run(GUI_InitParams ¶ms)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
|
||||||
|
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
|
||||||
|
// G-code viewer is currently not performing instance check, a new G-code viewer is started every time.
|
||||||
|
bool gui_single_instance_setting = gui->app_config->get("single_instance") == "1";
|
||||||
|
if (Slic3r::instance_check(params.argc, params.argv, gui_single_instance_setting)) {
|
||||||
|
//TODO: do we have delete gui and other stuff?
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
GUI::GUI_App *gui = new GUI::GUI_App();
|
||||||
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
|
||||||
|
// gui->autosave = m_config.opt_string("autosave");
|
||||||
|
GUI::GUI_App::SetInstance(gui);
|
||||||
|
gui->init_params = ¶ms;
|
||||||
|
/*
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
gui->CallAfter([gui, this, &load_configs, params.start_as_gcodeviewer] {
|
||||||
|
#else
|
||||||
|
gui->CallAfter([gui, this, &load_configs] {
|
||||||
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
if (!gui->initialized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
if (params.start_as_gcodeviewer) {
|
||||||
|
if (!m_input_files.empty())
|
||||||
|
gui->plater()->load_gcode(wxString::FromUTF8(m_input_files[0].c_str()));
|
||||||
|
} else {
|
||||||
|
#endif // ENABLE_GCODE_VIEWER_AS
|
||||||
|
#if 0
|
||||||
|
// Load the cummulative config over the currently active profiles.
|
||||||
|
//FIXME if multiple configs are loaded, only the last one will have an effect.
|
||||||
|
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
|
||||||
|
// As of now only the full configs are supported here.
|
||||||
|
if (!m_print_config.empty())
|
||||||
|
gui->mainframe->load_config(m_print_config);
|
||||||
|
#endif
|
||||||
|
if (!load_configs.empty())
|
||||||
|
// Load the last config to give it a name at the UI. The name of the preset may be later
|
||||||
|
// changed by loading an AMF or 3MF.
|
||||||
|
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
|
||||||
|
gui->mainframe->load_config_file(load_configs.back());
|
||||||
|
// If loading a 3MF file, the config is loaded from the last one.
|
||||||
|
if (!m_input_files.empty())
|
||||||
|
gui->plater()->load_files(m_input_files, true, true);
|
||||||
|
if (!m_extra_config.empty())
|
||||||
|
gui->mainframe->load_config(m_extra_config);
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
}
|
||||||
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
int result = wxEntry(params.argc, params.argv);
|
||||||
|
return result;
|
||||||
|
} catch (const Slic3r::Exception &ex) {
|
||||||
|
boost::nowide::cerr << ex.what() << std::endl;
|
||||||
|
wxMessageBox(boost::nowide::widen(ex.what()), _L("PrusaSlicer GUI initialization failed"), wxICON_STOP);
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
boost::nowide::cerr << "PrusaSlicer GUI initialization failed: " << ex.what() << std::endl;
|
||||||
|
wxMessageBox(format_wxstr(_L("Fatal error, exception catched: %1%"), ex.what()), _L("PrusaSlicer GUI initialization failed"), wxICON_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
27
src/slic3r/GUI/GUI_Init.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef slic3r_GUI_Init_hpp_
|
||||||
|
#define slic3r_GUI_Init_hpp_
|
||||||
|
|
||||||
|
#include <libslic3r/PrintConfig.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
struct GUI_InitParams
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
std::vector<std::string> load_configs;
|
||||||
|
DynamicPrintConfig extra_config;
|
||||||
|
std::vector<std::string> input_files;
|
||||||
|
|
||||||
|
bool start_as_gcodeviewer;
|
||||||
|
};
|
||||||
|
|
||||||
|
int GUI_Run(GUI_InitParams ¶ms);
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // slic3r_GUI_Init_hpp_
|
@ -71,7 +71,6 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba
|
|||||||
|
|
||||||
m_canvas = new GLCanvas3D(m_canvas_widget);
|
m_canvas = new GLCanvas3D(m_canvas_widget);
|
||||||
m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
|
m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
|
||||||
m_canvas->bind_event_handlers();
|
|
||||||
|
|
||||||
m_canvas->allow_multisample(OpenGLManager::can_multisample());
|
m_canvas->allow_multisample(OpenGLManager::can_multisample());
|
||||||
// XXX: If have OpenGL
|
// XXX: If have OpenGL
|
||||||
@ -278,7 +277,6 @@ bool Preview::init(wxWindow* parent, Model* model)
|
|||||||
|
|
||||||
m_canvas = new GLCanvas3D(m_canvas_widget);
|
m_canvas = new GLCanvas3D(m_canvas_widget);
|
||||||
m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
|
m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget));
|
||||||
m_canvas->bind_event_handlers();
|
|
||||||
m_canvas->allow_multisample(OpenGLManager::can_multisample());
|
m_canvas->allow_multisample(OpenGLManager::can_multisample());
|
||||||
m_canvas->set_config(m_config);
|
m_canvas->set_config(m_config);
|
||||||
m_canvas->set_model(model);
|
m_canvas->set_model(model);
|
||||||
@ -368,7 +366,7 @@ bool Preview::init(wxWindow* parent, Model* model)
|
|||||||
#else
|
#else
|
||||||
m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel")));
|
m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel")));
|
||||||
m_checkbox_retractions = new wxCheckBox(this, wxID_ANY, _(L(width_screen == tiny ? "Retr." : "Retractions")));
|
m_checkbox_retractions = new wxCheckBox(this, wxID_ANY, _(L(width_screen == tiny ? "Retr." : "Retractions")));
|
||||||
m_checkbox_unretractions = new wxCheckBox(this, wxID_ANY, _(L(width_screen == tiny ? "Unre." : "Unretractions")));
|
m_checkbox_unretractions = new wxCheckBox(this, wxID_ANY, _(L(width_screen == tiny ? "Dere." : "Deretractions")));
|
||||||
m_checkbox_shells = new wxCheckBox(this, wxID_ANY, _(L("Shells")));
|
m_checkbox_shells = new wxCheckBox(this, wxID_ANY, _(L("Shells")));
|
||||||
m_checkbox_legend = new wxCheckBox(this, wxID_ANY, _(L("Legend")));
|
m_checkbox_legend = new wxCheckBox(this, wxID_ANY, _(L("Legend")));
|
||||||
m_checkbox_legend->SetValue(true);
|
m_checkbox_legend->SetValue(true);
|
||||||
@ -382,7 +380,6 @@ bool Preview::init(wxWindow* parent, Model* model)
|
|||||||
right_sizer->Add(m_layers_slider_sizer, 1, wxEXPAND, 0);
|
right_sizer->Add(m_layers_slider_sizer, 1, wxEXPAND, 0);
|
||||||
|
|
||||||
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxSize(-1, 3 * GetTextExtent("m").y), wxSL_HORIZONTAL);
|
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxSize(-1, 3 * GetTextExtent("m").y), wxSL_HORIZONTAL);
|
||||||
m_moves_slider->set_lower_editable(get_app_config()->get("seq_top_layer_only") == "0");
|
|
||||||
m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView);
|
m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView);
|
||||||
|
|
||||||
wxBoxSizer* bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer* bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
@ -598,9 +595,6 @@ void Preview::refresh_print()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
load_print(true);
|
load_print(true);
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
m_moves_slider->set_lower_editable(get_app_config()->get("seq_top_layer_only") == "0");
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preview::msw_rescale()
|
void Preview::msw_rescale()
|
||||||
@ -1314,17 +1308,13 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
if (wxGetApp().is_editor() && !has_layers)
|
if (wxGetApp().is_editor() && !has_layers) {
|
||||||
#else
|
|
||||||
if (! has_layers)
|
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
|
||||||
{
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
|
||||||
hide_layers_slider();
|
hide_layers_slider();
|
||||||
m_left_sizer->Hide(m_bottom_toolbar_panel);
|
m_left_sizer->Hide(m_bottom_toolbar_panel);
|
||||||
m_left_sizer->Layout();
|
m_left_sizer->Layout();
|
||||||
Refresh();
|
Refresh();
|
||||||
#else
|
#else
|
||||||
|
if (! has_layers) {
|
||||||
reset_sliders(true);
|
reset_sliders(true);
|
||||||
m_canvas->reset_legend_texture();
|
m_canvas->reset_legend_texture();
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
@ -1332,8 +1322,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_preferred_color_mode == "tool_or_feature")
|
if (m_preferred_color_mode == "tool_or_feature") {
|
||||||
{
|
|
||||||
// It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature.
|
// It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature.
|
||||||
// Color by feature if it is a single extruder print.
|
// Color by feature if it is a single extruder print.
|
||||||
unsigned int number_extruders = (unsigned int)print->extruders().size();
|
unsigned int number_extruders = (unsigned int)print->extruders().size();
|
||||||
@ -1362,18 +1351,21 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
|||||||
std::vector<CustomGCode::Item> color_print_values = {};
|
std::vector<CustomGCode::Item> color_print_values = {};
|
||||||
// set color print values, if it si selected "ColorPrint" view type
|
// set color print values, if it si selected "ColorPrint" view type
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
if (gcode_view_type == GCodeViewer::EViewType::ColorPrint)
|
if (gcode_view_type == GCodeViewer::EViewType::ColorPrint) {
|
||||||
#else
|
#else
|
||||||
if (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint)
|
if (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint) {
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
{
|
|
||||||
colors = wxGetApp().plater()->get_colors_for_color_print();
|
colors = wxGetApp().plater()->get_colors_for_color_print();
|
||||||
#if !ENABLE_GCODE_VIEWER
|
#if !ENABLE_GCODE_VIEWER
|
||||||
colors.push_back("#808080"); // gray color for pause print or custom G-code
|
colors.push_back("#808080"); // gray color for pause print or custom G-code
|
||||||
#endif // !ENABLE_GCODE_VIEWER
|
#endif // !ENABLE_GCODE_VIEWER
|
||||||
|
|
||||||
if (!gcode_preview_data_valid)
|
if (!gcode_preview_data_valid) {
|
||||||
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
|
color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
colors.push_back("#808080"); // gray color for pause print or custom G-code
|
||||||
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
else if (gcode_preview_data_valid || gcode_view_type == GCodeViewer::EViewType::Filament)
|
else if (gcode_preview_data_valid || gcode_view_type == GCodeViewer::EViewType::Filament)
|
||||||
@ -1408,8 +1400,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
|||||||
color_print_values.clear();
|
color_print_values.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsShown())
|
if (IsShown()) {
|
||||||
{
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
std::vector<double> zs;
|
std::vector<double> zs;
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
@ -1563,7 +1554,7 @@ wxString Preview::get_option_type_string(OptionType type) const
|
|||||||
{
|
{
|
||||||
case OptionType::Travel: { return _L("Travel"); }
|
case OptionType::Travel: { return _L("Travel"); }
|
||||||
case OptionType::Retractions: { return _L("Retractions"); }
|
case OptionType::Retractions: { return _L("Retractions"); }
|
||||||
case OptionType::Unretractions: { return _L("Unretractions"); }
|
case OptionType::Unretractions: { return _L("Deretractions"); }
|
||||||
case OptionType::ToolChanges: { return _L("Tool changes"); }
|
case OptionType::ToolChanges: { return _L("Tool changes"); }
|
||||||
case OptionType::ColorChanges: { return _L("Color changes"); }
|
case OptionType::ColorChanges: { return _L("Color changes"); }
|
||||||
case OptionType::PausePrints: { return _L("Pause prints"); }
|
case OptionType::PausePrints: { return _L("Pause prints"); }
|
||||||
|
@ -30,7 +30,7 @@ void GLGizmoFdmSupports::on_shutdown()
|
|||||||
|
|
||||||
std::string GLGizmoFdmSupports::on_get_name() const
|
std::string GLGizmoFdmSupports::on_get_name() const
|
||||||
{
|
{
|
||||||
return (_(L("FDM Support Editing")) + " [L]").ToUTF8().data();
|
return (_L("Paint-on supports") + " [L]").ToUTF8().data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ bool GLGizmoFlatten::on_init()
|
|||||||
|
|
||||||
void GLGizmoFlatten::on_set_state()
|
void GLGizmoFlatten::on_set_state()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
|
CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
|
||||||
@ -38,7 +37,7 @@ CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
|
|||||||
|
|
||||||
std::string GLGizmoFlatten::on_get_name() const
|
std::string GLGizmoFlatten::on_get_name() const
|
||||||
{
|
{
|
||||||
return (_(L("Place on face")) + " [F]").ToUTF8().data();
|
return (_L("Place on face") + " [F]").ToUTF8().data();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLGizmoFlatten::on_is_activable() const
|
bool GLGizmoFlatten::on_is_activable() const
|
||||||
@ -48,8 +47,7 @@ bool GLGizmoFlatten::on_is_activable() const
|
|||||||
|
|
||||||
void GLGizmoFlatten::on_start_dragging()
|
void GLGizmoFlatten::on_start_dragging()
|
||||||
{
|
{
|
||||||
if (m_hover_id != -1)
|
if (m_hover_id != -1) {
|
||||||
{
|
|
||||||
assert(m_planes_valid);
|
assert(m_planes_valid);
|
||||||
m_normal = m_planes[m_hover_id].normal;
|
m_normal = m_planes[m_hover_id].normal;
|
||||||
m_starting_center = m_parent.get_selection().get_bounding_box().center();
|
m_starting_center = m_parent.get_selection().get_bounding_box().center();
|
||||||
@ -65,16 +63,14 @@ void GLGizmoFlatten::on_render() const
|
|||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
glsafe(::glEnable(GL_BLEND));
|
glsafe(::glEnable(GL_BLEND));
|
||||||
|
|
||||||
if (selection.is_single_full_instance())
|
if (selection.is_single_full_instance()) {
|
||||||
{
|
|
||||||
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
||||||
glsafe(::glPushMatrix());
|
glsafe(::glPushMatrix());
|
||||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
||||||
glsafe(::glMultMatrixd(m.data()));
|
glsafe(::glMultMatrixd(m.data()));
|
||||||
if (this->is_plane_update_necessary())
|
if (this->is_plane_update_necessary())
|
||||||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
||||||
for (int i = 0; i < (int)m_planes.size(); ++i)
|
for (int i = 0; i < (int)m_planes.size(); ++i) {
|
||||||
{
|
|
||||||
if (i == m_hover_id)
|
if (i == m_hover_id)
|
||||||
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f));
|
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f));
|
||||||
else
|
else
|
||||||
@ -97,16 +93,14 @@ void GLGizmoFlatten::on_render_for_picking() const
|
|||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
|
|
||||||
if (selection.is_single_full_instance())
|
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) {
|
||||||
{
|
|
||||||
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
||||||
glsafe(::glPushMatrix());
|
glsafe(::glPushMatrix());
|
||||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
||||||
glsafe(::glMultMatrixd(m.data()));
|
glsafe(::glMultMatrixd(m.data()));
|
||||||
if (this->is_plane_update_necessary())
|
if (this->is_plane_update_necessary())
|
||||||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
||||||
for (int i = 0; i < (int)m_planes.size(); ++i)
|
for (int i = 0; i < (int)m_planes.size(); ++i) {
|
||||||
{
|
|
||||||
glsafe(::glColor4fv(picking_color_component(i).data()));
|
glsafe(::glColor4fv(picking_color_component(i).data()));
|
||||||
m_planes[i].vbo.render();
|
m_planes[i].vbo.render();
|
||||||
}
|
}
|
||||||
@ -129,8 +123,7 @@ void GLGizmoFlatten::update_planes()
|
|||||||
{
|
{
|
||||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||||
TriangleMesh ch;
|
TriangleMesh ch;
|
||||||
for (const ModelVolume* vol : mo->volumes)
|
for (const ModelVolume* vol : mo->volumes) {
|
||||||
{
|
|
||||||
if (vol->type() != ModelVolumeType::MODEL_PART)
|
if (vol->type() != ModelVolumeType::MODEL_PART)
|
||||||
continue;
|
continue;
|
||||||
TriangleMesh vol_ch = vol->get_convex_hull();
|
TriangleMesh vol_ch = vol->get_convex_hull();
|
||||||
|
@ -80,7 +80,7 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
|||||||
|
|
||||||
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
|
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
|
||||||
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } );
|
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } );
|
||||||
glsafe(::glPolygonOffset(-1.0, 1.0));
|
glsafe(::glPolygonOffset(-5.0, -5.0));
|
||||||
|
|
||||||
// Take care of the clipping plane. The normal of the clipping plane is
|
// Take care of the clipping plane. The normal of the clipping plane is
|
||||||
// saved with opposite sign than we need to pass to OpenGL (FIXME)
|
// saved with opposite sign than we need to pass to OpenGL (FIXME)
|
||||||
|
@ -43,7 +43,7 @@ bool GLGizmoSeam::on_init()
|
|||||||
|
|
||||||
std::string GLGizmoSeam::on_get_name() const
|
std::string GLGizmoSeam::on_get_name() const
|
||||||
{
|
{
|
||||||
return (_(L("Seam Editing")) + " [P]").ToUTF8().data();
|
return (_L("Seam painting") + " [P]").ToUTF8().data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -504,22 +504,22 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||||||
int selected_object_idx = selection.get_object_idx();
|
int selected_object_idx = selection.get_object_idx();
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
|
|
||||||
|
// when control is down we allow scene pan and rotation even when clicking over some object
|
||||||
|
bool control_down = evt.CmdDown();
|
||||||
|
|
||||||
// mouse anywhere
|
// mouse anywhere
|
||||||
if (evt.Moving())
|
if (evt.Moving())
|
||||||
m_tooltip = update_hover_state(mouse_pos);
|
m_tooltip = update_hover_state(mouse_pos);
|
||||||
else if (evt.LeftUp())
|
else if (evt.LeftUp()) {
|
||||||
{
|
if (m_mouse_capture.left) {
|
||||||
if (m_mouse_capture.left)
|
|
||||||
{
|
|
||||||
processed = true;
|
processed = true;
|
||||||
m_mouse_capture.left = false;
|
m_mouse_capture.left = false;
|
||||||
}
|
}
|
||||||
else if (is_dragging())
|
else if (is_dragging()) {
|
||||||
{
|
|
||||||
switch (m_current) {
|
switch (m_current) {
|
||||||
case Move: m_parent.do_move(L("Gizmo-Move")); break;
|
case Move: { m_parent.do_move(L("Gizmo-Move")); break; }
|
||||||
case Scale: m_parent.do_scale(L("Gizmo-Scale")); break;
|
case Scale: { m_parent.do_scale(L("Gizmo-Scale")); break; }
|
||||||
case Rotate: m_parent.do_rotate(L("Gizmo-Rotate")); break;
|
case Rotate: { m_parent.do_rotate(L("Gizmo-Rotate")); break; }
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,41 +538,34 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||||||
// else
|
// else
|
||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
else if (evt.MiddleUp())
|
else if (evt.MiddleUp()) {
|
||||||
{
|
if (m_mouse_capture.middle) {
|
||||||
if (m_mouse_capture.middle)
|
|
||||||
{
|
|
||||||
processed = true;
|
processed = true;
|
||||||
m_mouse_capture.middle = false;
|
m_mouse_capture.middle = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (evt.RightUp())
|
else if (evt.RightUp()) {
|
||||||
{
|
if (pending_right_up) {
|
||||||
if (pending_right_up)
|
|
||||||
{
|
|
||||||
pending_right_up = false;
|
pending_right_up = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_mouse_capture.right)
|
if (m_mouse_capture.right) {
|
||||||
{
|
|
||||||
processed = true;
|
processed = true;
|
||||||
m_mouse_capture.right = false;
|
m_mouse_capture.right = false;
|
||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && !is_dragging())
|
else if (evt.Dragging() && !is_dragging()) {
|
||||||
{
|
|
||||||
if (m_mouse_capture.any())
|
if (m_mouse_capture.any())
|
||||||
// if the button down was done on this toolbar, prevent from dragging into the scene
|
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||||
processed = true;
|
processed = true;
|
||||||
// else
|
// else
|
||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && is_dragging())
|
else if (evt.Dragging() && is_dragging()) {
|
||||||
{
|
|
||||||
if (!m_parent.get_wxglcanvas()->HasCapture())
|
if (!m_parent.get_wxglcanvas()->HasCapture())
|
||||||
m_parent.get_wxglcanvas()->CaptureMouse();
|
m_parent.get_wxglcanvas()->CaptureMouse();
|
||||||
|
|
||||||
@ -595,7 +588,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||||||
if (evt.AltDown())
|
if (evt.AltDown())
|
||||||
transformation_type.set_independent();
|
transformation_type.set_independent();
|
||||||
selection.scale(get_scale(), transformation_type);
|
selection.scale(get_scale(), transformation_type);
|
||||||
if (evt.ControlDown())
|
if (control_down)
|
||||||
selection.translate(get_scale_offset(), true);
|
selection.translate(get_scale_offset(), true);
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
break;
|
break;
|
||||||
@ -618,15 +611,13 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined)
|
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined) {
|
||||||
{
|
|
||||||
// mouse is outside the toolbar
|
// mouse is outside the toolbar
|
||||||
m_tooltip = "";
|
m_tooltip = "";
|
||||||
|
|
||||||
if (evt.LeftDown())
|
if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) {
|
||||||
{
|
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam)
|
||||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports ||m_current == Seam)
|
&& gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown()))
|
||||||
&& gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
|
|
||||||
// the gizmo got the event and took some action, there is no need to do anything more
|
// the gizmo got the event and took some action, there is no need to do anything more
|
||||||
processed = true;
|
processed = true;
|
||||||
else if (!selection.is_empty() && grabber_contains_mouse()) {
|
else if (!selection.is_empty() && grabber_contains_mouse()) {
|
||||||
@ -644,71 +635,67 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.RightDown() && (selected_object_idx != -1) && (m_current == SlaSupports || m_current == Hollow)
|
else if (evt.RightDown() && selected_object_idx != -1 && (m_current == SlaSupports || m_current == Hollow)
|
||||||
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos))
|
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) {
|
||||||
{
|
|
||||||
// we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object
|
// we need to set the following right up as processed to avoid showing the context menu if the user release the mouse over the object
|
||||||
pending_right_up = true;
|
pending_right_up = true;
|
||||||
// event was taken care of by the SlaSupports gizmo
|
// event was taken care of by the SlaSupports gizmo
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
else if (evt.RightDown() && (selected_object_idx != -1) && (m_current == FdmSupports || m_current == Seam)
|
else if (evt.RightDown() && !control_down && selected_object_idx != -1 && (m_current == FdmSupports || m_current == Seam)
|
||||||
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos))
|
&& gizmo_event(SLAGizmoEventType::RightDown, mouse_pos)) {
|
||||||
{
|
|
||||||
// event was taken care of by the FdmSupports / Seam gizmo
|
// event was taken care of by the FdmSupports / Seam gizmo
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1)
|
else if (evt.Dragging() && m_parent.get_move_volume_id() != -1
|
||||||
&& (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam))
|
&& (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam))
|
||||||
// don't allow dragging objects with the Sla gizmo on
|
// don't allow dragging objects with the Sla gizmo on
|
||||||
processed = true;
|
processed = true;
|
||||||
else if (evt.Dragging() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam )
|
else if (evt.Dragging() && !control_down && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam)
|
||||||
&& gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
|
&& gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown())) {
|
||||||
{
|
|
||||||
// the gizmo got the event and took some action, no need to do anything more here
|
// the gizmo got the event and took some action, no need to do anything more here
|
||||||
m_parent.set_as_dirty();
|
m_parent.set_as_dirty();
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam) && !m_parent.is_mouse_dragging())
|
else if (evt.Dragging() && control_down && (evt.LeftIsDown() || evt.RightIsDown())) {
|
||||||
{
|
// CTRL has been pressed while already dragging -> stop current action
|
||||||
|
if (evt.LeftIsDown())
|
||||||
|
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true);
|
||||||
|
else if (evt.RightIsDown())
|
||||||
|
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), true);
|
||||||
|
}
|
||||||
|
else if (evt.LeftUp() && (m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam) && !m_parent.is_mouse_dragging()) {
|
||||||
// in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither
|
// in case SLA/FDM gizmo is selected, we just pass the LeftUp event and stop processing - neither
|
||||||
// object moving or selecting is suppressed in that case
|
// object moving or selecting is suppressed in that case
|
||||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
|
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down);
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
else if (evt.LeftUp() && (m_current == Flatten) && (m_gizmos[m_current]->get_hover_id() != -1))
|
else if (evt.LeftUp() && m_current == Flatten && m_gizmos[m_current]->get_hover_id() != -1) {
|
||||||
{
|
|
||||||
// to avoid to loose the selection when user clicks an the white faces of a different object while the Flatten gizmo is active
|
// to avoid to loose the selection when user clicks an the white faces of a different object while the Flatten gizmo is active
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam) && !m_parent.is_mouse_dragging())
|
else if (evt.RightUp() && (m_current == FdmSupports || m_current == Seam) && !m_parent.is_mouse_dragging()) {
|
||||||
{
|
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), control_down);
|
||||||
gizmo_event(SLAGizmoEventType::RightUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
|
|
||||||
processed = true;
|
processed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// mouse inside toolbar
|
// mouse inside toolbar
|
||||||
if (evt.LeftDown() || evt.LeftDClick())
|
if (evt.LeftDown() || evt.LeftDClick()) {
|
||||||
{
|
|
||||||
m_mouse_capture.left = true;
|
m_mouse_capture.left = true;
|
||||||
m_mouse_capture.parent = &m_parent;
|
m_mouse_capture.parent = &m_parent;
|
||||||
processed = true;
|
processed = true;
|
||||||
if (!selection.is_empty())
|
if (!selection.is_empty()) {
|
||||||
{
|
|
||||||
update_on_off_state(mouse_pos);
|
update_on_off_state(mouse_pos);
|
||||||
update_data();
|
update_data();
|
||||||
m_parent.set_as_dirty();
|
m_parent.set_as_dirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (evt.MiddleDown())
|
else if (evt.MiddleDown()) {
|
||||||
{
|
|
||||||
m_mouse_capture.middle = true;
|
m_mouse_capture.middle = true;
|
||||||
m_mouse_capture.parent = &m_parent;
|
m_mouse_capture.parent = &m_parent;
|
||||||
}
|
}
|
||||||
else if (evt.RightDown())
|
else if (evt.RightDown()) {
|
||||||
{
|
|
||||||
m_mouse_capture.right = true;
|
m_mouse_capture.right = true;
|
||||||
m_mouse_capture.parent = &m_parent;
|
m_mouse_capture.parent = &m_parent;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "boost/nowide/convert.hpp"
|
#include "boost/nowide/convert.hpp"
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -136,6 +137,13 @@ namespace instance_check_internal
|
|||||||
fl.l_whence = SEEK_SET;
|
fl.l_whence = SEEK_SET;
|
||||||
fl.l_start = 0;
|
fl.l_start = 0;
|
||||||
fl.l_len = 1;
|
fl.l_len = 1;
|
||||||
|
|
||||||
|
if (! boost::filesystem::is_directory(path)) {
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "get_lock(): datadir does not exist yet, creating...";
|
||||||
|
if (! boost::filesystem::create_directories(path))
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "get_lock(): unable to create datadir !!!";
|
||||||
|
}
|
||||||
|
|
||||||
if ((fdlock = open(dest_dir.c_str(), O_WRONLY | O_CREAT, 0666)) == -1)
|
if ((fdlock = open(dest_dir.c_str(), O_WRONLY | O_CREAT, 0666)) == -1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Job.hpp"
|
#include "Job.hpp"
|
||||||
|
#include <libslic3r/Thread.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include <slic3r/Utils/Thread.hpp>
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
#include <slic3r/GUI/I18N.hpp>
|
#include <slic3r/GUI/I18N.hpp>
|
||||||
|
|
||||||
#include "ProgressIndicator.hpp"
|
#include "ProgressIndicator.hpp"
|
||||||
|
@ -178,7 +178,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||||||
{ "O", L("Zoom out") },
|
{ "O", L("Zoom out") },
|
||||||
{ "Tab", L("Switch between Editor/Preview") },
|
{ "Tab", L("Switch between Editor/Preview") },
|
||||||
{ "Shift+Tab", L("Collapse/Expand the sidebar") },
|
{ "Shift+Tab", L("Collapse/Expand the sidebar") },
|
||||||
#ifdef __linux__
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
{ ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") },
|
{ ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") },
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
#if ENABLE_RENDER_PICKING_PASS
|
#if ENABLE_RENDER_PICKING_PASS
|
||||||
@ -190,10 +190,13 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||||||
m_full_shortcuts.push_back(std::make_pair(_L("Plater"), plater_shortcuts));
|
m_full_shortcuts.push_back(std::make_pair(_L("Plater"), plater_shortcuts));
|
||||||
|
|
||||||
Shortcuts gizmos_shortcuts = {
|
Shortcuts gizmos_shortcuts = {
|
||||||
{ "Shift+", L("Press to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
|
{ ctrl, L("All gizmos: Press to rotate view with mouse left or to pan view with mouse right") },
|
||||||
{ "F", L("Scale selection to fit print volume\nin Gizmo scale") },
|
{ "Shift+", L("Gizmo move: Press to snap by 1mm") },
|
||||||
{ ctrl, L("Press to activate one direction scaling in Gizmo scale") },
|
{ "Shift+", L("Gizmo scale: Press to snap by 5%") },
|
||||||
{ alt, L("Press to scale (in Gizmo scale) or rotate (in Gizmo rotate)\nselected objects around their own center") },
|
{ "F", L("Gizmo scale: Scale selection to fit print volume") },
|
||||||
|
{ ctrl, L("Gizmo scale: Press to activate one direction scaling") },
|
||||||
|
{ alt, L("Gizmo scale: Press to scale selected objects around their own center") },
|
||||||
|
{ alt, L("Gizmo rotate: Press to rotate selected objects around their own center") },
|
||||||
};
|
};
|
||||||
|
|
||||||
m_full_shortcuts.push_back(std::make_pair(_L("Gizmos"), gizmos_shortcuts));
|
m_full_shortcuts.push_back(std::make_pair(_L("Gizmos"), gizmos_shortcuts));
|
||||||
@ -251,7 +254,11 @@ wxPanel* KBShortcutsDialog::create_header(wxWindow* parent, const wxFont& bold_f
|
|||||||
sizer->AddStretchSpacer();
|
sizer->AddStretchSpacer();
|
||||||
|
|
||||||
// logo
|
// logo
|
||||||
|
#if ENABLE_GCODE_VIEWER
|
||||||
|
m_logo_bmp = ScalableBitmap(this, wxGetApp().is_editor() ? "Slic3r_32px.png" : "PrusaSlicer-gcodeviewer_32px.png", 32);
|
||||||
|
#else
|
||||||
m_logo_bmp = ScalableBitmap(this, "Slic3r_32px.png", 32);
|
m_logo_bmp = ScalableBitmap(this, "Slic3r_32px.png", 32);
|
||||||
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
m_header_bitmap = new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp());
|
m_header_bitmap = new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp());
|
||||||
sizer->Add(m_header_bitmap, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
|
sizer->Add(m_header_bitmap, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
|
||||||
|
|
||||||
|
@ -1302,7 +1302,7 @@ void MainFrame::init_menubar()
|
|||||||
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &labels") + sep + "E", _L("Show object/instance labels in 3D scene"),
|
append_menu_check_item(viewMenu, wxID_ANY, _L("Show &labels") + sep + "E", _L("Show object/instance labels in 3D scene"),
|
||||||
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
|
[this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this,
|
||||||
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
|
[this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this);
|
||||||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse sidebar"), _L("Collapse sidebar"),
|
append_menu_check_item(viewMenu, wxID_ANY, _L("&Collapse sidebar") + "\tShift+Tab", _L("Collapse sidebar"),
|
||||||
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
|
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
|
||||||
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
|
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
|
||||||
}
|
}
|
||||||
@ -1989,7 +1989,7 @@ void MainFrame::add_to_recent_projects(const wxString& filename)
|
|||||||
//
|
//
|
||||||
// Called after the Preferences dialog is closed and the program settings are saved.
|
// Called after the Preferences dialog is closed and the program settings are saved.
|
||||||
// Update the UI based on the current preferences.
|
// Update the UI based on the current preferences.
|
||||||
void MainFrame::update_ui_from_settings()
|
void MainFrame::update_ui_from_settings(bool apply_free_camera_correction)
|
||||||
{
|
{
|
||||||
// const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
|
// const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
|
||||||
// m_menu_item_reslice_now->Enable(!bp_on);
|
// m_menu_item_reslice_now->Enable(!bp_on);
|
||||||
@ -1998,7 +1998,7 @@ void MainFrame::update_ui_from_settings()
|
|||||||
// m_plater->sidebar().Layout();
|
// m_plater->sidebar().Layout();
|
||||||
|
|
||||||
if (m_plater)
|
if (m_plater)
|
||||||
m_plater->update_ui_from_settings();
|
m_plater->update_ui_from_settings(apply_free_camera_correction);
|
||||||
for (auto tab: wxGetApp().tabs_list)
|
for (auto tab: wxGetApp().tabs_list)
|
||||||
tab->update_ui_from_settings();
|
tab->update_ui_from_settings();
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <wx/filehistory.h>
|
#include <wx/filehistory.h>
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <wx/taskbar.h>
|
#include <wx/taskbar.h>
|
||||||
#endif __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -167,7 +167,7 @@ public:
|
|||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
void update_menubar();
|
void update_menubar();
|
||||||
|
|
||||||
void update_ui_from_settings();
|
void update_ui_from_settings(bool apply_free_camera_correction = true);
|
||||||
bool is_loaded() const { return m_loaded; }
|
bool is_loaded() const { return m_loaded; }
|
||||||
bool is_last_input_file() const { return !m_qs_last_input_file.IsEmpty(); }
|
bool is_last_input_file() const { return !m_qs_last_input_file.IsEmpty(); }
|
||||||
bool is_dlg_layout() const { return m_layout == ESettingsLayout::Dlg; }
|
bool is_dlg_layout() const { return m_layout == ESettingsLayout::Dlg; }
|
||||||
|
@ -1645,7 +1645,7 @@ struct Plater::priv
|
|||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
|
|
||||||
void reset_all_gizmos();
|
void reset_all_gizmos();
|
||||||
void update_ui_from_settings();
|
void update_ui_from_settings(bool apply_free_camera_correction = true);
|
||||||
void update_main_toolbar_tooltips();
|
void update_main_toolbar_tooltips();
|
||||||
std::shared_ptr<ProgressStatusBar> statusbar();
|
std::shared_ptr<ProgressStatusBar> statusbar();
|
||||||
std::string get_config(const std::string &key) const;
|
std::string get_config(const std::string &key) const;
|
||||||
@ -1795,7 +1795,8 @@ struct Plater::priv
|
|||||||
// Caching last value of show_action_buttons parameter for show_action_buttons(), so that a callback which does not know this state will not override it.
|
// Caching last value of show_action_buttons parameter for show_action_buttons(), so that a callback which does not know this state will not override it.
|
||||||
mutable bool ready_to_slice = { false };
|
mutable bool ready_to_slice = { false };
|
||||||
// Flag indicating that the G-code export targets a removable device, therefore the show_action_buttons() needs to be called at any case when the background processing finishes.
|
// Flag indicating that the G-code export targets a removable device, therefore the show_action_buttons() needs to be called at any case when the background processing finishes.
|
||||||
bool writing_to_removable_device = { false };
|
bool writing_to_removable_device { false };
|
||||||
|
bool show_ExportToRemovableFinished_notification { false };
|
||||||
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
|
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
|
||||||
bool process_completed_with_error { false };
|
bool process_completed_with_error { false };
|
||||||
private:
|
private:
|
||||||
@ -2153,7 +2154,7 @@ void Plater::priv::select_view_3D(const std::string& name)
|
|||||||
set_current_panel(preview);
|
set_current_panel(preview);
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER
|
#if ENABLE_GCODE_VIEWER
|
||||||
wxGetApp().update_ui_from_settings();
|
wxGetApp().update_ui_from_settings(false);
|
||||||
#endif // ENABLE_GCODE_VIEWER
|
#endif // ENABLE_GCODE_VIEWER
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2186,10 +2187,10 @@ void Plater::priv::reset_all_gizmos()
|
|||||||
|
|
||||||
// Called after the Preferences dialog is closed and the program settings are saved.
|
// Called after the Preferences dialog is closed and the program settings are saved.
|
||||||
// Update the UI based on the current preferences.
|
// Update the UI based on the current preferences.
|
||||||
void Plater::priv::update_ui_from_settings()
|
void Plater::priv::update_ui_from_settings(bool apply_free_camera_correction)
|
||||||
{
|
{
|
||||||
camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
|
camera.set_type(wxGetApp().app_config->get("use_perspective_camera"));
|
||||||
if (wxGetApp().app_config->get("use_free_camera") != "1")
|
if (apply_free_camera_correction && wxGetApp().app_config->get("use_free_camera") != "1")
|
||||||
camera.recover_from_free_camera();
|
camera.recover_from_free_camera();
|
||||||
|
|
||||||
view3D->get_canvas3d()->update_ui_from_settings();
|
view3D->get_canvas3d()->update_ui_from_settings();
|
||||||
@ -3330,16 +3331,14 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||||||
if (current_panel == panel)
|
if (current_panel == panel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
wxPanel* old_panel = current_panel;
|
||||||
current_panel = panel;
|
current_panel = panel;
|
||||||
// to reduce flickering when changing view, first set as visible the new current panel
|
// to reduce flickering when changing view, first set as visible the new current panel
|
||||||
for (wxPanel* p : panels)
|
for (wxPanel* p : panels) {
|
||||||
{
|
if (p == current_panel) {
|
||||||
if (p == current_panel)
|
|
||||||
{
|
|
||||||
#ifdef __WXMAC__
|
#ifdef __WXMAC__
|
||||||
// On Mac we need also to force a render to avoid flickering when changing view
|
// On Mac we need also to force a render to avoid flickering when changing view
|
||||||
if (force_render)
|
if (force_render) {
|
||||||
{
|
|
||||||
if (p == view3D)
|
if (p == view3D)
|
||||||
dynamic_cast<View3D*>(p)->get_canvas3d()->render();
|
dynamic_cast<View3D*>(p)->get_canvas3d()->render();
|
||||||
else if (p == preview)
|
else if (p == preview)
|
||||||
@ -3350,21 +3349,22 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// then set to invisible the other
|
// then set to invisible the other
|
||||||
for (wxPanel* p : panels)
|
for (wxPanel* p : panels) {
|
||||||
{
|
|
||||||
if (p != current_panel)
|
if (p != current_panel)
|
||||||
p->Hide();
|
p->Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
panel_sizer->Layout();
|
panel_sizer->Layout();
|
||||||
|
|
||||||
if (current_panel == view3D)
|
if (current_panel == view3D) {
|
||||||
{
|
if (old_panel == preview)
|
||||||
if (view3D->is_reload_delayed())
|
preview->get_canvas3d()->unbind_event_handlers();
|
||||||
{
|
|
||||||
|
view3D->get_canvas3d()->bind_event_handlers();
|
||||||
|
|
||||||
|
if (view3D->is_reload_delayed()) {
|
||||||
// Delayed loading of the 3D scene.
|
// Delayed loading of the 3D scene.
|
||||||
if (this->printer_technology == ptSLA)
|
if (this->printer_technology == ptSLA) {
|
||||||
{
|
|
||||||
// Update the SLAPrint from the current Model, so that the reload_scene()
|
// Update the SLAPrint from the current Model, so that the reload_scene()
|
||||||
// pulls the correct data.
|
// pulls the correct data.
|
||||||
this->update_restart_background_process(true, false);
|
this->update_restart_background_process(true, false);
|
||||||
@ -3378,8 +3378,12 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||||||
if(notification_manager != nullptr)
|
if(notification_manager != nullptr)
|
||||||
notification_manager->set_in_preview(false);
|
notification_manager->set_in_preview(false);
|
||||||
}
|
}
|
||||||
else if (current_panel == preview)
|
else if (current_panel == preview) {
|
||||||
{
|
if (old_panel == view3D)
|
||||||
|
view3D->get_canvas3d()->unbind_event_handlers();
|
||||||
|
|
||||||
|
preview->get_canvas3d()->bind_event_handlers();
|
||||||
|
|
||||||
// see: Plater::priv::object_list_changed()
|
// see: Plater::priv::object_list_changed()
|
||||||
// FIXME: it may be better to have a single function making this check and let it be called wherever needed
|
// FIXME: it may be better to have a single function making this check and let it be called wherever needed
|
||||||
bool export_in_progress = this->background_process.is_export_scheduled();
|
bool export_in_progress = this->background_process.is_export_scheduled();
|
||||||
@ -3538,6 +3542,8 @@ void Plater::priv::on_export_began(wxCommandEvent& evt)
|
|||||||
{
|
{
|
||||||
if (show_warning_dialog)
|
if (show_warning_dialog)
|
||||||
warnings_dialog();
|
warnings_dialog();
|
||||||
|
if (this->writing_to_removable_device)
|
||||||
|
this->show_ExportToRemovableFinished_notification = true;
|
||||||
}
|
}
|
||||||
void Plater::priv::on_slicing_began()
|
void Plater::priv::on_slicing_began()
|
||||||
{
|
{
|
||||||
@ -3652,11 +3658,12 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||||||
else if (wxGetApp().get_mode() == comSimple && wxGetApp().app_config->get("objects_always_expert") != "1") {
|
else if (wxGetApp().get_mode() == comSimple && wxGetApp().app_config->get("objects_always_expert") != "1") {
|
||||||
show_action_buttons(false);
|
show_action_buttons(false);
|
||||||
}
|
}
|
||||||
else if (this->writing_to_removable_device)
|
// If writing to removable drive was scheduled, show notification with eject button
|
||||||
{
|
if (this->writing_to_removable_device && this->show_ExportToRemovableFinished_notification) {
|
||||||
show_action_buttons(false);
|
show_action_buttons(false);
|
||||||
notification_manager->push_notification(NotificationType::ExportToRemovableFinished, *q->get_current_canvas3D());
|
notification_manager->push_notification(NotificationType::ExportToRemovableFinished, *q->get_current_canvas3D());
|
||||||
}
|
}
|
||||||
|
this->show_ExportToRemovableFinished_notification = false;
|
||||||
this->writing_to_removable_device = false;
|
this->writing_to_removable_device = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4736,7 +4743,9 @@ void Plater::load_gcode()
|
|||||||
|
|
||||||
void Plater::load_gcode(const wxString& filename)
|
void Plater::load_gcode(const wxString& filename)
|
||||||
{
|
{
|
||||||
if (filename.empty() || m_last_loaded_gcode == filename)
|
if (filename.empty() ||
|
||||||
|
(!filename.Lower().EndsWith(".gcode") && !filename.Lower().EndsWith(".g")) ||
|
||||||
|
m_last_loaded_gcode == filename)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_last_loaded_gcode = filename;
|
m_last_loaded_gcode = filename;
|
||||||
@ -4784,7 +4793,7 @@ void Plater::update() { p->update(); }
|
|||||||
|
|
||||||
void Plater::stop_jobs() { p->m_ui_jobs.stop_all(); }
|
void Plater::stop_jobs() { p->m_ui_jobs.stop_all(); }
|
||||||
|
|
||||||
void Plater::update_ui_from_settings() { p->update_ui_from_settings(); }
|
void Plater::update_ui_from_settings(bool apply_free_camera_correction) { p->update_ui_from_settings(apply_free_camera_correction); }
|
||||||
|
|
||||||
void Plater::select_view(const std::string& direction) { p->select_view(direction); }
|
void Plater::select_view(const std::string& direction) { p->select_view(direction); }
|
||||||
|
|
||||||
@ -5022,12 +5031,13 @@ void Plater::export_gcode(bool prefer_removable)
|
|||||||
|
|
||||||
if (! output_path.empty()) {
|
if (! output_path.empty()) {
|
||||||
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
|
bool path_on_removable_media = removable_drive_manager.set_and_verify_last_save_path(output_path.string());
|
||||||
|
p->writing_to_removable_device = path_on_removable_media;
|
||||||
p->export_gcode(output_path, path_on_removable_media, PrintHostJob());
|
p->export_gcode(output_path, path_on_removable_media, PrintHostJob());
|
||||||
// Storing a path to AppConfig either as path to removable media or a path to internal media.
|
// Storing a path to AppConfig either as path to removable media or a path to internal media.
|
||||||
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
|
// is_path_on_removable_drive() is called with the "true" parameter to update its internal database as the user may have shuffled the external drives
|
||||||
// while the dialog was open.
|
// while the dialog was open.
|
||||||
appconfig.update_last_output_dir(output_path.parent_path().string(), path_on_removable_media);
|
appconfig.update_last_output_dir(output_path.parent_path().string(), path_on_removable_media);
|
||||||
p->writing_to_removable_device = path_on_removable_media;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ public:
|
|||||||
|
|
||||||
// Called after the Preferences dialog is closed and the program settings are saved.
|
// Called after the Preferences dialog is closed and the program settings are saved.
|
||||||
// Update the UI based on the current preferences.
|
// Update the UI based on the current preferences.
|
||||||
void update_ui_from_settings();
|
void update_ui_from_settings(bool apply_free_camera_correction = true);
|
||||||
|
|
||||||
void select_all();
|
void select_all();
|
||||||
void deselect_all();
|
void deselect_all();
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "../Utils/UndoRedo.hpp"
|
#include "../Utils/UndoRedo.hpp"
|
||||||
#include "BitmapCache.hpp"
|
#include "BitmapCache.hpp"
|
||||||
#include "PhysicalPrinterDialog.hpp"
|
#include "PhysicalPrinterDialog.hpp"
|
||||||
|
#include "SavePresetDialog.hpp"
|
||||||
|
|
||||||
using Slic3r::GUI::format_wxstr;
|
using Slic3r::GUI::format_wxstr;
|
||||||
|
|
||||||
@ -247,6 +248,51 @@ void PresetComboBox::update(std::string select_preset_name)
|
|||||||
Thaw();
|
Thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PresetComboBox::edit_physical_printer()
|
||||||
|
{
|
||||||
|
if (!m_preset_bundle->physical_printers.has_selection())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PhysicalPrinterDialog dlg(this->GetString(this->GetSelection()));
|
||||||
|
if (dlg.ShowModal() == wxID_OK)
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PresetComboBox::add_physical_printer()
|
||||||
|
{
|
||||||
|
if (PhysicalPrinterDialog(wxEmptyString).ShowModal() == wxID_OK)
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PresetComboBox::del_physical_printer(const wxString& note_string/* = wxEmptyString*/)
|
||||||
|
{
|
||||||
|
const std::string& printer_name = m_preset_bundle->physical_printers.get_selected_full_printer_name();
|
||||||
|
if (printer_name.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wxString msg;
|
||||||
|
if (!note_string.IsEmpty())
|
||||||
|
msg += note_string + "\n";
|
||||||
|
msg += format_wxstr(_L("Are you sure you want to delete \"%1%\" printer?"), printer_name);
|
||||||
|
|
||||||
|
if (wxMessageDialog(this, msg, _L("Delete Physical Printer"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal() != wxID_YES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_preset_bundle->physical_printers.delete_selected_printer();
|
||||||
|
|
||||||
|
this->update();
|
||||||
|
|
||||||
|
if (dynamic_cast<PlaterPresetComboBox*>(this) != nullptr)
|
||||||
|
wxGetApp().get_tab(m_type)->update_preset_choice();
|
||||||
|
else if (dynamic_cast<TabPresetComboBox*>(this) != nullptr)
|
||||||
|
{
|
||||||
|
wxGetApp().get_tab(m_type)->update_btns_enabling();
|
||||||
|
wxGetApp().plater()->sidebar().update_presets(m_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void PresetComboBox::update()
|
void PresetComboBox::update()
|
||||||
{
|
{
|
||||||
this->update(into_u8(this->GetString(this->GetSelection())));
|
this->update(into_u8(this->GetString(this->GetSelection())));
|
||||||
@ -312,7 +358,7 @@ wxBitmap* PresetComboBox::get_bmp( std::string bitmap_key, bool wide_icons, con
|
|||||||
// Paint a red flag for incompatible presets.
|
// Paint a red flag for incompatible presets.
|
||||||
bmps.emplace_back(is_compatible ? bitmap_cache().mkclear(norm_icon_width, icon_height) : m_bitmapIncompatible.bmp());
|
bmps.emplace_back(is_compatible ? bitmap_cache().mkclear(norm_icon_width, icon_height) : m_bitmapIncompatible.bmp());
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_FILAMENT)
|
if (m_type == Preset::TYPE_FILAMENT && !filament_rgb.empty())
|
||||||
{
|
{
|
||||||
unsigned char rgb[3];
|
unsigned char rgb[3];
|
||||||
// Paint the color bars.
|
// Paint the color bars.
|
||||||
@ -641,28 +687,11 @@ void PlaterPresetComboBox::show_edit_menu()
|
|||||||
[this](wxCommandEvent&) { this->switch_to_tab(); }, "cog", menu, []() { return true; }, wxGetApp().plater());
|
[this](wxCommandEvent&) { this->switch_to_tab(); }, "cog", menu, []() { return true; }, wxGetApp().plater());
|
||||||
|
|
||||||
if (this->is_selected_physical_printer()) {
|
if (this->is_selected_physical_printer()) {
|
||||||
append_menu_item(menu, wxID_ANY, _L("Edit physical printer"), "",
|
append_menu_item(menu, wxID_ANY, _L("Edit physical printer"), "",
|
||||||
[this](wxCommandEvent&) {
|
[this](wxCommandEvent&) { this->edit_physical_printer(); }, "cog", menu, []() { return true; }, wxGetApp().plater());
|
||||||
PhysicalPrinterDialog dlg(this->GetString(this->GetSelection()));
|
|
||||||
if (dlg.ShowModal() == wxID_OK)
|
|
||||||
update();
|
|
||||||
}, "cog", menu, []() { return true; }, wxGetApp().plater());
|
|
||||||
|
|
||||||
append_menu_item(menu, wxID_ANY, _L("Delete physical printer"), "",
|
append_menu_item(menu, wxID_ANY, _L("Delete physical printer"), "",
|
||||||
[this](wxCommandEvent&) {
|
[this](wxCommandEvent&) { this->del_physical_printer(); }, "cross", menu, []() { return true; }, wxGetApp().plater());
|
||||||
const std::string& printer_name = m_preset_bundle->physical_printers.get_selected_full_printer_name();
|
|
||||||
if (printer_name.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const wxString msg = from_u8((boost::format(_u8L("Are you sure you want to delete \"%1%\" printer?")) % printer_name).str());
|
|
||||||
if (wxMessageDialog(this, msg, _L("Delete Physical Printer"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal() != wxID_YES)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_preset_bundle->physical_printers.delete_selected_printer();
|
|
||||||
|
|
||||||
wxGetApp().get_tab(m_type)->update_preset_choice();
|
|
||||||
update();
|
|
||||||
}, "cross", menu, []() { return true; }, wxGetApp().plater());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
append_menu_item(menu, wxID_ANY, _L("Add/Remove presets"), "",
|
append_menu_item(menu, wxID_ANY, _L("Add/Remove presets"), "",
|
||||||
@ -671,11 +700,7 @@ void PlaterPresetComboBox::show_edit_menu()
|
|||||||
}, "edit_uni", menu, []() { return true; }, wxGetApp().plater());
|
}, "edit_uni", menu, []() { return true; }, wxGetApp().plater());
|
||||||
|
|
||||||
append_menu_item(menu, wxID_ANY, _L("Add physical printer"), "",
|
append_menu_item(menu, wxID_ANY, _L("Add physical printer"), "",
|
||||||
[this](wxCommandEvent&) {
|
[this](wxCommandEvent&) { this->add_physical_printer(); }, "edit_uni", menu, []() { return true; }, wxGetApp().plater());
|
||||||
PhysicalPrinterDialog dlg(wxEmptyString);
|
|
||||||
if (dlg.ShowModal() == wxID_OK)
|
|
||||||
update();
|
|
||||||
}, "edit_uni", menu, []() { return true; }, wxGetApp().plater());
|
|
||||||
|
|
||||||
wxGetApp().plater()->PopupMenu(menu);
|
wxGetApp().plater()->PopupMenu(menu);
|
||||||
}
|
}
|
||||||
@ -804,11 +829,13 @@ void PlaterPresetComboBox::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_SLA_MATERIAL) {
|
if (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_FILAMENT || m_type == Preset::TYPE_SLA_MATERIAL) {
|
||||||
wxBitmap* bmp = get_bmp("edit_preset_list", wide_icons, "edit_uni");
|
wxBitmap* bmp = get_bmp("edit_preset_list", wide_icons, "edit_uni");
|
||||||
assert(bmp);
|
assert(bmp);
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_SLA_MATERIAL)
|
if (m_type == Preset::TYPE_FILAMENT)
|
||||||
|
set_label_marker(Append(separator(L("Add/Remove filaments")), *bmp), LABEL_ITEM_WIZARD_FILAMENTS);
|
||||||
|
else if (m_type == Preset::TYPE_SLA_MATERIAL)
|
||||||
set_label_marker(Append(separator(L("Add/Remove materials")), *bmp), LABEL_ITEM_WIZARD_MATERIALS);
|
set_label_marker(Append(separator(L("Add/Remove materials")), *bmp), LABEL_ITEM_WIZARD_MATERIALS);
|
||||||
else
|
else
|
||||||
set_label_marker(Append(separator(L("Add/Remove printers")), *bmp), LABEL_ITEM_WIZARD_PRINTERS);
|
set_label_marker(Append(separator(L("Add/Remove printers")), *bmp), LABEL_ITEM_WIZARD_PRINTERS);
|
||||||
@ -1022,348 +1049,4 @@ void TabPresetComboBox::update_dirty()
|
|||||||
#endif /* __APPLE __ */
|
#endif /* __APPLE __ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------
|
|
||||||
// SavePresetDialog::Item
|
|
||||||
//-----------------------------------------------
|
|
||||||
|
|
||||||
SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent):
|
|
||||||
m_type(type),
|
|
||||||
m_parent(parent)
|
|
||||||
{
|
|
||||||
Tab* tab = wxGetApp().get_tab(m_type);
|
|
||||||
assert(tab);
|
|
||||||
m_presets = tab->get_presets();
|
|
||||||
|
|
||||||
const Preset& sel_preset = m_presets->get_selected_preset();
|
|
||||||
std::string preset_name = sel_preset.is_default ? "Untitled" :
|
|
||||||
sel_preset.is_system ? (boost::format(("%1% - %2%")) % sel_preset.name % suffix).str() :
|
|
||||||
sel_preset.name;
|
|
||||||
|
|
||||||
// if name contains extension
|
|
||||||
if (boost::iends_with(preset_name, ".ini")) {
|
|
||||||
size_t len = preset_name.length() - 4;
|
|
||||||
preset_name.resize(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> values;
|
|
||||||
for (const Preset& preset : *m_presets) {
|
|
||||||
if (preset.is_default || preset.is_system || preset.is_external)
|
|
||||||
continue;
|
|
||||||
values.push_back(preset.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
wxStaticText* label_top = new wxStaticText(m_parent, wxID_ANY, from_u8((boost::format(_utf8(L("Save %s as:"))) % into_u8(tab->title())).str()));
|
|
||||||
|
|
||||||
m_valid_bmp = new wxStaticBitmap(m_parent, wxID_ANY, create_scaled_bitmap("tick_mark", m_parent));
|
|
||||||
|
|
||||||
m_combo = new wxComboBox(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1));
|
|
||||||
for (const std::string& value : values)
|
|
||||||
m_combo->Append(from_u8(value));
|
|
||||||
|
|
||||||
m_combo->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); });
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
// Under OSX wxEVT_TEXT wasn't invoked after change selection in combobox,
|
|
||||||
// So process wxEVT_COMBOBOX too
|
|
||||||
m_combo->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { update(); });
|
|
||||||
#endif //__WXOSX__
|
|
||||||
|
|
||||||
m_valid_label = new wxStaticText(m_parent, wxID_ANY, "");
|
|
||||||
m_valid_label->SetFont(wxGetApp().bold_font());
|
|
||||||
|
|
||||||
wxBoxSizer* combo_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
combo_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W);
|
|
||||||
combo_sizer->Add(m_combo, 1, wxEXPAND, BORDER_W);
|
|
||||||
|
|
||||||
sizer->Add(label_top, 0, wxEXPAND | wxTOP| wxBOTTOM, BORDER_W);
|
|
||||||
sizer->Add(combo_sizer, 0, wxEXPAND | wxBOTTOM, BORDER_W);
|
|
||||||
sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W);
|
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_PRINTER)
|
|
||||||
m_parent->add_info_for_edit_ph_printer(sizer);
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::Item::update()
|
|
||||||
{
|
|
||||||
m_preset_name = into_u8(m_combo->GetValue());
|
|
||||||
|
|
||||||
m_valid_type = Valid;
|
|
||||||
wxString info_line;
|
|
||||||
|
|
||||||
const char* unusable_symbols = "<>[]:/\\|?*\"";
|
|
||||||
|
|
||||||
const std::string unusable_suffix = PresetCollection::get_suffix_modified();//"(modified)";
|
|
||||||
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
|
|
||||||
if (m_preset_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
|
|
||||||
info_line = _L("The supplied name is not valid;") + "\n" +
|
|
||||||
_L("the following characters are not allowed:") + " " + unusable_symbols;
|
|
||||||
m_valid_type = NoValid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_valid_type == Valid && m_preset_name.find(unusable_suffix) != std::string::npos) {
|
|
||||||
info_line = _L("The supplied name is not valid;") + "\n" +
|
|
||||||
_L("the following suffix is not allowed:") + "\n\t" +
|
|
||||||
from_u8(PresetCollection::get_suffix_modified());
|
|
||||||
m_valid_type = NoValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_valid_type == Valid && m_preset_name == "- default -") {
|
|
||||||
info_line = _L("The supplied name is not available.");
|
|
||||||
m_valid_type = NoValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Preset* existing = m_presets->find_preset(m_preset_name, false);
|
|
||||||
if (m_valid_type == Valid && existing && (existing->is_default || existing->is_system)) {
|
|
||||||
info_line = _L("Cannot overwrite a system profile.");
|
|
||||||
m_valid_type = NoValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_valid_type == Valid && existing && (existing->is_external)) {
|
|
||||||
info_line = _L("Cannot overwrite an external profile.");
|
|
||||||
m_valid_type = NoValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_valid_type == Valid && existing && m_preset_name != m_presets->get_selected_preset_name())
|
|
||||||
{
|
|
||||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str());
|
|
||||||
if (!existing->is_compatible)
|
|
||||||
info_line += "\n" + _L("And selected preset is imcopatible with selected printer.");
|
|
||||||
info_line += "\n" + _L("Note: This preset will be replaced after saving");
|
|
||||||
m_valid_type = Warning;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_valid_type == Valid && m_preset_name.empty()) {
|
|
||||||
info_line = _L("The empty name is not available.");
|
|
||||||
m_valid_type = NoValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_valid_label->SetLabel(info_line);
|
|
||||||
m_valid_label->Show(!info_line.IsEmpty());
|
|
||||||
|
|
||||||
update_valid_bmp();
|
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_PRINTER)
|
|
||||||
m_parent->update_info_for_edit_ph_printer(m_preset_name);
|
|
||||||
|
|
||||||
m_parent->layout();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::Item::update_valid_bmp()
|
|
||||||
{
|
|
||||||
std::string bmp_name = m_valid_type == Warning ? "exclamation" :
|
|
||||||
m_valid_type == NoValid ? "cross" : "tick_mark" ;
|
|
||||||
m_valid_bmp->SetBitmap(create_scaled_bitmap(bmp_name, m_parent));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::Item::accept()
|
|
||||||
{
|
|
||||||
if (m_valid_type == Warning)
|
|
||||||
m_presets->delete_preset(m_preset_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------
|
|
||||||
// SavePresetDialog
|
|
||||||
//-----------------------------------------------
|
|
||||||
|
|
||||||
SavePresetDialog::SavePresetDialog(Preset::Type type, std::string suffix)
|
|
||||||
: DPIDialog(nullptr, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
|
||||||
{
|
|
||||||
build(std::vector<Preset::Type>{type}, suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
SavePresetDialog::SavePresetDialog(std::vector<Preset::Type> types, std::string suffix)
|
|
||||||
: DPIDialog(nullptr, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
|
||||||
{
|
|
||||||
build(types, suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
SavePresetDialog::~SavePresetDialog()
|
|
||||||
{
|
|
||||||
for (auto item : m_items) {
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::build(std::vector<Preset::Type> types, std::string suffix)
|
|
||||||
{
|
|
||||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
|
||||||
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
|
|
||||||
// ys_FIXME! temporary workaround for correct font scaling
|
|
||||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
|
||||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
|
||||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
|
||||||
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
|
||||||
|
|
||||||
if (suffix.empty())
|
|
||||||
suffix = _CTX_utf8(L_CONTEXT("Copy", "PresetName"), "PresetName");
|
|
||||||
|
|
||||||
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
m_presets_sizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
// Add first item
|
|
||||||
for (Preset::Type type : types)
|
|
||||||
AddItem(type, suffix);
|
|
||||||
|
|
||||||
// Add dialog's buttons
|
|
||||||
wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
|
||||||
wxButton* btnOK = static_cast<wxButton*>(this->FindWindowById(wxID_OK, this));
|
|
||||||
btnOK->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { accept(); });
|
|
||||||
btnOK->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(enable_ok_btn()); });
|
|
||||||
|
|
||||||
topSizer->Add(m_presets_sizer, 0, wxEXPAND | wxALL, BORDER_W);
|
|
||||||
topSizer->Add(btns, 0, wxEXPAND | wxALL, BORDER_W);
|
|
||||||
|
|
||||||
SetSizer(topSizer);
|
|
||||||
topSizer->SetSizeHints(this);
|
|
||||||
|
|
||||||
this->CenterOnScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::AddItem(Preset::Type type, const std::string& suffix)
|
|
||||||
{
|
|
||||||
m_items.emplace_back(new Item{type, suffix, m_presets_sizer, this});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SavePresetDialog::get_name()
|
|
||||||
{
|
|
||||||
return m_items.front()->preset_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SavePresetDialog::get_name(Preset::Type type)
|
|
||||||
{
|
|
||||||
for (const Item* item : m_items)
|
|
||||||
if (item->type() == type)
|
|
||||||
return item->preset_name();
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SavePresetDialog::enable_ok_btn() const
|
|
||||||
{
|
|
||||||
for (const Item* item : m_items)
|
|
||||||
if (!item->is_valid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::add_info_for_edit_ph_printer(wxBoxSizer* sizer)
|
|
||||||
{
|
|
||||||
PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers;
|
|
||||||
m_ph_printer_name = printers.get_selected_printer_name();
|
|
||||||
m_old_preset_name = printers.get_selected_printer_preset_name();
|
|
||||||
|
|
||||||
wxString msg_text = from_u8((boost::format(_u8L("You have selected physical printer \"%1%\" \n"
|
|
||||||
"with related printer preset \"%2%\"")) %
|
|
||||||
m_ph_printer_name % m_old_preset_name).str());
|
|
||||||
m_label = new wxStaticText(this, wxID_ANY, msg_text);
|
|
||||||
m_label->SetFont(wxGetApp().bold_font());
|
|
||||||
|
|
||||||
wxString choices[] = {"","",""};
|
|
||||||
|
|
||||||
m_action_radio_box = new wxRadioBox(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
|
|
||||||
WXSIZEOF(choices), choices, 3, wxRA_SPECIFY_ROWS);
|
|
||||||
m_action_radio_box->SetSelection(0);
|
|
||||||
m_action_radio_box->Bind(wxEVT_RADIOBOX, [this](wxCommandEvent& e) {
|
|
||||||
m_action = (ActionType)e.GetSelection(); });
|
|
||||||
m_action = ChangePreset;
|
|
||||||
|
|
||||||
m_radio_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
m_radio_sizer->Add(m_action_radio_box, 1, wxEXPAND | wxTOP, 2*BORDER_W);
|
|
||||||
|
|
||||||
sizer->Add(m_label, 0, wxEXPAND | wxLEFT | wxTOP, 3*BORDER_W);
|
|
||||||
sizer->Add(m_radio_sizer, 1, wxEXPAND | wxLEFT, 3*BORDER_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::update_info_for_edit_ph_printer(const std::string& preset_name)
|
|
||||||
{
|
|
||||||
bool show = wxGetApp().preset_bundle->physical_printers.has_selection() && m_old_preset_name != preset_name;
|
|
||||||
|
|
||||||
m_label->Show(show);
|
|
||||||
m_radio_sizer->ShowItems(show);
|
|
||||||
if (!show) {
|
|
||||||
this->SetMinSize(wxSize(100,50));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxString msg_text = from_u8((boost::format(_u8L("What would you like to do with \"%1%\" preset after saving?")) % preset_name).str());
|
|
||||||
m_action_radio_box->SetLabel(msg_text);
|
|
||||||
|
|
||||||
wxString choices[] = { from_u8((boost::format(_u8L("Change \"%1%\" to \"%2%\" for this physical printer \"%3%\"")) % m_old_preset_name % preset_name % m_ph_printer_name).str()),
|
|
||||||
from_u8((boost::format(_u8L("Add \"%1%\" as a next preset for the the physical printer \"%2%\"")) % preset_name % m_ph_printer_name).str()),
|
|
||||||
from_u8((boost::format(_u8L("Just switch to \"%1%\" preset")) % preset_name).str()) };
|
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
for(const wxString& label: choices)
|
|
||||||
m_action_radio_box->SetString(n++, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::layout()
|
|
||||||
{
|
|
||||||
this->Layout();
|
|
||||||
this->Fit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::on_dpi_changed(const wxRect& suggested_rect)
|
|
||||||
{
|
|
||||||
const int& em = em_unit();
|
|
||||||
|
|
||||||
msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
|
|
||||||
|
|
||||||
for (Item* item : m_items)
|
|
||||||
item->update_valid_bmp();
|
|
||||||
|
|
||||||
//const wxSize& size = wxSize(45 * em, 35 * em);
|
|
||||||
SetMinSize(/*size*/wxSize(100, 50));
|
|
||||||
|
|
||||||
Fit();
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::update_physical_printers(const std::string& preset_name)
|
|
||||||
{
|
|
||||||
if (m_action == UndefAction)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PhysicalPrinterCollection& physical_printers = wxGetApp().preset_bundle->physical_printers;
|
|
||||||
if (!physical_printers.has_selection())
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string printer_preset_name = physical_printers.get_selected_printer_preset_name();
|
|
||||||
|
|
||||||
if (m_action == Switch)
|
|
||||||
// unselect physical printer, if it was selected
|
|
||||||
physical_printers.unselect_printer();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PhysicalPrinter printer = physical_printers.get_selected_printer();
|
|
||||||
|
|
||||||
if (m_action == ChangePreset)
|
|
||||||
printer.delete_preset(printer_preset_name);
|
|
||||||
|
|
||||||
if (printer.add_preset(preset_name))
|
|
||||||
physical_printers.save_printer(printer);
|
|
||||||
|
|
||||||
physical_printers.select_printer(printer.get_full_name(preset_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SavePresetDialog::accept()
|
|
||||||
{
|
|
||||||
for (Item* item : m_items) {
|
|
||||||
item->accept();
|
|
||||||
if (item->type() == Preset::TYPE_PRINTER)
|
|
||||||
update_physical_printers(item->preset_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
EndModal(wxID_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
@ -59,6 +59,10 @@ public:
|
|||||||
|
|
||||||
void update(std::string select_preset);
|
void update(std::string select_preset);
|
||||||
|
|
||||||
|
void edit_physical_printer();
|
||||||
|
void add_physical_printer();
|
||||||
|
bool del_physical_printer(const wxString& note_string = wxEmptyString);
|
||||||
|
|
||||||
virtual void update();
|
virtual void update();
|
||||||
virtual void msw_rescale();
|
virtual void msw_rescale();
|
||||||
|
|
||||||
@ -187,91 +191,6 @@ public:
|
|||||||
Preset::Type type() const { return m_type; }
|
Preset::Type type() const { return m_type; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------
|
|
||||||
// SavePresetDialog
|
|
||||||
//------------------------------------------------
|
|
||||||
|
|
||||||
class SavePresetDialog : public DPIDialog
|
|
||||||
{
|
|
||||||
enum ActionType
|
|
||||||
{
|
|
||||||
ChangePreset,
|
|
||||||
AddPreset,
|
|
||||||
Switch,
|
|
||||||
UndefAction
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Item
|
|
||||||
{
|
|
||||||
enum ValidationType
|
|
||||||
{
|
|
||||||
Valid,
|
|
||||||
NoValid,
|
|
||||||
Warning
|
|
||||||
};
|
|
||||||
|
|
||||||
Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent);
|
|
||||||
|
|
||||||
void update_valid_bmp();
|
|
||||||
void accept();
|
|
||||||
|
|
||||||
bool is_valid() const { return m_valid_type != NoValid; }
|
|
||||||
Preset::Type type() const { return m_type; }
|
|
||||||
std::string preset_name() const { return m_preset_name; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Preset::Type m_type;
|
|
||||||
ValidationType m_valid_type;
|
|
||||||
std::string m_preset_name;
|
|
||||||
|
|
||||||
SavePresetDialog* m_parent {nullptr};
|
|
||||||
wxStaticBitmap* m_valid_bmp {nullptr};
|
|
||||||
wxComboBox* m_combo {nullptr};
|
|
||||||
wxStaticText* m_valid_label {nullptr};
|
|
||||||
|
|
||||||
PresetCollection* m_presets {nullptr};
|
|
||||||
|
|
||||||
void update();
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Item*> m_items;
|
|
||||||
|
|
||||||
wxBoxSizer* m_presets_sizer {nullptr};
|
|
||||||
wxStaticText* m_label {nullptr};
|
|
||||||
wxRadioBox* m_action_radio_box {nullptr};
|
|
||||||
wxBoxSizer* m_radio_sizer {nullptr};
|
|
||||||
ActionType m_action {UndefAction};
|
|
||||||
|
|
||||||
std::string m_ph_printer_name;
|
|
||||||
std::string m_old_preset_name;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SavePresetDialog(Preset::Type type, std::string suffix = "");
|
|
||||||
SavePresetDialog(std::vector<Preset::Type> types, std::string suffix = "");
|
|
||||||
~SavePresetDialog();
|
|
||||||
|
|
||||||
void AddItem(Preset::Type type, const std::string& suffix);
|
|
||||||
|
|
||||||
std::string get_name();
|
|
||||||
std::string get_name(Preset::Type type);
|
|
||||||
|
|
||||||
bool enable_ok_btn() const;
|
|
||||||
void add_info_for_edit_ph_printer(wxBoxSizer *sizer);
|
|
||||||
void update_info_for_edit_ph_printer(const std::string &preset_name);
|
|
||||||
void layout();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
|
||||||
void on_sys_color_changed() override {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void build(std::vector<Preset::Type> types, std::string suffix = "");
|
|
||||||
void update_physical_printers(const std::string& preset_name);
|
|
||||||
void accept();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
368
src/slic3r/GUI/SavePresetDialog.cpp
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
#include "SavePresetDialog.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include <wx/sizer.h>
|
||||||
|
#include <wx/stattext.h>
|
||||||
|
#include <wx/wupdlock.h>
|
||||||
|
|
||||||
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
|
||||||
|
#include "GUI.hpp"
|
||||||
|
#include "GUI_App.hpp"
|
||||||
|
#include "format.hpp"
|
||||||
|
#include "Tab.hpp"
|
||||||
|
|
||||||
|
using Slic3r::GUI::format_wxstr;
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
#define BORDER_W 10
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// SavePresetDialog::Item
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent):
|
||||||
|
m_type(type),
|
||||||
|
m_parent(parent)
|
||||||
|
{
|
||||||
|
Tab* tab = wxGetApp().get_tab(m_type);
|
||||||
|
assert(tab);
|
||||||
|
m_presets = tab->get_presets();
|
||||||
|
|
||||||
|
const Preset& sel_preset = m_presets->get_selected_preset();
|
||||||
|
std::string preset_name = sel_preset.is_default ? "Untitled" :
|
||||||
|
sel_preset.is_system ? (boost::format(("%1% - %2%")) % sel_preset.name % suffix).str() :
|
||||||
|
sel_preset.name;
|
||||||
|
|
||||||
|
// if name contains extension
|
||||||
|
if (boost::iends_with(preset_name, ".ini")) {
|
||||||
|
size_t len = preset_name.length() - 4;
|
||||||
|
preset_name.resize(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> values;
|
||||||
|
for (const Preset& preset : *m_presets) {
|
||||||
|
if (preset.is_default || preset.is_system || preset.is_external)
|
||||||
|
continue;
|
||||||
|
values.push_back(preset.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxStaticText* label_top = new wxStaticText(m_parent, wxID_ANY, from_u8((boost::format(_utf8(L("Save %s as:"))) % into_u8(tab->title())).str()));
|
||||||
|
|
||||||
|
m_valid_bmp = new wxStaticBitmap(m_parent, wxID_ANY, create_scaled_bitmap("tick_mark", m_parent));
|
||||||
|
|
||||||
|
m_combo = new wxComboBox(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1));
|
||||||
|
for (const std::string& value : values)
|
||||||
|
m_combo->Append(from_u8(value));
|
||||||
|
|
||||||
|
m_combo->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); });
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
// Under OSX wxEVT_TEXT wasn't invoked after change selection in combobox,
|
||||||
|
// So process wxEVT_COMBOBOX too
|
||||||
|
m_combo->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { update(); });
|
||||||
|
#endif //__WXOSX__
|
||||||
|
|
||||||
|
m_valid_label = new wxStaticText(m_parent, wxID_ANY, "");
|
||||||
|
m_valid_label->SetFont(wxGetApp().bold_font());
|
||||||
|
|
||||||
|
wxBoxSizer* combo_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
combo_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W);
|
||||||
|
combo_sizer->Add(m_combo, 1, wxEXPAND, BORDER_W);
|
||||||
|
|
||||||
|
sizer->Add(label_top, 0, wxEXPAND | wxTOP| wxBOTTOM, BORDER_W);
|
||||||
|
sizer->Add(combo_sizer, 0, wxEXPAND | wxBOTTOM, BORDER_W);
|
||||||
|
sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W);
|
||||||
|
|
||||||
|
if (m_type == Preset::TYPE_PRINTER)
|
||||||
|
m_parent->add_info_for_edit_ph_printer(sizer);
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::Item::update()
|
||||||
|
{
|
||||||
|
m_preset_name = into_u8(m_combo->GetValue());
|
||||||
|
|
||||||
|
m_valid_type = Valid;
|
||||||
|
wxString info_line;
|
||||||
|
|
||||||
|
const char* unusable_symbols = "<>[]:/\\|?*\"";
|
||||||
|
|
||||||
|
const std::string unusable_suffix = PresetCollection::get_suffix_modified();//"(modified)";
|
||||||
|
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
|
||||||
|
if (m_preset_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
|
||||||
|
info_line = _L("The supplied name is not valid;") + "\n" +
|
||||||
|
_L("the following characters are not allowed:") + " " + unusable_symbols;
|
||||||
|
m_valid_type = NoValid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_valid_type == Valid && m_preset_name.find(unusable_suffix) != std::string::npos) {
|
||||||
|
info_line = _L("The supplied name is not valid;") + "\n" +
|
||||||
|
_L("the following suffix is not allowed:") + "\n\t" +
|
||||||
|
from_u8(PresetCollection::get_suffix_modified());
|
||||||
|
m_valid_type = NoValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_valid_type == Valid && m_preset_name == "- default -") {
|
||||||
|
info_line = _L("The supplied name is not available.");
|
||||||
|
m_valid_type = NoValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Preset* existing = m_presets->find_preset(m_preset_name, false);
|
||||||
|
if (m_valid_type == Valid && existing && (existing->is_default || existing->is_system)) {
|
||||||
|
info_line = _L("Cannot overwrite a system profile.");
|
||||||
|
m_valid_type = NoValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_valid_type == Valid && existing && (existing->is_external)) {
|
||||||
|
info_line = _L("Cannot overwrite an external profile.");
|
||||||
|
m_valid_type = NoValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_valid_type == Valid && existing && m_preset_name != m_presets->get_selected_preset_name())
|
||||||
|
{
|
||||||
|
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str());
|
||||||
|
if (!existing->is_compatible)
|
||||||
|
info_line += "\n" + _L("And selected preset is imcopatible with selected printer.");
|
||||||
|
info_line += "\n" + _L("Note: This preset will be replaced after saving");
|
||||||
|
m_valid_type = Warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_valid_type == Valid && m_preset_name.empty()) {
|
||||||
|
info_line = _L("The empty name is not available.");
|
||||||
|
m_valid_type = NoValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_valid_label->SetLabel(info_line);
|
||||||
|
m_valid_label->Show(!info_line.IsEmpty());
|
||||||
|
|
||||||
|
update_valid_bmp();
|
||||||
|
|
||||||
|
if (m_type == Preset::TYPE_PRINTER)
|
||||||
|
m_parent->update_info_for_edit_ph_printer(m_preset_name);
|
||||||
|
|
||||||
|
m_parent->layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::Item::update_valid_bmp()
|
||||||
|
{
|
||||||
|
std::string bmp_name = m_valid_type == Warning ? "exclamation" :
|
||||||
|
m_valid_type == NoValid ? "cross" : "tick_mark" ;
|
||||||
|
m_valid_bmp->SetBitmap(create_scaled_bitmap(bmp_name, m_parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::Item::accept()
|
||||||
|
{
|
||||||
|
if (m_valid_type == Warning)
|
||||||
|
m_presets->delete_preset(m_preset_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// SavePresetDialog
|
||||||
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
SavePresetDialog::SavePresetDialog(Preset::Type type, std::string suffix)
|
||||||
|
: DPIDialog(nullptr, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
||||||
|
{
|
||||||
|
build(std::vector<Preset::Type>{type}, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
SavePresetDialog::SavePresetDialog(std::vector<Preset::Type> types, std::string suffix)
|
||||||
|
: DPIDialog(nullptr, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
||||||
|
{
|
||||||
|
build(types, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
SavePresetDialog::~SavePresetDialog()
|
||||||
|
{
|
||||||
|
for (auto item : m_items) {
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::build(std::vector<Preset::Type> types, std::string suffix)
|
||||||
|
{
|
||||||
|
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||||
|
#if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
|
||||||
|
// ys_FIXME! temporary workaround for correct font scaling
|
||||||
|
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||||
|
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||||
|
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||||
|
#endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
|
||||||
|
|
||||||
|
if (suffix.empty())
|
||||||
|
suffix = _CTX_utf8(L_CONTEXT("Copy", "PresetName"), "PresetName");
|
||||||
|
|
||||||
|
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
m_presets_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
// Add first item
|
||||||
|
for (Preset::Type type : types)
|
||||||
|
AddItem(type, suffix);
|
||||||
|
|
||||||
|
// Add dialog's buttons
|
||||||
|
wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
||||||
|
wxButton* btnOK = static_cast<wxButton*>(this->FindWindowById(wxID_OK, this));
|
||||||
|
btnOK->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { accept(); });
|
||||||
|
btnOK->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(enable_ok_btn()); });
|
||||||
|
|
||||||
|
topSizer->Add(m_presets_sizer, 0, wxEXPAND | wxALL, BORDER_W);
|
||||||
|
topSizer->Add(btns, 0, wxEXPAND | wxALL, BORDER_W);
|
||||||
|
|
||||||
|
SetSizer(topSizer);
|
||||||
|
topSizer->SetSizeHints(this);
|
||||||
|
|
||||||
|
this->CenterOnScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::AddItem(Preset::Type type, const std::string& suffix)
|
||||||
|
{
|
||||||
|
m_items.emplace_back(new Item{type, suffix, m_presets_sizer, this});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SavePresetDialog::get_name()
|
||||||
|
{
|
||||||
|
return m_items.front()->preset_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SavePresetDialog::get_name(Preset::Type type)
|
||||||
|
{
|
||||||
|
for (const Item* item : m_items)
|
||||||
|
if (item->type() == type)
|
||||||
|
return item->preset_name();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SavePresetDialog::enable_ok_btn() const
|
||||||
|
{
|
||||||
|
for (const Item* item : m_items)
|
||||||
|
if (!item->is_valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::add_info_for_edit_ph_printer(wxBoxSizer* sizer)
|
||||||
|
{
|
||||||
|
PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers;
|
||||||
|
m_ph_printer_name = printers.get_selected_printer_name();
|
||||||
|
m_old_preset_name = printers.get_selected_printer_preset_name();
|
||||||
|
|
||||||
|
wxString msg_text = from_u8((boost::format(_u8L("You have selected physical printer \"%1%\" \n"
|
||||||
|
"with related printer preset \"%2%\"")) %
|
||||||
|
m_ph_printer_name % m_old_preset_name).str());
|
||||||
|
m_label = new wxStaticText(this, wxID_ANY, msg_text);
|
||||||
|
m_label->SetFont(wxGetApp().bold_font());
|
||||||
|
|
||||||
|
wxString choices[] = {"","",""};
|
||||||
|
|
||||||
|
m_action_radio_box = new wxRadioBox(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
|
||||||
|
WXSIZEOF(choices), choices, 3, wxRA_SPECIFY_ROWS);
|
||||||
|
m_action_radio_box->SetSelection(0);
|
||||||
|
m_action_radio_box->Bind(wxEVT_RADIOBOX, [this](wxCommandEvent& e) {
|
||||||
|
m_action = (ActionType)e.GetSelection(); });
|
||||||
|
m_action = ChangePreset;
|
||||||
|
|
||||||
|
m_radio_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
m_radio_sizer->Add(m_action_radio_box, 1, wxEXPAND | wxTOP, 2*BORDER_W);
|
||||||
|
|
||||||
|
sizer->Add(m_label, 0, wxEXPAND | wxLEFT | wxTOP, 3*BORDER_W);
|
||||||
|
sizer->Add(m_radio_sizer, 1, wxEXPAND | wxLEFT, 3*BORDER_W);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::update_info_for_edit_ph_printer(const std::string& preset_name)
|
||||||
|
{
|
||||||
|
bool show = wxGetApp().preset_bundle->physical_printers.has_selection() && m_old_preset_name != preset_name;
|
||||||
|
|
||||||
|
m_label->Show(show);
|
||||||
|
m_radio_sizer->ShowItems(show);
|
||||||
|
if (!show) {
|
||||||
|
this->SetMinSize(wxSize(100,50));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString msg_text = from_u8((boost::format(_u8L("What would you like to do with \"%1%\" preset after saving?")) % preset_name).str());
|
||||||
|
m_action_radio_box->SetLabel(msg_text);
|
||||||
|
|
||||||
|
wxString choices[] = { from_u8((boost::format(_u8L("Change \"%1%\" to \"%2%\" for this physical printer \"%3%\"")) % m_old_preset_name % preset_name % m_ph_printer_name).str()),
|
||||||
|
from_u8((boost::format(_u8L("Add \"%1%\" as a next preset for the the physical printer \"%2%\"")) % preset_name % m_ph_printer_name).str()),
|
||||||
|
from_u8((boost::format(_u8L("Just switch to \"%1%\" preset")) % preset_name).str()) };
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
for(const wxString& label: choices)
|
||||||
|
m_action_radio_box->SetString(n++, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::layout()
|
||||||
|
{
|
||||||
|
this->Layout();
|
||||||
|
this->Fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||||
|
{
|
||||||
|
const int& em = em_unit();
|
||||||
|
|
||||||
|
msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
|
||||||
|
|
||||||
|
for (Item* item : m_items)
|
||||||
|
item->update_valid_bmp();
|
||||||
|
|
||||||
|
//const wxSize& size = wxSize(45 * em, 35 * em);
|
||||||
|
SetMinSize(/*size*/wxSize(100, 50));
|
||||||
|
|
||||||
|
Fit();
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::update_physical_printers(const std::string& preset_name)
|
||||||
|
{
|
||||||
|
if (m_action == UndefAction)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PhysicalPrinterCollection& physical_printers = wxGetApp().preset_bundle->physical_printers;
|
||||||
|
if (!physical_printers.has_selection())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string printer_preset_name = physical_printers.get_selected_printer_preset_name();
|
||||||
|
|
||||||
|
if (m_action == Switch)
|
||||||
|
// unselect physical printer, if it was selected
|
||||||
|
physical_printers.unselect_printer();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PhysicalPrinter printer = physical_printers.get_selected_printer();
|
||||||
|
|
||||||
|
if (m_action == ChangePreset)
|
||||||
|
printer.delete_preset(printer_preset_name);
|
||||||
|
|
||||||
|
if (printer.add_preset(preset_name))
|
||||||
|
physical_printers.save_printer(printer);
|
||||||
|
|
||||||
|
physical_printers.select_printer(printer.get_full_name(preset_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SavePresetDialog::accept()
|
||||||
|
{
|
||||||
|
for (Item* item : m_items) {
|
||||||
|
item->accept();
|
||||||
|
if (item->type() == Preset::TYPE_PRINTER)
|
||||||
|
update_physical_printers(item->preset_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
EndModal(wxID_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::GUI
|
103
src/slic3r/GUI/SavePresetDialog.hpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#ifndef slic3r_SavePresetDialog_hpp_
|
||||||
|
#define slic3r_SavePresetDialog_hpp_
|
||||||
|
|
||||||
|
//#include <wx/gdicmn.h>
|
||||||
|
|
||||||
|
#include "libslic3r/Preset.hpp"
|
||||||
|
#include "wxExtensions.hpp"
|
||||||
|
#include "GUI_Utils.hpp"
|
||||||
|
|
||||||
|
class wxString;
|
||||||
|
class wxStaticText;
|
||||||
|
class wxComboBox;
|
||||||
|
class wxRadioBox;
|
||||||
|
class wxStaticBitmap;
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
class SavePresetDialog : public DPIDialog
|
||||||
|
{
|
||||||
|
enum ActionType
|
||||||
|
{
|
||||||
|
ChangePreset,
|
||||||
|
AddPreset,
|
||||||
|
Switch,
|
||||||
|
UndefAction
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
enum ValidationType
|
||||||
|
{
|
||||||
|
Valid,
|
||||||
|
NoValid,
|
||||||
|
Warning
|
||||||
|
};
|
||||||
|
|
||||||
|
Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent);
|
||||||
|
|
||||||
|
void update_valid_bmp();
|
||||||
|
void accept();
|
||||||
|
|
||||||
|
bool is_valid() const { return m_valid_type != NoValid; }
|
||||||
|
Preset::Type type() const { return m_type; }
|
||||||
|
std::string preset_name() const { return m_preset_name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Preset::Type m_type;
|
||||||
|
ValidationType m_valid_type;
|
||||||
|
std::string m_preset_name;
|
||||||
|
|
||||||
|
SavePresetDialog* m_parent {nullptr};
|
||||||
|
wxStaticBitmap* m_valid_bmp {nullptr};
|
||||||
|
wxComboBox* m_combo {nullptr};
|
||||||
|
wxStaticText* m_valid_label {nullptr};
|
||||||
|
|
||||||
|
PresetCollection* m_presets {nullptr};
|
||||||
|
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Item*> m_items;
|
||||||
|
|
||||||
|
wxBoxSizer* m_presets_sizer {nullptr};
|
||||||
|
wxStaticText* m_label {nullptr};
|
||||||
|
wxRadioBox* m_action_radio_box {nullptr};
|
||||||
|
wxBoxSizer* m_radio_sizer {nullptr};
|
||||||
|
ActionType m_action {UndefAction};
|
||||||
|
|
||||||
|
std::string m_ph_printer_name;
|
||||||
|
std::string m_old_preset_name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SavePresetDialog(Preset::Type type, std::string suffix = "");
|
||||||
|
SavePresetDialog(std::vector<Preset::Type> types, std::string suffix = "");
|
||||||
|
~SavePresetDialog();
|
||||||
|
|
||||||
|
void AddItem(Preset::Type type, const std::string& suffix);
|
||||||
|
|
||||||
|
std::string get_name();
|
||||||
|
std::string get_name(Preset::Type type);
|
||||||
|
|
||||||
|
bool enable_ok_btn() const;
|
||||||
|
void add_info_for_edit_ph_printer(wxBoxSizer *sizer);
|
||||||
|
void update_info_for_edit_ph_printer(const std::string &preset_name);
|
||||||
|
void layout();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||||
|
void on_sys_color_changed() override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void build(std::vector<Preset::Type> types, std::string suffix = "");
|
||||||
|
void update_physical_printers(const std::string& preset_name);
|
||||||
|
void accept();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif
|
@ -44,6 +44,7 @@
|
|||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
#include "PhysicalPrinterDialog.hpp"
|
#include "PhysicalPrinterDialog.hpp"
|
||||||
#include "UnsavedChangesDialog.hpp"
|
#include "UnsavedChangesDialog.hpp"
|
||||||
|
#include "SavePresetDialog.hpp"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
@ -208,9 +209,7 @@ void Tab::create_preset_tab()
|
|||||||
// TRN "Save current Settings"
|
// TRN "Save current Settings"
|
||||||
m_btn_save_preset->SetToolTip(from_u8((boost::format(_utf8(L("Save current %s"))) % m_title).str()));
|
m_btn_save_preset->SetToolTip(from_u8((boost::format(_utf8(L("Save current %s"))) % m_title).str()));
|
||||||
m_btn_delete_preset->SetToolTip(_(L("Delete this preset")));
|
m_btn_delete_preset->SetToolTip(_(L("Delete this preset")));
|
||||||
m_btn_delete_preset->Disable();
|
m_btn_delete_preset->Hide();
|
||||||
if (m_btn_edit_ph_printer)
|
|
||||||
m_btn_edit_ph_printer->Disable();
|
|
||||||
|
|
||||||
add_scaled_button(panel, &m_question_btn, "question");
|
add_scaled_button(panel, &m_question_btn, "question");
|
||||||
m_question_btn->SetToolTip(_(L("Hover the cursor over buttons to find more information \n"
|
m_question_btn->SetToolTip(_(L("Hover the cursor over buttons to find more information \n"
|
||||||
@ -345,11 +344,12 @@ void Tab::create_preset_tab()
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (m_btn_edit_ph_printer)
|
if (m_btn_edit_ph_printer)
|
||||||
m_btn_edit_ph_printer->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) {
|
m_btn_edit_ph_printer->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) {
|
||||||
PhysicalPrinterDialog dlg(m_presets_choice->GetString(m_presets_choice->GetSelection()));
|
if (m_preset_bundle->physical_printers.has_selection())
|
||||||
if (dlg.ShowModal() == wxID_OK)
|
m_presets_choice->edit_physical_printer();
|
||||||
update_tab_ui();
|
else
|
||||||
}));
|
m_presets_choice->add_physical_printer();
|
||||||
|
});
|
||||||
|
|
||||||
// Fill cache for mode bitmaps
|
// Fill cache for mode bitmaps
|
||||||
m_mode_bitmap_cache.reserve(3);
|
m_mode_bitmap_cache.reserve(3);
|
||||||
@ -2999,17 +2999,15 @@ void Tab::rebuild_page_tree()
|
|||||||
|
|
||||||
void Tab::update_btns_enabling()
|
void Tab::update_btns_enabling()
|
||||||
{
|
{
|
||||||
// we can't delete last preset from the physical printer
|
// we can delete any preset from the physical printer
|
||||||
if (m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection())
|
// and any user preset
|
||||||
m_btn_delete_preset->Enable(m_preset_bundle->physical_printers.get_selected_printer().preset_names.size() > 1);
|
|
||||||
else {
|
|
||||||
const Preset& preset = m_presets->get_edited_preset();
|
const Preset& preset = m_presets->get_edited_preset();
|
||||||
m_btn_delete_preset->Enable(!preset.is_default && !preset.is_system);
|
m_btn_delete_preset->Show(m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection() ||
|
||||||
}
|
!preset.is_default && !preset.is_system);
|
||||||
|
|
||||||
// we can edit physical printer only if it's selected in the list
|
|
||||||
if (m_btn_edit_ph_printer)
|
if (m_btn_edit_ph_printer)
|
||||||
m_btn_edit_ph_printer->Enable(m_preset_bundle->physical_printers.has_selection());
|
m_btn_edit_ph_printer->SetToolTip( m_preset_bundle->physical_printers.has_selection() ?
|
||||||
|
_L("Edit physical printer") : _L("Add physical printer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tab::update_preset_choice()
|
void Tab::update_preset_choice()
|
||||||
@ -3410,7 +3408,7 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
|
|||||||
// Update the selection boxes at the plater.
|
// Update the selection boxes at the plater.
|
||||||
on_presets_changed();
|
on_presets_changed();
|
||||||
// If current profile is saved, "delete preset" button have to be enabled
|
// If current profile is saved, "delete preset" button have to be enabled
|
||||||
m_btn_delete_preset->Enable(true);
|
m_btn_delete_preset->Show();
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_PRINTER)
|
if (m_type == Preset::TYPE_PRINTER)
|
||||||
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
|
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
|
||||||
@ -3465,8 +3463,16 @@ void Tab::delete_preset()
|
|||||||
PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers;
|
PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers;
|
||||||
wxString msg;
|
wxString msg;
|
||||||
if (m_presets_choice->is_selected_physical_printer())
|
if (m_presets_choice->is_selected_physical_printer())
|
||||||
msg = from_u8((boost::format(_u8L("Are you sure you want to delete \"%1%\" preset from the physical printer \"%2%\"?"))
|
{
|
||||||
% current_preset.name % physical_printers.get_selected_printer_name()).str());
|
PhysicalPrinter& printer = physical_printers.get_selected_printer();
|
||||||
|
if (printer.preset_names.size() == 1) {
|
||||||
|
if (m_presets_choice->del_physical_printer(_L("It's a last preset for this physical printer.")))
|
||||||
|
Layout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = format_wxstr(_L("Are you sure you want to delete \"%1%\" preset from the physical printer \"%2%\"?"), current_preset.name, printer.name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_type == Preset::TYPE_PRINTER && !physical_printers.empty())
|
if (m_type == Preset::TYPE_PRINTER && !physical_printers.empty())
|
||||||
@ -3507,11 +3513,6 @@ void Tab::delete_preset()
|
|||||||
if (m_presets_choice->is_selected_physical_printer()) {
|
if (m_presets_choice->is_selected_physical_printer()) {
|
||||||
PhysicalPrinter& printer = physical_printers.get_selected_printer();
|
PhysicalPrinter& printer = physical_printers.get_selected_printer();
|
||||||
|
|
||||||
if (printer.preset_names.size() == 1) {
|
|
||||||
wxMessageDialog dialog(nullptr, _L("It's a last for this physical printer. We can't delete it"), _L("Information"), wxICON_INFORMATION | wxOK);
|
|
||||||
dialog.ShowModal();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// just delete this preset from the current physical printer
|
// just delete this preset from the current physical printer
|
||||||
printer.delete_preset(m_presets->get_edited_preset().name);
|
printer.delete_preset(m_presets->get_edited_preset().name);
|
||||||
// select first from the possible presets for this printer
|
// select first from the possible presets for this printer
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include "Tab.hpp"
|
#include "Tab.hpp"
|
||||||
#include "ExtraRenderers.hpp"
|
#include "ExtraRenderers.hpp"
|
||||||
#include "wxExtensions.hpp"
|
#include "wxExtensions.hpp"
|
||||||
#include "PresetComboBoxes.hpp"
|
#include "SavePresetDialog.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
|
|
||||||
//#define FTS_FUZZY_MATCH_IMPLEMENTATION
|
//#define FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||||
@ -597,7 +597,7 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection* dependent_
|
|||||||
#endif
|
#endif
|
||||||
wxDataViewColumn* column = new wxDataViewColumn(label, rd, model_column, width, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_CELL_INERT);
|
wxDataViewColumn* column = new wxDataViewColumn(label, rd, model_column, width, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_CELL_INERT);
|
||||||
#else
|
#else
|
||||||
wxDataViewColumn* column = new wxDataViewColumn(label, new BitmapTextRenderer(true), model_column, width, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE);
|
wxDataViewColumn* column = new wxDataViewColumn(label, new BitmapTextRenderer(true, wxDATAVIEW_CELL_INERT), model_column, width, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE);
|
||||||
#endif //__linux__
|
#endif //__linux__
|
||||||
m_tree->AppendColumn(column);
|
m_tree->AppendColumn(column);
|
||||||
if (set_expander)
|
if (set_expander)
|
||||||
@ -727,8 +727,6 @@ void UnsavedChangesDialog::context_menu(wxDataViewEvent& event)
|
|||||||
|
|
||||||
void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name)
|
void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name)
|
||||||
{
|
{
|
||||||
if (m_motion_action == action)
|
|
||||||
return;
|
|
||||||
if (action == Action::Undef && !m_has_long_strings)
|
if (action == Action::Undef && !m_has_long_strings)
|
||||||
m_info_line->Hide();
|
m_info_line->Hide();
|
||||||
else {
|
else {
|
||||||
@ -752,8 +750,6 @@ void UnsavedChangesDialog::show_info_line(Action action, std::string preset_name
|
|||||||
m_info_line->Show();
|
m_info_line->Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_motion_action = action;
|
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
@ -1013,7 +1009,7 @@ void UnsavedChangesDialog::update(Preset::Type type, PresetCollection* dependent
|
|||||||
action_msg = format_wxstr(_L("Preset \"%1%\" has the following unsaved changes:"), presets->get_edited_preset().name);
|
action_msg = format_wxstr(_L("Preset \"%1%\" has the following unsaved changes:"), presets->get_edited_preset().name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
action_msg = format_wxstr(Preset::TYPE_PRINTER ?
|
action_msg = format_wxstr(type == Preset::TYPE_PRINTER ?
|
||||||
_L("Preset \"%1%\" is not compatible with the new printer profile and it has the following unsaved changes:") :
|
_L("Preset \"%1%\" is not compatible with the new printer profile and it has the following unsaved changes:") :
|
||||||
_L("Preset \"%1%\" is not compatible with the new print profile and it has the following unsaved changes:"),
|
_L("Preset \"%1%\" is not compatible with the new print profile and it has the following unsaved changes:"),
|
||||||
presets->get_edited_preset().name);
|
presets->get_edited_preset().name);
|
||||||
|
@ -210,9 +210,6 @@ class UnsavedChangesDialog : public DPIDialog
|
|||||||
// selected action after Dialog closing
|
// selected action after Dialog closing
|
||||||
Action m_exit_action {Action::Undef};
|
Action m_exit_action {Action::Undef};
|
||||||
|
|
||||||
// Action during mouse motion
|
|
||||||
Action m_motion_action {Action::Undef};
|
|
||||||
|
|
||||||
struct ItemData
|
struct ItemData
|
||||||
{
|
{
|
||||||
std::string opt_key;
|
std::string opt_key;
|
||||||
|
@ -25,7 +25,7 @@ namespace Slic3r {
|
|||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
|
||||||
static const char* URL_CHANGELOG = "http://files.prusa3d.com/?latest=slicer-stable&lng=%1%";
|
static const char* URL_CHANGELOG = "https://files.prusa3d.com/?latest=slicer-stable&lng=%1%";
|
||||||
static const char* URL_DOWNLOAD = "https://www.prusa3d.com/downloads&lng=%1%";
|
static const char* URL_DOWNLOAD = "https://www.prusa3d.com/downloads&lng=%1%";
|
||||||
static const char* URL_DEV = "https://github.com/supermerill/SuperSlicer/releases/tag/version_%1%";
|
static const char* URL_DEV = "https://github.com/supermerill/SuperSlicer/releases/tag/version_%1%";
|
||||||
|
|
||||||
|
@ -36,12 +36,10 @@ const char* Duet::get_name() const { return "Duet"; }
|
|||||||
|
|
||||||
bool Duet::test(wxString &msg) const
|
bool Duet::test(wxString &msg) const
|
||||||
{
|
{
|
||||||
bool connected = connect(msg);
|
auto connectionType = connect(msg);
|
||||||
if (connected) {
|
disconnect(connectionType);
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
return connected;
|
return connectionType != ConnectionType::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString Duet::get_test_ok_msg () const
|
wxString Duet::get_test_ok_msg () const
|
||||||
@ -59,33 +57,39 @@ wxString Duet::get_test_failed_msg (wxString &msg) const
|
|||||||
bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const
|
bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const
|
||||||
{
|
{
|
||||||
wxString connect_msg;
|
wxString connect_msg;
|
||||||
if (!connect(connect_msg)) {
|
auto connectionType = connect(connect_msg);
|
||||||
|
if (connectionType == ConnectionType::error) {
|
||||||
error_fn(std::move(connect_msg));
|
error_fn(std::move(connect_msg));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool res = true;
|
bool res = true;
|
||||||
|
bool dsf = (connectionType == ConnectionType::dsf);
|
||||||
|
|
||||||
auto upload_cmd = get_upload_url(upload_data.upload_path.string());
|
auto upload_cmd = get_upload_url(upload_data.upload_path.string(), connectionType);
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%")
|
BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%")
|
||||||
% upload_data.source_path
|
% upload_data.source_path
|
||||||
% upload_data.upload_path
|
% upload_data.upload_path
|
||||||
% upload_data.start_print
|
% upload_data.start_print
|
||||||
% upload_cmd;
|
% upload_cmd;
|
||||||
|
|
||||||
auto http = Http::post(std::move(upload_cmd));
|
auto http = (dsf ? Http::put(std::move(upload_cmd)) : Http::post(std::move(upload_cmd)));
|
||||||
http.set_post_body(upload_data.source_path)
|
if (dsf) {
|
||||||
.on_complete([&](std::string body, unsigned status) {
|
http.set_put_body(upload_data.source_path);
|
||||||
|
} else {
|
||||||
|
http.set_post_body(upload_data.source_path);
|
||||||
|
}
|
||||||
|
http.on_complete([&](std::string body, unsigned status) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
|
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
|
||||||
|
|
||||||
int err_code = get_err_code_from_body(body);
|
int err_code = dsf ? (status == 201 ? 0 : 1) : get_err_code_from_body(body);
|
||||||
if (err_code != 0) {
|
if (err_code != 0) {
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Request completed but error code was received: %1%") % err_code;
|
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Request completed but error code was received: %1%") % err_code;
|
||||||
error_fn(format_error(body, L("Unknown error occured"), 0));
|
error_fn(format_error(body, L("Unknown error occured"), 0));
|
||||||
res = false;
|
res = false;
|
||||||
} else if (upload_data.start_print) {
|
} else if (upload_data.start_print) {
|
||||||
wxString errormsg;
|
wxString errormsg;
|
||||||
res = start_print(errormsg, upload_data.upload_path.string());
|
res = start_print(errormsg, upload_data.upload_path.string(), connectionType);
|
||||||
if (! res) {
|
if (! res) {
|
||||||
error_fn(std::move(errormsg));
|
error_fn(std::move(errormsg));
|
||||||
}
|
}
|
||||||
@ -106,20 +110,28 @@ bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn e
|
|||||||
})
|
})
|
||||||
.perform_sync();
|
.perform_sync();
|
||||||
|
|
||||||
disconnect();
|
disconnect(connectionType);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Duet::connect(wxString &msg) const
|
Duet::ConnectionType Duet::connect(wxString &msg) const
|
||||||
{
|
{
|
||||||
bool res = false;
|
auto res = ConnectionType::error;
|
||||||
auto url = get_connect_url();
|
auto url = get_connect_url(false);
|
||||||
|
|
||||||
auto http = Http::get(std::move(url));
|
auto http = Http::get(std::move(url));
|
||||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
auto dsfUrl = get_connect_url(true);
|
||||||
msg = format_error(body, error, status);
|
auto dsfHttp = Http::get(std::move(dsfUrl));
|
||||||
|
dsfHttp.on_error([&](std::string body, std::string error, unsigned status) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||||
|
msg = format_error(body, error, status);
|
||||||
|
})
|
||||||
|
.on_complete([&](std::string body, unsigned) {
|
||||||
|
res = ConnectionType::dsf;
|
||||||
|
})
|
||||||
|
.perform_sync();
|
||||||
})
|
})
|
||||||
.on_complete([&](std::string body, unsigned) {
|
.on_complete([&](std::string body, unsigned) {
|
||||||
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;
|
BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;
|
||||||
@ -127,7 +139,7 @@ bool Duet::connect(wxString &msg) const
|
|||||||
int err_code = get_err_code_from_body(body);
|
int err_code = get_err_code_from_body(body);
|
||||||
switch (err_code) {
|
switch (err_code) {
|
||||||
case 0:
|
case 0:
|
||||||
res = true;
|
res = ConnectionType::rrf;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
msg = format_error(body, L("Wrong password"), 0);
|
msg = format_error(body, L("Wrong password"), 0);
|
||||||
@ -146,8 +158,12 @@ bool Duet::connect(wxString &msg) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Duet::disconnect() const
|
void Duet::disconnect(ConnectionType connectionType) const
|
||||||
{
|
{
|
||||||
|
// we don't need to disconnect from DSF or if it failed anyway
|
||||||
|
if (connectionType != ConnectionType::rrf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto url = (boost::format("%1%rr_disconnect")
|
auto url = (boost::format("%1%rr_disconnect")
|
||||||
% get_base_url()).str();
|
% get_base_url()).str();
|
||||||
|
|
||||||
@ -159,20 +175,33 @@ void Duet::disconnect() const
|
|||||||
.perform_sync();
|
.perform_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Duet::get_upload_url(const std::string &filename) const
|
std::string Duet::get_upload_url(const std::string &filename, ConnectionType connectionType) const
|
||||||
{
|
{
|
||||||
return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%")
|
assert(connectionType != ConnectionType::error);
|
||||||
% get_base_url()
|
|
||||||
% Http::url_encode(filename)
|
if (connectionType == ConnectionType::dsf) {
|
||||||
% timestamp_str()).str();
|
return (boost::format("%1%machine/file/gcodes/%2%")
|
||||||
|
% get_base_url()
|
||||||
|
% Http::url_encode(filename)).str();
|
||||||
|
} else {
|
||||||
|
return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%")
|
||||||
|
% get_base_url()
|
||||||
|
% Http::url_encode(filename)
|
||||||
|
% timestamp_str()).str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Duet::get_connect_url() const
|
std::string Duet::get_connect_url(const bool dsfUrl) const
|
||||||
{
|
{
|
||||||
return (boost::format("%1%rr_connect?password=%2%&%3%")
|
if (dsfUrl) {
|
||||||
% get_base_url()
|
return (boost::format("%1%machine/status")
|
||||||
% (password.empty() ? "reprap" : password)
|
% get_base_url()).str();
|
||||||
% timestamp_str()).str();
|
} else {
|
||||||
|
return (boost::format("%1%rr_connect?password=%2%&%3%")
|
||||||
|
% get_base_url()
|
||||||
|
% (password.empty() ? "reprap" : password)
|
||||||
|
% timestamp_str()).str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Duet::get_base_url() const
|
std::string Duet::get_base_url() const
|
||||||
@ -201,15 +230,27 @@ std::string Duet::timestamp_str() const
|
|||||||
return std::string(buffer);
|
return std::string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Duet::start_print(wxString &msg, const std::string &filename) const
|
bool Duet::start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const
|
||||||
{
|
{
|
||||||
bool res = false;
|
assert(connectionType != ConnectionType::error);
|
||||||
|
|
||||||
auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"")
|
bool res = false;
|
||||||
|
bool dsf = (connectionType == ConnectionType::dsf);
|
||||||
|
|
||||||
|
auto url = dsf
|
||||||
|
? (boost::format("%1%machine/code")
|
||||||
|
% get_base_url()).str()
|
||||||
|
: (boost::format("%1%rr_gcode?gcode=M32%%20\"0:/gcodes/%2%\"")
|
||||||
% get_base_url()
|
% get_base_url()
|
||||||
% Http::url_encode(filename)).str();
|
% Http::url_encode(filename)).str();
|
||||||
|
|
||||||
auto http = Http::get(std::move(url));
|
auto http = (dsf ? Http::post(std::move(url)) : Http::get(std::move(url)));
|
||||||
|
if (dsf) {
|
||||||
|
http.set_post_body(
|
||||||
|
(boost::format("M32 \"0:/gcodes/%1%\"")
|
||||||
|
% filename).str()
|
||||||
|
);
|
||||||
|
}
|
||||||
http.on_error([&](std::string body, std::string error, unsigned status) {
|
http.on_error([&](std::string body, std::string error, unsigned status) {
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error starting print: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error starting print: %1%, HTTP %2%, body: `%3%`") % error % status % body;
|
||||||
msg = format_error(body, error, status);
|
msg = format_error(body, error, status);
|
||||||
|
@ -14,7 +14,7 @@ class Http;
|
|||||||
class Duet : public PrintHost
|
class Duet : public PrintHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Duet(DynamicPrintConfig *config);
|
explicit Duet(DynamicPrintConfig *config);
|
||||||
~Duet() override = default;
|
~Duet() override = default;
|
||||||
|
|
||||||
const char* get_name() const override;
|
const char* get_name() const override;
|
||||||
@ -29,16 +29,17 @@ public:
|
|||||||
std::string get_host() const override { return host; }
|
std::string get_host() const override { return host; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class ConnectionType { rrf, dsf, error };
|
||||||
std::string host;
|
std::string host;
|
||||||
std::string password;
|
std::string password;
|
||||||
|
|
||||||
std::string get_upload_url(const std::string &filename) const;
|
std::string get_upload_url(const std::string &filename, ConnectionType connectionType) const;
|
||||||
std::string get_connect_url() const;
|
std::string get_connect_url(const bool dsfUrl) const;
|
||||||
std::string get_base_url() const;
|
std::string get_base_url() const;
|
||||||
std::string timestamp_str() const;
|
std::string timestamp_str() const;
|
||||||
bool connect(wxString &msg) const;
|
ConnectionType connect(wxString &msg) const;
|
||||||
void disconnect() const;
|
void disconnect(ConnectionType connectionType) const;
|
||||||
bool start_print(wxString &msg, const std::string &filename) const;
|
bool start_print(wxString &msg, const std::string &filename, ConnectionType connectionType) const;
|
||||||
int get_err_code_from_body(const std::string &body) const;
|
int get_err_code_from_body(const std::string &body) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,11 +35,11 @@ struct CurlGlobalInit
|
|||||||
{
|
{
|
||||||
static std::unique_ptr<CurlGlobalInit> instance;
|
static std::unique_ptr<CurlGlobalInit> instance;
|
||||||
std::string message;
|
std::string message;
|
||||||
|
|
||||||
CurlGlobalInit()
|
CurlGlobalInit()
|
||||||
{
|
{
|
||||||
#ifdef OPENSSL_CERT_OVERRIDE // defined if SLIC3R_STATIC=ON
|
#ifdef OPENSSL_CERT_OVERRIDE // defined if SLIC3R_STATIC=ON
|
||||||
|
|
||||||
// Look for a set of distro specific directories. Don't change the
|
// Look for a set of distro specific directories. Don't change the
|
||||||
// order: https://bugzilla.redhat.com/show_bug.cgi?id=1053882
|
// order: https://bugzilla.redhat.com/show_bug.cgi?id=1053882
|
||||||
static const char * CA_BUNDLES[] = {
|
static const char * CA_BUNDLES[] = {
|
||||||
@ -48,17 +48,17 @@ struct CurlGlobalInit
|
|||||||
"/usr/share/ssl/certs/ca-bundle.crt",
|
"/usr/share/ssl/certs/ca-bundle.crt",
|
||||||
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
|
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
|
||||||
"/etc/ssl/cert.pem",
|
"/etc/ssl/cert.pem",
|
||||||
"/etc/ssl/ca-bundle.pem" // OpenSUSE Tumbleweed
|
"/etc/ssl/ca-bundle.pem" // OpenSUSE Tumbleweed
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
// Env var name for the OpenSSL CA bundle (SSL_CERT_FILE nomally)
|
// Env var name for the OpenSSL CA bundle (SSL_CERT_FILE nomally)
|
||||||
const char *const SSL_CA_FILE = X509_get_default_cert_file_env();
|
const char *const SSL_CA_FILE = X509_get_default_cert_file_env();
|
||||||
const char * ssl_cafile = ::getenv(SSL_CA_FILE);
|
const char * ssl_cafile = ::getenv(SSL_CA_FILE);
|
||||||
|
|
||||||
if (!ssl_cafile)
|
if (!ssl_cafile)
|
||||||
ssl_cafile = X509_get_default_cert_file();
|
ssl_cafile = X509_get_default_cert_file();
|
||||||
|
|
||||||
int replace = true;
|
int replace = true;
|
||||||
if (!ssl_cafile || !fs::exists(fs::path(ssl_cafile))) {
|
if (!ssl_cafile || !fs::exists(fs::path(ssl_cafile))) {
|
||||||
const char * bundle = nullptr;
|
const char * bundle = nullptr;
|
||||||
@ -86,15 +86,15 @@ struct CurlGlobalInit
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // OPENSSL_CERT_OVERRIDE
|
#endif // OPENSSL_CERT_OVERRIDE
|
||||||
|
|
||||||
if (CURLcode ec = ::curl_global_init(CURL_GLOBAL_DEFAULT)) {
|
if (CURLcode ec = ::curl_global_init(CURL_GLOBAL_DEFAULT)) {
|
||||||
message += _u8L("CURL init has failed. PrusaSlicer will be unable to establish "
|
message += _u8L("CURL init has failed. PrusaSlicer will be unable to establish "
|
||||||
"network connections. See logs for additional details.");
|
"network connections. See logs for additional details.");
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(error) << ::curl_easy_strerror(ec);
|
BOOST_LOG_TRIVIAL(error) << ::curl_easy_strerror(ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~CurlGlobalInit() { ::curl_global_cleanup(); }
|
~CurlGlobalInit() { ::curl_global_cleanup(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,6 +120,7 @@ struct Http::priv
|
|||||||
std::string error_buffer; // Used for CURLOPT_ERRORBUFFER
|
std::string error_buffer; // Used for CURLOPT_ERRORBUFFER
|
||||||
size_t limit;
|
size_t limit;
|
||||||
bool cancel;
|
bool cancel;
|
||||||
|
std::unique_ptr<fs::ifstream> putFile;
|
||||||
|
|
||||||
std::thread io_thread;
|
std::thread io_thread;
|
||||||
Http::CompleteFn completefn;
|
Http::CompleteFn completefn;
|
||||||
@ -138,6 +139,8 @@ struct Http::priv
|
|||||||
void set_timeout_connect(long timeout);
|
void set_timeout_connect(long timeout);
|
||||||
void form_add_file(const char *name, const fs::path &path, const char* filename);
|
void form_add_file(const char *name, const fs::path &path, const char* filename);
|
||||||
void set_post_body(const fs::path &path);
|
void set_post_body(const fs::path &path);
|
||||||
|
void set_post_body(const std::string &body);
|
||||||
|
void set_put_body(const fs::path &path);
|
||||||
|
|
||||||
std::string curl_error(CURLcode curlcode);
|
std::string curl_error(CURLcode curlcode);
|
||||||
std::string body_size_error();
|
std::string body_size_error();
|
||||||
@ -154,7 +157,7 @@ Http::priv::priv(const std::string &url)
|
|||||||
, cancel(false)
|
, cancel(false)
|
||||||
{
|
{
|
||||||
Http::tls_global_init();
|
Http::tls_global_init();
|
||||||
|
|
||||||
if (curl == nullptr) {
|
if (curl == nullptr) {
|
||||||
throw Slic3r::RuntimeError(std::string("Could not construct Curl object"));
|
throw Slic3r::RuntimeError(std::string("Could not construct Curl object"));
|
||||||
}
|
}
|
||||||
@ -277,11 +280,28 @@ void Http::priv::form_add_file(const char *name, const fs::path &path, const cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME may throw! Is the caller aware of it?
|
||||||
void Http::priv::set_post_body(const fs::path &path)
|
void Http::priv::set_post_body(const fs::path &path)
|
||||||
{
|
{
|
||||||
std::ifstream file(path.string());
|
std::ifstream file(path.string());
|
||||||
std::string file_content { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() };
|
std::string file_content { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() };
|
||||||
postfields = file_content;
|
postfields = std::move(file_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Http::priv::set_post_body(const std::string &body)
|
||||||
|
{
|
||||||
|
postfields = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Http::priv::set_put_body(const fs::path &path)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
boost::uintmax_t filesize = file_size(path, ec);
|
||||||
|
if (!ec) {
|
||||||
|
putFile = std::make_unique<fs::ifstream>(path);
|
||||||
|
::curl_easy_setopt(curl, CURLOPT_READDATA, (void *) (putFile.get()));
|
||||||
|
::curl_easy_setopt(curl, CURLOPT_INFILESIZE, filesize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Http::priv::curl_error(CURLcode curlcode)
|
std::string Http::priv::curl_error(CURLcode curlcode)
|
||||||
@ -335,6 +355,8 @@ void Http::priv::http_perform()
|
|||||||
|
|
||||||
CURLcode res = ::curl_easy_perform(curl);
|
CURLcode res = ::curl_easy_perform(curl);
|
||||||
|
|
||||||
|
putFile.reset();
|
||||||
|
|
||||||
if (res != CURLE_OK) {
|
if (res != CURLE_OK) {
|
||||||
if (res == CURLE_ABORTED_BY_CALLBACK) {
|
if (res == CURLE_ABORTED_BY_CALLBACK) {
|
||||||
if (cancel) {
|
if (cancel) {
|
||||||
@ -373,6 +395,7 @@ Http::Http(Http &&other) : p(std::move(other.p)) {}
|
|||||||
|
|
||||||
Http::~Http()
|
Http::~Http()
|
||||||
{
|
{
|
||||||
|
assert(! p || ! p->putFile);
|
||||||
if (p && p->io_thread.joinable()) {
|
if (p && p->io_thread.joinable()) {
|
||||||
p->io_thread.detach();
|
p->io_thread.detach();
|
||||||
}
|
}
|
||||||
@ -465,6 +488,18 @@ Http& Http::set_post_body(const fs::path &path)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Http& Http::set_post_body(const std::string &body)
|
||||||
|
{
|
||||||
|
if (p) { p->set_post_body(body); }
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Http& Http::set_put_body(const fs::path &path)
|
||||||
|
{
|
||||||
|
if (p) { p->set_put_body(path);}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Http& Http::on_complete(CompleteFn fn)
|
Http& Http::on_complete(CompleteFn fn)
|
||||||
{
|
{
|
||||||
if (p) { p->completefn = std::move(fn); }
|
if (p) { p->completefn = std::move(fn); }
|
||||||
@ -519,6 +554,13 @@ Http Http::post(std::string url)
|
|||||||
return http;
|
return http;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Http Http::put(std::string url)
|
||||||
|
{
|
||||||
|
Http http{std::move(url)};
|
||||||
|
curl_easy_setopt(http.p->curl, CURLOPT_UPLOAD, 1L);
|
||||||
|
return http;
|
||||||
|
}
|
||||||
|
|
||||||
bool Http::ca_file_supported()
|
bool Http::ca_file_supported()
|
||||||
{
|
{
|
||||||
::CURL *curl = ::curl_easy_init();
|
::CURL *curl = ::curl_easy_init();
|
||||||
@ -531,7 +573,7 @@ std::string Http::tls_global_init()
|
|||||||
{
|
{
|
||||||
if (!CurlGlobalInit::instance)
|
if (!CurlGlobalInit::instance)
|
||||||
CurlGlobalInit::instance = std::make_unique<CurlGlobalInit>();
|
CurlGlobalInit::instance = std::make_unique<CurlGlobalInit>();
|
||||||
|
|
||||||
return CurlGlobalInit::instance->message;
|
return CurlGlobalInit::instance->message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +584,7 @@ std::string Http::tls_system_cert_store()
|
|||||||
#ifdef OPENSSL_CERT_OVERRIDE
|
#ifdef OPENSSL_CERT_OVERRIDE
|
||||||
ret = ::getenv(X509_get_default_cert_file_env());
|
ret = ::getenv(X509_get_default_cert_file_env());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ public:
|
|||||||
// for a GET and a POST request respectively.
|
// for a GET and a POST request respectively.
|
||||||
static Http get(std::string url);
|
static Http get(std::string url);
|
||||||
static Http post(std::string url);
|
static Http post(std::string url);
|
||||||
|
static Http put(std::string url);
|
||||||
~Http();
|
~Http();
|
||||||
|
|
||||||
Http(const Http &) = delete;
|
Http(const Http &) = delete;
|
||||||
@ -82,6 +83,16 @@ public:
|
|||||||
// This can be used for hosts which do not support multipart requests.
|
// This can be used for hosts which do not support multipart requests.
|
||||||
Http& set_post_body(const boost::filesystem::path &path);
|
Http& set_post_body(const boost::filesystem::path &path);
|
||||||
|
|
||||||
|
// Set the POST request body.
|
||||||
|
// The data is used verbatim, it is not additionally encoded in any way.
|
||||||
|
// This can be used for hosts which do not support multipart requests.
|
||||||
|
Http& set_post_body(const std::string &body);
|
||||||
|
|
||||||
|
// Set the file contents as a PUT request body.
|
||||||
|
// The data is used verbatim, it is not additionally encoded in any way.
|
||||||
|
// This can be used for hosts which do not support multipart requests.
|
||||||
|
Http& set_put_body(const boost::filesystem::path &path);
|
||||||
|
|
||||||
// Callback called on HTTP request complete
|
// Callback called on HTTP request complete
|
||||||
Http& on_complete(CompleteFn fn);
|
Http& on_complete(CompleteFn fn);
|
||||||
// Callback called on an error occuring at any stage of the requests: Url parsing, DNS lookup,
|
// Callback called on an error occuring at any stage of the requests: Url parsing, DNS lookup,
|
||||||
@ -102,7 +113,7 @@ public:
|
|||||||
|
|
||||||
// Tells whether current backend supports seting up a CA file using ca_file()
|
// Tells whether current backend supports seting up a CA file using ca_file()
|
||||||
static bool ca_file_supported();
|
static bool ca_file_supported();
|
||||||
|
|
||||||
// Return empty string on success or error message on fail.
|
// Return empty string on success or error message on fail.
|
||||||
static std::string tls_global_init();
|
static std::string tls_global_init();
|
||||||
static std::string tls_system_cert_store();
|
static std::string tls_system_cert_store();
|
||||||
|
@ -309,7 +309,8 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
|||||||
const std::string idx_path = (cache_path / (vendor.id + ".idx")).string();
|
const std::string idx_path = (cache_path / (vendor.id + ".idx")).string();
|
||||||
const std::string idx_path_temp = idx_path + "-update";
|
const std::string idx_path_temp = idx_path + "-update";
|
||||||
//check if idx_url is leading to a safe site
|
//check if idx_url is leading to a safe site
|
||||||
//if (! boost::starts_with(idx_url, "http://files.my_company.com/wp-content/uploads/repository/"))
|
//if (! boost::starts_with(idx_url, "http://files.my_company.com/wp-content/uploads/repository/")
|
||||||
|
// && ! boost::starts_with(idx_url, "https://files.my_company.com/wp-content/uploads/repository/"))
|
||||||
//{
|
//{
|
||||||
// BOOST_LOG_TRIVIAL(warning) << "unsafe url path for vendor \"" << vendor.name << "\" rejected: " << idx_url;
|
// BOOST_LOG_TRIVIAL(warning) << "unsafe url path for vendor \"" << vendor.name << "\" rejected: " << idx_url;
|
||||||
// continue;
|
// continue;
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
#ifndef GUI_THREAD_HPP
|
|
||||||
#define GUI_THREAD_HPP
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <boost/thread.hpp>
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
template<class Fn>
|
|
||||||
inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn)
|
|
||||||
{
|
|
||||||
// Duplicating the stack allocation size of Thread Building Block worker
|
|
||||||
// threads of the thread pool: allocate 4MB on a 64bit system, allocate 2MB
|
|
||||||
// on a 32bit system by default.
|
|
||||||
|
|
||||||
attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024));
|
|
||||||
return boost::thread{attrs, std::forward<Fn>(fn)};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Fn> inline boost::thread create_thread(Fn &&fn)
|
|
||||||
{
|
|
||||||
boost::thread::attributes attrs;
|
|
||||||
return create_thread(attrs, std::forward<Fn>(fn));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // GUI_THREAD_HPP
|
|