Merge remote-tracking branch 'origin/master' into ys_printable_property

This commit is contained in:
YuSanka 2019-08-01 15:15:18 +02:00
commit 885da35544
45 changed files with 1533 additions and 619 deletions

View file

@ -3,39 +3,23 @@
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="edit_x5F_layers_x5F_all"> <g id="edit_x5F_layers_x5F_all">
<path fill="#808080" d="M15,2.5H1C0.72,2.5,0.5,2.28,0.5,2S0.72,1.5,1,1.5h14c0.28,0,0.5,0.22,0.5,0.5S15.28,2.5,15,2.5z"/> <line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="2" x2="6" y2="2"/>
<path fill="#808080" d="M15,4.5H1C0.72,4.5,0.5,4.28,0.5,4S0.72,3.5,1,3.5h14c0.28,0,0.5,0.22,0.5,0.5S15.28,4.5,15,4.5z"/> <line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="6" x2="6" y2="6"/>
<path fill="#808080" d="M15,12.5H1c-0.28,0-0.5-0.22-0.5-0.5s0.22-0.5,0.5-0.5h14c0.28,0,0.5,0.22,0.5,0.5S15.28,12.5,15,12.5z"/>
<path fill="#808080" d="M15,14.5H1c-0.28,0-0.5-0.22-0.5-0.5s0.22-0.5,0.5-0.5h14c0.28,0,0.5,0.22,0.5,0.5S15.28,14.5,15,14.5z"/> <line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="10" x2="14" y2="10"/>
<g>
<path fill="#808080" d="M5.86,10.36c-0.01,0.04-0.13-0.14-0.2-0.22l-0.2-0.02C5.16,10.1,4.85,9.89,4.73,9.6L4.69,9.5H1 <line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="14" x2="14" y2="14"/>
c-0.28,0-0.5,0.22-0.5,0.5s0.22,0.5,0.5,0.5h4.87L5.86,10.36z"/> <path fill="#ED6B21" d="M14.62,4.37c-0.01-0.14,0.06-0.34,0.15-0.44l0.13-0.15c0.09-0.11,0.12-0.3,0.07-0.43l-0.2-0.49
<path fill="#808080" d="M15,9.5h-3.69l-0.04,0.1c-0.12,0.29-0.42,0.5-0.73,0.53l-0.18,0.01c0.04,0.01-0.13,0.13-0.21,0.2 c-0.05-0.13-0.21-0.24-0.35-0.25l-0.2-0.01c-0.14-0.01-0.33-0.1-0.42-0.21c-0.09-0.1-0.37-0.46-0.38-0.6l-0.01-0.2
l-0.02,0.16H15c0.28,0,0.5-0.22,0.5-0.5S15.28,9.5,15,9.5z"/> c-0.01-0.14-0.12-0.3-0.25-0.35l-0.49-0.2C12.52,0.97,12.33,1,12.22,1.1l-0.15,0.13c-0.11,0.09-0.31,0.16-0.44,0.15
</g> c-0.14-0.01-0.59-0.06-0.69-0.15L10.78,1.1c-0.11-0.09-0.3-0.12-0.43-0.07l-0.49,0.2C9.73,1.28,9.61,1.44,9.6,1.58l-0.01,0.2
<g> C9.58,1.92,9.49,2.11,9.38,2.2c-0.1,0.09-0.46,0.37-0.6,0.38L8.58,2.6c-0.14,0.01-0.3,0.12-0.35,0.25l-0.2,0.49
<path fill="#808080" d="M4.7,8.29l0.11-0.13c-0.03,0.02,0-0.19,0.01-0.3L4.7,7.71C4.65,7.65,4.61,7.58,4.58,7.5H1 C7.97,3.48,8,3.67,8.1,3.78l0.13,0.15c0.09,0.11,0.16,0.31,0.15,0.44C8.37,4.52,8.32,4.96,8.23,5.07L8.1,5.22
C0.72,7.5,0.5,7.72,0.5,8S0.72,8.5,1,8.5h3.58C4.61,8.42,4.65,8.35,4.7,8.29z"/> C8,5.33,7.97,5.52,8.03,5.65l0.2,0.49C8.28,6.27,8.44,6.39,8.58,6.4l0.2,0.01c0.14,0.01,0.33,0.1,0.42,0.21
<path fill="#808080" d="M15,7.5h-3.58c-0.03,0.08-0.08,0.15-0.13,0.21l-0.11,0.13l-0.01,0.02c0.01,0.12,0.04,0.32,0.06,0.38 c0.09,0.1,0.37,0.46,0.38,0.6l0.01,0.2c0.01,0.14,0.12,0.3,0.25,0.35l0.49,0.2C10.48,8.03,10.67,8,10.78,7.9l0.15-0.13
l0.06,0.05c0.05,0.06,0.1,0.13,0.13,0.21H15c0.28,0,0.5-0.22,0.5-0.5S15.28,7.5,15,7.5z"/> c0.11-0.09,0.31-0.16,0.44-0.15c0.14,0.01,0.59,0.06,0.69,0.15l0.15,0.13c0.11,0.09,0.3,0.12,0.43,0.07l0.49-0.2
</g> c0.13-0.05,0.24-0.21,0.25-0.35l0.01-0.2c0.01-0.14,0.1-0.33,0.21-0.42s0.46-0.37,0.6-0.38l0.2-0.01c0.14-0.01,0.3-0.12,0.35-0.25
<g> l0.2-0.49C15.03,5.52,15,5.33,14.9,5.22l-0.13-0.15C14.68,4.96,14.63,4.51,14.62,4.37z M11.5,6.6c-1.16,0-2.1-0.94-2.1-2.1
<path fill="#808080" d="M4.74,6.4c0.12-0.29,0.42-0.5,0.73-0.52l0.17-0.01C5.6,5.86,5.77,5.73,5.85,5.66L5.87,5.5H1 s0.94-2.1,2.1-2.1s2.1,0.94,2.1,2.1S12.66,6.6,11.5,6.6z"/>
C0.72,5.5,0.5,5.72,0.5,6S0.72,6.5,1,6.5h3.69L4.74,6.4z"/>
<path fill="#808080" d="M15,5.5h-4.87l0.01,0.14c0-0.03,0.13,0.13,0.2,0.21l0.2,0.02c0.31,0.02,0.61,0.24,0.73,0.53l0.04,0.1H15
c0.28,0,0.5-0.22,0.5-0.5S15.28,5.5,15,5.5z"/>
</g>
<path fill="#ED6B21" d="M10.67,7.89c-0.01-0.12,0.05-0.29,0.13-0.38l0.11-0.13c0.08-0.09,0.11-0.26,0.06-0.37L10.8,6.59
c-0.05-0.11-0.18-0.21-0.3-0.22l-0.17-0.01c-0.12-0.01-0.28-0.09-0.36-0.18C9.89,6.1,9.65,5.79,9.64,5.67L9.63,5.5
C9.62,5.38,9.52,5.24,9.41,5.2L8.99,5.02C8.88,4.98,8.71,5,8.62,5.08L8.49,5.2C8.4,5.28,8.22,5.33,8.11,5.33
C7.99,5.32,7.6,5.27,7.51,5.2L7.38,5.08C7.29,5,7.13,4.98,7.01,5.02L6.59,5.2C6.48,5.24,6.38,5.38,6.37,5.5L6.36,5.67
C6.35,5.79,6.27,5.95,6.19,6.03S5.79,6.35,5.67,6.36L5.5,6.37C5.38,6.38,5.24,6.48,5.2,6.59L5.02,7.01C4.98,7.12,5,7.29,5.08,7.38
L5.2,7.51C5.28,7.6,5.33,7.78,5.33,7.89C5.32,8.01,5.27,8.4,5.2,8.49L5.08,8.62C5,8.71,4.98,8.87,5.02,8.99L5.2,9.41
c0.05,0.11,0.18,0.21,0.3,0.22l0.17,0.01c0.12,0.01,0.28,0.09,0.36,0.18c0.08,0.09,0.32,0.39,0.33,0.51l0.01,0.17
c0.01,0.12,0.11,0.26,0.22,0.3l0.42,0.17c0.11,0.05,0.28,0.02,0.37-0.06l0.13-0.11c0.09-0.08,0.26-0.14,0.38-0.13
c0.12,0.01,0.5,0.05,0.59,0.13l0.13,0.11c0.09,0.08,0.26,0.11,0.37,0.06l0.42-0.17c0.11-0.05,0.21-0.18,0.22-0.3l0.01-0.17
c0.01-0.12,0.09-0.28,0.18-0.36c0.09-0.08,0.39-0.32,0.51-0.33l0.17-0.01c0.12-0.01,0.26-0.11,0.3-0.22l0.17-0.42
c0.05-0.11,0.02-0.28-0.06-0.37L10.8,8.49C10.72,8.4,10.68,8.01,10.67,7.89z M8,9.8c-0.99,0-1.8-0.8-1.8-1.8S7.01,6.2,8,6.2
S9.8,7.01,9.8,8S8.99,9.8,8,9.8z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -2,68 +2,13 @@
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="edit_x5F_layers_x5F_some"> <g id="edit_x5F_layers_x5F_some_1_">
<g>
<path fill="#808080" d="M15,2.5H1C0.72,2.5,0.5,2.28,0.5,2S0.72,1.5,1,1.5h14c0.28,0,0.5,0.22,0.5,0.5S15.28,2.5,15,2.5z"/> <line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="11" x2="14" y2="11"/>
</g>
<g> <line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="14" x2="14" y2="14"/>
<g> <path fill="#ED6B21" d="M7.68,8.87c0.18,0.18,0.47,0.18,0.64,0L11.19,6c0.18-0.18,0.12-0.32-0.13-0.32H9.62
<path fill="#808080" d="M15,4.5h-2.5C12.22,4.5,12,4.28,12,4s0.22-0.5,0.5-0.5H15c0.28,0,0.5,0.22,0.5,0.5S15.28,4.5,15,4.5z"/> c-0.25,0-0.45-0.2-0.45-0.45V1.45C9.17,1.2,8.97,1,8.71,1H7.29C7.03,1,6.83,1.2,6.83,1.45v3.77c0,0.25-0.2,0.45-0.45,0.45H4.95
</g> C4.7,5.68,4.64,5.82,4.81,6L7.68,8.87z"/>
<g>
<path fill="#808080" d="M9.5,4.5h-3C6.22,4.5,6,4.28,6,4s0.22-0.5,0.5-0.5h3C9.78,3.5,10,3.72,10,4S9.78,4.5,9.5,4.5z"/>
</g>
<g>
<path fill="#808080" d="M3.5,4.5H1C0.72,4.5,0.5,4.28,0.5,4S0.72,3.5,1,3.5h2.5C3.78,3.5,4,3.72,4,4S3.78,4.5,3.5,4.5z"/>
</g>
</g>
<g>
<g>
<path fill="#808080" d="M15,8.5h-2.5C12.22,8.5,12,8.28,12,8s0.22-0.5,0.5-0.5H15c0.28,0,0.5,0.22,0.5,0.5S15.28,8.5,15,8.5z"/>
</g>
<g>
<path fill="#808080" d="M3.5,8.5H1C0.72,8.5,0.5,8.28,0.5,8S0.72,7.5,1,7.5h2.5C3.78,7.5,4,7.72,4,8S3.78,8.5,3.5,8.5z"/>
</g>
</g>
<g>
<g>
<path fill="#808080" d="M15,12.5h-2.5c-0.28,0-0.5-0.22-0.5-0.5s0.22-0.5,0.5-0.5H15c0.28,0,0.5,0.22,0.5,0.5S15.28,12.5,15,12.5
z"/>
</g>
<g>
<path fill="#808080" d="M9.5,12.5h-3C6.22,12.5,6,12.28,6,12s0.22-0.5,0.5-0.5h3c0.28,0,0.5,0.22,0.5,0.5S9.78,12.5,9.5,12.5z"/>
</g>
<g>
<path fill="#808080" d="M3.5,12.5H1c-0.28,0-0.5-0.22-0.5-0.5s0.22-0.5,0.5-0.5h2.5C3.78,11.5,4,11.72,4,12S3.78,12.5,3.5,12.5z"
/>
</g>
</g>
<g>
<path fill="#808080" d="M15,14.5H1c-0.28,0-0.5-0.22-0.5-0.5s0.22-0.5,0.5-0.5h14c0.28,0,0.5,0.22,0.5,0.5S15.28,14.5,15,14.5z"/>
</g>
<g>
<path fill="#808080" d="M15,9.5h-3.69l-0.04,0.1c-0.12,0.29-0.42,0.5-0.73,0.53l-0.18,0.01c0.04,0.01-0.13,0.13-0.21,0.2
l-0.02,0.16H15c0.28,0,0.5-0.22,0.5-0.5S15.28,9.5,15,9.5z"/>
<path fill="#808080" d="M5.86,10.36c-0.01,0.04-0.13-0.14-0.2-0.22l-0.2-0.02C5.16,10.1,4.85,9.89,4.73,9.6L4.69,9.5H1
c-0.28,0-0.5,0.22-0.5,0.5s0.22,0.5,0.5,0.5h4.87L5.86,10.36z"/>
</g>
<g>
<path fill="#808080" d="M4.74,6.4c0.12-0.29,0.42-0.5,0.73-0.52l0.17-0.01C5.6,5.86,5.77,5.73,5.85,5.66L5.87,5.5H1
C0.72,5.5,0.5,5.72,0.5,6S0.72,6.5,1,6.5h3.69L4.74,6.4z"/>
<path fill="#808080" d="M15,5.5h-4.87l0.01,0.14c0-0.03,0.13,0.13,0.2,0.21l0.2,0.02c0.31,0.02,0.61,0.24,0.73,0.53l0.04,0.1H15
c0.28,0,0.5-0.22,0.5-0.5S15.28,5.5,15,5.5z"/>
</g>
<path fill="#ED6B21" d="M10.67,7.89c-0.01-0.12,0.05-0.29,0.13-0.38l0.11-0.13c0.08-0.09,0.11-0.26,0.06-0.37L10.8,6.59
c-0.05-0.11-0.18-0.21-0.3-0.22l-0.17-0.01c-0.12-0.01-0.28-0.09-0.36-0.18C9.89,6.1,9.65,5.79,9.64,5.67L9.63,5.5
C9.62,5.38,9.52,5.24,9.41,5.2L8.99,5.02C8.88,4.98,8.71,5,8.62,5.08L8.49,5.2C8.4,5.28,8.22,5.33,8.11,5.33
C7.99,5.32,7.6,5.27,7.51,5.2L7.38,5.08C7.29,5,7.13,4.98,7.01,5.02L6.59,5.2C6.48,5.24,6.38,5.38,6.37,5.5L6.36,5.67
C6.35,5.79,6.27,5.95,6.19,6.03S5.79,6.35,5.67,6.36L5.5,6.37C5.38,6.38,5.24,6.48,5.2,6.59L5.02,7.01C4.98,7.12,5,7.29,5.08,7.38
L5.2,7.51C5.28,7.6,5.33,7.78,5.33,7.89C5.32,8.01,5.27,8.4,5.2,8.49L5.08,8.62C5,8.71,4.98,8.87,5.02,8.99L5.2,9.41
c0.05,0.11,0.18,0.21,0.3,0.22l0.17,0.01c0.12,0.01,0.28,0.09,0.36,0.18c0.08,0.09,0.32,0.39,0.33,0.51l0.01,0.17
c0.01,0.12,0.11,0.26,0.22,0.3l0.42,0.17c0.11,0.05,0.28,0.02,0.37-0.06l0.13-0.11c0.09-0.08,0.26-0.14,0.38-0.13
c0.12,0.01,0.5,0.05,0.59,0.13l0.13,0.11c0.09,0.08,0.26,0.11,0.37,0.06l0.42-0.17c0.11-0.05,0.21-0.18,0.22-0.3l0.01-0.17
c0.01-0.12,0.09-0.28,0.18-0.36c0.09-0.08,0.39-0.32,0.51-0.33l0.17-0.01c0.12-0.01,0.26-0.11,0.3-0.22l0.17-0.42
c0.05-0.11,0.02-0.28-0.06-0.37L10.8,8.49C10.72,8.4,10.68,8.01,10.67,7.89z M8,9.8c-0.99,0-1.8-0.8-1.8-1.8S7.01,6.2,8,6.2
S9.8,7.01,9.8,8S8.99,9.8,8,9.8z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 931 B

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="lock_x5F_closed">
<path fill="none" stroke="#808080" stroke-width="3" stroke-miterlimit="9" d="M4,8V4c0,0,0-2,2-2c1,0,3,0,4,0c2,0,2,2,2,2v4"/>
<path fill="#808080" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91
c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 728 B

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="lock_x5F_open">
<path fill="none" stroke="#ED6B21" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2
c1,0,3,0,4,0c2,0,2,2,2,2v1"/>
<path fill="#ED6B21" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91
c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 753 B

View file

@ -4,19 +4,19 @@
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="mirror_x5F_off"> <g id="mirror_x5F_off">
<g> <g>
<path fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" d="M10,3.01l4,0c0.55,0,1,0.45,1,1v8 <path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
c0,0.55-0.45,1-1,1h-4"/> M10,3.01l3,0c0.55,0,1,0.45,1,1v8c0,0.55-0.45,1-1,1h-3"/>
</g> </g>
<g> <g>
<path fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" d="M6,3.01L2,3C1.45,3,1,3.45,1,4v8 <path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
c0,0.55,0.45,1,1,1h4"/> M6,3.01L3,3C2.45,3,2,3.45,2,4v8c0,0.55,0.45,1,1,1h3"/>
</g> </g>
<g> <g>
<g> <g>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="1" x2="8" y2="3.5"/> <line fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="1" x2="8" y2="3.5"/>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,3" x1="8" y1="6.5" x2="8" y2="11"/> <line fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,3" x1="8" y1="6.5" x2="8" y2="11"/>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="12.5" x2="8" y2="15"/> <line fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="12.5" x2="8" y2="15"/>
</g> </g>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -2,21 +2,21 @@
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="mirror_x5F_off_1_"> <g id="mirror_x5F_on">
<g> <g>
<path fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" d="M10,3.01l4,0c0.55,0,1,0.45,1,1v8 <path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M10,3.01l3,0
c0,0.55-0.45,1-1,1h-4"/> c0.55,0,1,0.45,1,1v8c0,0.55-0.45,1-1,1h-3"/>
</g> </g>
<g> <g>
<path fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-miterlimit="10" d="M6,3.01L2,3C1.45,3,1,3.45,1,4v8 <path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M6,3.01L3,3
c0,0.55,0.45,1,1,1h4"/> C2.45,3,2,3.45,2,4v8c0,0.55,0.45,1,1,1h3"/>
</g> </g>
<g> <g>
<g> <g>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="1" x2="8" y2="3.5"/> <line fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="1" x2="8" y2="3.5"/>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,3" x1="8" y1="6.5" x2="8" y2="11"/> <line fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,3" x1="8" y1="6.5" x2="8" y2="11"/>
<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="12.5" x2="8" y2="15"/> <line fill="none" stroke="#000000" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="12.5" x2="8" y2="15"/>
</g> </g>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,4 +1,9 @@
min_slic3r_version = 2.1.0-alpha0
1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX
min_slic3r_version = 1.42.0-alpha6 min_slic3r_version = 1.42.0-alpha6
0.8.3 FW version and SL1 materials update
0.8.2 FFF and SL1 settings update
0.8.1 Output settings and SLA materials update
0.8.0 Updated for the PrusaSlicer 2.0.0 final release 0.8.0 Updated for the PrusaSlicer 2.0.0 final release
0.8.0-rc2 Updated firmware versions for MK2.5/S and MK3/S 0.8.0-rc2 Updated firmware versions for MK2.5/S and MK3/S
0.8.0-rc1 Updated SLA profiles 0.8.0-rc1 Updated SLA profiles
@ -18,6 +23,8 @@ min_slic3r_version = 1.42.0-alpha
0.4.0-alpha3 Update of SLA profiles 0.4.0-alpha3 Update of SLA profiles
0.4.0-alpha2 First SLA profiles 0.4.0-alpha2 First SLA profiles
min_slic3r_version = 1.41.3-alpha min_slic3r_version = 1.41.3-alpha
0.4.8 MK2.5/3/S FW update
0.4.7 MK2/S/MMU FW update
0.4.6 Updated firmware versions for MK2.5/S and MK3/S 0.4.6 Updated firmware versions for MK2.5/S and MK3/S
0.4.5 Enabled remaining time support for MK2/S/MMU1 0.4.5 Enabled remaining time support for MK2/S/MMU1
0.4.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.4.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
@ -26,6 +33,8 @@ min_slic3r_version = 1.41.3-alpha
0.4.1 New MK2.5S and MK3S FW versions 0.4.1 New MK2.5S and MK3S FW versions
0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
min_slic3r_version = 1.41.1 min_slic3r_version = 1.41.1
0.3.8 MK2.5/3/S FW update
0.3.7 MK2/S/MMU FW update
0.3.6 Updated firmware versions for MK2.5 and MK3 0.3.6 Updated firmware versions for MK2.5 and MK3
0.3.5 New MK2.5 and MK3 FW versions 0.3.5 New MK2.5 and MK3 FW versions
0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt 0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
@ -60,6 +69,8 @@ min_slic3r_version = 1.41.0-alpha
0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0 0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0
0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters 0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters
min_slic3r_version = 1.40.0 min_slic3r_version = 1.40.0
0.1.16 MK2.5/3/S FW update
0.1.15 MK2/S/MMU FW update
0.1.14 Updated firmware versions for MK2.5 and MK3 0.1.14 Updated firmware versions for MK2.5 and MK3
0.1.13 New MK2.5 and MK3 FW versions 0.1.13 New MK2.5 and MK3 FW versions
0.1.12 New MK2.5 and MK3 FW versions 0.1.12 New MK2.5 and MK3 FW versions

File diff suppressed because it is too large Load diff

View file

@ -102,7 +102,7 @@ protected:
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST #ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
return from - save_from; return from - save_from;
#else #else
return save_max - max; return int(save_max - max);
#endif #endif
} }

View file

@ -211,25 +211,35 @@ std::vector<std::string> ConfigOptionDef::cli_args(const std::string &key) const
ConfigOption* ConfigOptionDef::create_empty_option() const ConfigOption* ConfigOptionDef::create_empty_option() const
{ {
switch (this->type) { if (this->nullable) {
case coFloat: return new ConfigOptionFloat(); switch (this->type) {
case coFloats: return new ConfigOptionFloats(); case coFloats: return new ConfigOptionFloatsNullable();
case coInt: return new ConfigOptionInt(); case coInts: return new ConfigOptionIntsNullable();
case coInts: return new ConfigOptionInts(); case coPercents: return new ConfigOptionPercentsNullable();
case coString: return new ConfigOptionString(); case coBools: return new ConfigOptionBoolsNullable();
case coStrings: return new ConfigOptionStrings(); default: throw std::runtime_error(std::string("Unknown option type for nullable option ") + this->label);
case coPercent: return new ConfigOptionPercent(); }
case coPercents: return new ConfigOptionPercents(); } else {
case coFloatOrPercent: return new ConfigOptionFloatOrPercent(); switch (this->type) {
case coPoint: return new ConfigOptionPoint(); case coFloat: return new ConfigOptionFloat();
case coPoints: return new ConfigOptionPoints(); case coFloats: return new ConfigOptionFloats();
case coPoint3: return new ConfigOptionPoint3(); case coInt: return new ConfigOptionInt();
// case coPoint3s: return new ConfigOptionPoint3s(); case coInts: return new ConfigOptionInts();
case coBool: return new ConfigOptionBool(); case coString: return new ConfigOptionString();
case coBools: return new ConfigOptionBools(); case coStrings: return new ConfigOptionStrings();
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map); case coPercent: return new ConfigOptionPercent();
default: throw std::runtime_error(std::string("Unknown option type for option ") + this->label); case coPercents: return new ConfigOptionPercents();
} case coFloatOrPercent: return new ConfigOptionFloatOrPercent();
case coPoint: return new ConfigOptionPoint();
case coPoints: return new ConfigOptionPoints();
case coPoint3: return new ConfigOptionPoint3();
// case coPoint3s: return new ConfigOptionPoint3s();
case coBool: return new ConfigOptionBool();
case coBools: return new ConfigOptionBools();
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map);
default: throw std::runtime_error(std::string("Unknown option type for option ") + this->label);
}
}
} }
ConfigOption* ConfigOptionDef::create_default_option() const ConfigOption* ConfigOptionDef::create_default_option() const
@ -254,6 +264,13 @@ ConfigOptionDef* ConfigDef::add(const t_config_option_key &opt_key, ConfigOption
return opt; return opt;
} }
ConfigOptionDef* ConfigDef::add_nullable(const t_config_option_key &opt_key, ConfigOptionType type)
{
ConfigOptionDef *def = this->add(opt_key, type);
def->nullable = true;
return def;
}
std::string ConfigOptionDef::nocli = "~~~noCLI"; std::string ConfigOptionDef::nocli = "~~~noCLI";
std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function<bool(const ConfigOptionDef &)> filter) const std::ostream& ConfigDef::print_cli_help(std::ostream& out, bool show_defaults, std::function<bool(const ConfigOptionDef &)> filter) const
@ -642,6 +659,17 @@ void ConfigBase::save(const std::string &file) const
c.close(); c.close();
} }
// Set all the nullable values to nils.
void ConfigBase::null_nullables()
{
for (const std::string &opt_key : this->keys()) {
ConfigOption *opt = this->optptr(opt_key, false);
assert(opt != nullptr);
if (opt->nullable())
opt->deserialize("nil");
}
}
bool DynamicConfig::operator==(const DynamicConfig &rhs) const bool DynamicConfig::operator==(const DynamicConfig &rhs) const
{ {
auto it1 = this->options.begin(); auto it1 = this->options.begin();
@ -655,6 +683,19 @@ bool DynamicConfig::operator==(const DynamicConfig &rhs) const
return it1 == it1_end && it2 == it2_end; return it1 == it1_end && it2 == it2_end;
} }
// Remove options with all nil values, those are optional and it does not help to hold them.
size_t DynamicConfig::remove_nil_options()
{
size_t cnt_removed = 0;
for (auto it = options.begin(); it != options.end();)
if (it->second->is_nil()) {
it = options.erase(it);
++ cnt_removed;
} else
++ it;
return cnt_removed;
}
ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool create)
{ {
auto it = options.find(opt_key); auto it = options.find(opt_key);
@ -838,18 +879,22 @@ CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<Slic3r::Vec2d>)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<unsigned char>) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionVector<unsigned char>)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloat) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloat)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloats) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloats)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInt) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInt)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInts) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionInts)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionIntsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionString) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionString)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionStrings) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionStrings)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercent) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercent)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercents) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercents)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPercentsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatOrPercent) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionFloatOrPercent)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoints) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoints)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint3) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionPoint3)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBool) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBool)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBools) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBools)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionBoolsNullable)
CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumGeneric) CEREAL_REGISTER_TYPE(Slic3r::ConfigOptionEnumGeneric)
CEREAL_REGISTER_TYPE(Slic3r::ConfigBase) CEREAL_REGISTER_TYPE(Slic3r::ConfigBase)
CEREAL_REGISTER_TYPE(Slic3r::DynamicConfig) CEREAL_REGISTER_TYPE(Slic3r::DynamicConfig)
@ -868,17 +913,21 @@ CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::Con
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<unsigned char>) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVectorBase, Slic3r::ConfigOptionVector<unsigned char>)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<double>, Slic3r::ConfigOptionFloat) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<double>, Slic3r::ConfigOptionFloat)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloats) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloats)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<double>, Slic3r::ConfigOptionFloatsNullable)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<int>, Slic3r::ConfigOptionInt) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<int>, Slic3r::ConfigOptionInt)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionInts) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionInts)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<int>, Slic3r::ConfigOptionIntsNullable)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<std::string>, Slic3r::ConfigOptionString) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<std::string>, Slic3r::ConfigOptionString)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<std::string>, Slic3r::ConfigOptionStrings) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<std::string>, Slic3r::ConfigOptionStrings)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloat, Slic3r::ConfigOptionPercent) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloat, Slic3r::ConfigOptionPercent)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercents) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercents)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionFloats, Slic3r::ConfigOptionPercentsNullable)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionPercent, Slic3r::ConfigOptionFloatOrPercent) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionPercent, Slic3r::ConfigOptionFloatOrPercent)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec2d>, Slic3r::ConfigOptionPoint) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec2d>, Slic3r::ConfigOptionPoint)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<Slic3r::Vec2d>, Slic3r::ConfigOptionPoints) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<Slic3r::Vec2d>, Slic3r::ConfigOptionPoints)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec3d>, Slic3r::ConfigOptionPoint3) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<Slic3r::Vec3d>, Slic3r::ConfigOptionPoint3)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<bool>, Slic3r::ConfigOptionBool) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionSingle<bool>, Slic3r::ConfigOptionBool)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBools) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBools)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionVector<unsigned char>, Slic3r::ConfigOptionBoolsNullable)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInt, Slic3r::ConfigOptionEnumGeneric) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigOptionInt, Slic3r::ConfigOptionEnumGeneric)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigBase, Slic3r::DynamicConfig) CEREAL_REGISTER_POLYMORPHIC_RELATION(Slic3r::ConfigBase, Slic3r::DynamicConfig)

View file

@ -15,6 +15,7 @@
#include "clonable_ptr.hpp" #include "clonable_ptr.hpp"
#include "Point.hpp" #include "Point.hpp"
#include <boost/algorithm/string/trim.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
@ -124,6 +125,23 @@ public:
bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); }
bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; } bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; }
bool is_vector() const { return ! this->is_scalar(); } bool is_vector() const { return ! this->is_scalar(); }
// If this option is nullable, then it may have its value or values set to nil.
virtual bool nullable() const { return false; }
// A scalar is nil, or all values of a vector are nil.
virtual bool is_nil() const { return false; }
// Is this option overridden by another option?
// An option overrides another option if it is not nil and not equal.
virtual bool overriden_by(const ConfigOption *rhs) const {
assert(! this->nullable() && ! rhs->nullable());
return *this != *rhs;
}
// Apply an override option, possibly a nullable one.
virtual bool apply_override(const ConfigOption *rhs) {
if (*this == *rhs)
return false;
*this = *rhs;
return true;
}
}; };
typedef ConfigOption* ConfigOptionPtr; typedef ConfigOption* ConfigOptionPtr;
@ -183,6 +201,8 @@ public:
virtual size_t size() const = 0; virtual size_t size() const = 0;
// Is this vector empty? // Is this vector empty?
virtual bool empty() const = 0; virtual bool empty() const = 0;
// Is the value nil? That should only be possible if this->nullable().
virtual bool is_nil(size_t idx) const = 0;
protected: protected:
// Used to verify type compatibility when assigning to / from a scalar ConfigOption. // Used to verify type compatibility when assigning to / from a scalar ConfigOption.
@ -302,6 +322,62 @@ public:
bool operator==(const std::vector<T> &rhs) const { return this->values == rhs; } bool operator==(const std::vector<T> &rhs) const { return this->values == rhs; }
bool operator!=(const std::vector<T> &rhs) const { return this->values != rhs; } bool operator!=(const std::vector<T> &rhs) const { return this->values != rhs; }
// Is this option overridden by another option?
// An option overrides another option if it is not nil and not equal.
bool overriden_by(const ConfigOption *rhs) const override {
if (this->nullable())
throw std::runtime_error("Cannot override a nullable ConfigOption.");
if (rhs->type() != this->type())
throw std::runtime_error("ConfigOptionVector.overriden_by() applied to different types.");
auto rhs_vec = static_cast<const ConfigOptionVector<T>*>(rhs);
if (! rhs->nullable())
// Overridding a non-nullable object with another non-nullable object.
return this->values != rhs_vec->values;
size_t i = 0;
size_t cnt = std::min(this->size(), rhs_vec->size());
for (; i < cnt; ++ i)
if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i])
return true;
for (; i < rhs_vec->size(); ++ i)
if (! rhs_vec->is_nil(i))
return true;
return false;
}
// Apply an override option, possibly a nullable one.
bool apply_override(const ConfigOption *rhs) override {
if (this->nullable())
throw std::runtime_error("Cannot override a nullable ConfigOption.");
if (rhs->type() != this->type())
throw std::runtime_error("ConfigOptionVector.apply_override() applied to different types.");
auto rhs_vec = static_cast<const ConfigOptionVector<T>*>(rhs);
if (! rhs->nullable()) {
// Overridding a non-nullable object with another non-nullable object.
if (this->values != rhs_vec->values) {
this->values = rhs_vec->values;
return true;
}
return false;
}
size_t i = 0;
size_t cnt = std::min(this->size(), rhs_vec->size());
bool modified = false;
for (; i < cnt; ++ i)
if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) {
this->values[i] = rhs_vec->values[i];
modified = true;
}
for (; i < rhs_vec->size(); ++ i)
if (! rhs_vec->is_nil(i)) {
if (this->values.empty())
this->values.resize(i + 1);
else
this->values.resize(i + 1, this->values.front());
this->values[i] = rhs_vec->values[i];
modified = true;
}
return false;
}
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive & ar) { ar(this->values); } template<class Archive> void serialize(Archive & ar) { ar(this->values); }
@ -345,26 +421,41 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<double>>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<double>>(this)); }
}; };
class ConfigOptionFloats : public ConfigOptionVector<double> template<bool NULLABLE>
class ConfigOptionFloatsTempl : public ConfigOptionVector<double>
{ {
public: public:
ConfigOptionFloats() : ConfigOptionVector<double>() {} ConfigOptionFloatsTempl() : ConfigOptionVector<double>() {}
explicit ConfigOptionFloats(size_t n, double value) : ConfigOptionVector<double>(n, value) {} explicit ConfigOptionFloatsTempl(size_t n, double value) : ConfigOptionVector<double>(n, value) {}
explicit ConfigOptionFloats(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {} explicit ConfigOptionFloatsTempl(std::initializer_list<double> il) : ConfigOptionVector<double>(std::move(il)) {}
explicit ConfigOptionFloats(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {} explicit ConfigOptionFloatsTempl(const std::vector<double> &vec) : ConfigOptionVector<double>(vec) {}
explicit ConfigOptionFloats(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {} explicit ConfigOptionFloatsTempl(std::vector<double> &&vec) : ConfigOptionVector<double>(std::move(vec)) {}
static ConfigOptionType static_type() { return coFloats; } static ConfigOptionType static_type() { return coFloats; }
ConfigOptionType type() const override { return static_type(); } ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionFloats(*this); } ConfigOption* clone() const override { return new ConfigOptionFloatsTempl(*this); }
bool operator==(const ConfigOptionFloats &rhs) const { return this->values == rhs.values; } bool operator==(const ConfigOptionFloatsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
throw std::runtime_error("ConfigOptionFloatsTempl: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionVector<double>*>(&rhs));
return vectors_equal(this->values, static_cast<const ConfigOptionVector<double>*>(&rhs)->values);
}
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
static double nil_value() { return std::numeric_limits<double>::quiet_NaN(); }
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; }
bool is_nil(size_t idx) const override { return std::isnan(this->values[idx]); }
std::string serialize() const override std::string serialize() const override
{ {
std::ostringstream ss; std::ostringstream ss;
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { for (const double &v : this->values) {
if (it - this->values.begin() != 0) ss << ","; if (&v != &this->values.front())
ss << *it; ss << ",";
serialize_single_value(ss, v);
} }
return ss.str(); return ss.str();
} }
@ -373,14 +464,14 @@ public:
{ {
std::vector<std::string> vv; std::vector<std::string> vv;
vv.reserve(this->values.size()); vv.reserve(this->values.size());
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { for (const double v : this->values) {
std::ostringstream ss; std::ostringstream ss;
ss << *it; serialize_single_value(ss, v);
vv.push_back(ss.str()); vv.push_back(ss.str());
} }
return vv; return vv;
} }
bool deserialize(const std::string &str, bool append = false) override bool deserialize(const std::string &str, bool append = false) override
{ {
if (! append) if (! append)
@ -388,25 +479,61 @@ public:
std::istringstream is(str); std::istringstream is(str);
std::string item_str; std::string item_str;
while (std::getline(is, item_str, ',')) { while (std::getline(is, item_str, ',')) {
std::istringstream iss(item_str); boost::trim(item_str);
double value; if (item_str == "nil") {
iss >> value; if (NULLABLE)
this->values.push_back(value); this->values.push_back(nil_value());
else
std::runtime_error("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
double value;
iss >> value;
this->values.push_back(value);
}
} }
return true; return true;
} }
ConfigOptionFloats& operator=(const ConfigOption *opt) ConfigOptionFloatsTempl& operator=(const ConfigOption *opt)
{ {
this->set(opt); this->set(opt);
return *this; return *this;
} }
protected:
void serialize_single_value(std::ostringstream &ss, const double v) const {
if (std::isfinite(v))
ss << v;
else if (std::isnan(v)) {
if (NULLABLE)
ss << "nil";
else
std::runtime_error("Serializing NaN");
} else
std::runtime_error("Serializing invalid number");
}
static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
if (NULLABLE) {
if (v1.size() != v2.size())
return false;
for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2)
if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2))
return false;
return true;
} else
// Not supporting nullable values, the default vector compare is cheaper.
return v1 == v2;
}
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<double>>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<double>>(this)); }
}; };
using ConfigOptionFloats = ConfigOptionFloatsTempl<false>;
using ConfigOptionFloatsNullable = ConfigOptionFloatsTempl<true>;
class ConfigOptionInt : public ConfigOptionSingle<int> class ConfigOptionInt : public ConfigOptionSingle<int>
{ {
public: public:
@ -447,35 +574,45 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<int>>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<int>>(this)); }
}; };
class ConfigOptionInts : public ConfigOptionVector<int> template<bool NULLABLE>
class ConfigOptionIntsTempl : public ConfigOptionVector<int>
{ {
public: public:
ConfigOptionInts() : ConfigOptionVector<int>() {} ConfigOptionIntsTempl() : ConfigOptionVector<int>() {}
explicit ConfigOptionInts(size_t n, int value) : ConfigOptionVector<int>(n, value) {} explicit ConfigOptionIntsTempl(size_t n, int value) : ConfigOptionVector<int>(n, value) {}
explicit ConfigOptionInts(std::initializer_list<int> il) : ConfigOptionVector<int>(std::move(il)) {} explicit ConfigOptionIntsTempl(std::initializer_list<int> il) : ConfigOptionVector<int>(std::move(il)) {}
static ConfigOptionType static_type() { return coInts; } static ConfigOptionType static_type() { return coInts; }
ConfigOptionType type() const override { return static_type(); } ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionInts(*this); } ConfigOption* clone() const override { return new ConfigOptionIntsTempl(*this); }
ConfigOptionInts& operator=(const ConfigOption *opt) { this->set(opt); return *this; } ConfigOptionIntsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionInts &rhs) const { return this->values == rhs.values; } bool operator==(const ConfigOptionIntsTempl &rhs) const { return this->values == rhs.values; }
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
static int nil_value() { return std::numeric_limits<int>::max(); }
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); }
std::string serialize() const override { std::string serialize() const override
{
std::ostringstream ss; std::ostringstream ss;
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { for (const int &v : this->values) {
if (it - this->values.begin() != 0) ss << ","; if (&v != &this->values.front())
ss << *it; ss << ",";
serialize_single_value(ss, v);
} }
return ss.str(); return ss.str();
} }
std::vector<std::string> vserialize() const override std::vector<std::string> vserialize() const override
{ {
std::vector<std::string> vv; std::vector<std::string> vv;
vv.reserve(this->values.size()); vv.reserve(this->values.size());
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { for (const int v : this->values) {
std::ostringstream ss; std::ostringstream ss;
ss << *it; serialize_single_value(ss, v);
vv.push_back(ss.str()); vv.push_back(ss.str());
} }
return vv; return vv;
@ -488,19 +625,40 @@ public:
std::istringstream is(str); std::istringstream is(str);
std::string item_str; std::string item_str;
while (std::getline(is, item_str, ',')) { while (std::getline(is, item_str, ',')) {
std::istringstream iss(item_str); boost::trim(item_str);
int value; if (item_str == "nil") {
iss >> value; if (NULLABLE)
this->values.push_back(value); this->values.push_back(nil_value());
else
std::runtime_error("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
int value;
iss >> value;
this->values.push_back(value);
}
} }
return true; return true;
} }
private: private:
void serialize_single_value(std::ostringstream &ss, const int v) const {
if (v == nil_value()) {
if (NULLABLE)
ss << "nil";
else
std::runtime_error("Serializing NaN");
} else
ss << v;
}
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<int>>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<int>>(this)); }
}; };
using ConfigOptionInts = ConfigOptionIntsTempl<false>;
using ConfigOptionIntsNullable = ConfigOptionIntsTempl<true>;
class ConfigOptionString : public ConfigOptionSingle<std::string> class ConfigOptionString : public ConfigOptionSingle<std::string>
{ {
public: public:
@ -544,6 +702,7 @@ public:
ConfigOption* clone() const override { return new ConfigOptionStrings(*this); } ConfigOption* clone() const override { return new ConfigOptionStrings(*this); }
ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; } ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionStrings &rhs) const { return this->values == rhs.values; } bool operator==(const ConfigOptionStrings &rhs) const { return this->values == rhs.values; }
bool is_nil(size_t idx) const override { return false; }
std::string serialize() const override std::string serialize() const override
{ {
@ -603,64 +762,61 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloat>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloat>(this)); }
}; };
class ConfigOptionPercents : public ConfigOptionFloats template<bool NULLABLE>
class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl<NULLABLE>
{ {
public: public:
ConfigOptionPercents() : ConfigOptionFloats() {} ConfigOptionPercentsTempl() : ConfigOptionFloatsTempl<NULLABLE>() {}
explicit ConfigOptionPercents(size_t n, double value) : ConfigOptionFloats(n, value) {} explicit ConfigOptionPercentsTempl(size_t n, double value) : ConfigOptionFloatsTempl<NULLABLE>(n, value) {}
explicit ConfigOptionPercents(std::initializer_list<double> il) : ConfigOptionFloats(std::move(il)) {} explicit ConfigOptionPercentsTempl(std::initializer_list<double> il) : ConfigOptionFloatsTempl<NULLABLE>(std::move(il)) {}
explicit ConfigOptionPercentsTempl(const std::vector<double>& vec) : ConfigOptionFloatsTempl<NULLABLE>(vec) {}
explicit ConfigOptionPercentsTempl(std::vector<double>&& vec) : ConfigOptionFloatsTempl<NULLABLE>(std::move(vec)) {}
static ConfigOptionType static_type() { return coPercents; } static ConfigOptionType static_type() { return coPercents; }
ConfigOptionType type() const override { return static_type(); } ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionPercents(*this); } ConfigOption* clone() const override { return new ConfigOptionPercentsTempl(*this); }
ConfigOptionPercents& operator=(const ConfigOption *opt) { this->set(opt); return *this; } ConfigOptionPercentsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionPercents &rhs) const { return this->values == rhs.values; } bool operator==(const ConfigOptionPercentsTempl &rhs) const { return this->values == rhs.values; }
std::string serialize() const override std::string serialize() const override
{ {
std::ostringstream ss; std::ostringstream ss;
for (const auto &v : this->values) { for (const double &v : this->values) {
if (&v != &this->values.front()) ss << ","; if (&v != &this->values.front())
ss << v << "%"; ss << ",";
this->serialize_single_value(ss, v);
if (! std::isnan(v))
ss << "%";
} }
std::string str = ss.str(); std::string str = ss.str();
return str; return str;
} }
std::vector<std::string> vserialize() const override std::vector<std::string> vserialize() const override
{ {
std::vector<std::string> vv; std::vector<std::string> vv;
vv.reserve(this->values.size()); vv.reserve(this->values.size());
for (const auto v : this->values) { for (const double v : this->values) {
std::ostringstream ss; std::ostringstream ss;
ss << v; this->serialize_single_value(ss, v);
std::string sout = ss.str() + "%"; if (! std::isnan(v))
vv.push_back(sout); ss << "%";
vv.push_back(ss.str());
} }
return vv; return vv;
} }
bool deserialize(const std::string &str, bool append = false) override // The float's deserialize function shall ignore the trailing optional %.
{ // bool deserialize(const std::string &str, bool append = false) override;
if (! append)
this->values.clear();
std::istringstream is(str);
std::string item_str;
while (std::getline(is, item_str, ',')) {
std::istringstream iss(item_str);
double value;
// don't try to parse the trailing % since it's optional
iss >> value;
this->values.push_back(value);
}
return true;
}
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloats>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionFloatsTempl<NULLABLE>>(this)); }
}; };
using ConfigOptionPercents = ConfigOptionPercentsTempl<false>;
using ConfigOptionPercentsNullable = ConfigOptionPercentsTempl<true>;
class ConfigOptionFloatOrPercent : public ConfigOptionPercent class ConfigOptionFloatOrPercent : public ConfigOptionPercent
{ {
public: public:
@ -761,6 +917,7 @@ public:
ConfigOption* clone() const override { return new ConfigOptionPoints(*this); } ConfigOption* clone() const override { return new ConfigOptionPoints(*this); }
ConfigOptionPoints& operator=(const ConfigOption *opt) { this->set(opt); return *this; } ConfigOptionPoints& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionPoints &rhs) const { return this->values == rhs.values; } bool operator==(const ConfigOptionPoints &rhs) const { return this->values == rhs.values; }
bool is_nil(size_t idx) const override { return false; }
std::string serialize() const override std::string serialize() const override
{ {
@ -887,18 +1044,29 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<bool>>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionSingle<bool>>(this)); }
}; };
class ConfigOptionBools : public ConfigOptionVector<unsigned char> template<bool NULLABLE>
class ConfigOptionBoolsTempl : public ConfigOptionVector<unsigned char>
{ {
public: public:
ConfigOptionBools() : ConfigOptionVector<unsigned char>() {} ConfigOptionBoolsTempl() : ConfigOptionVector<unsigned char>() {}
explicit ConfigOptionBools(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {} explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector<unsigned char>(n, (unsigned char)value) {}
explicit ConfigOptionBools(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); } explicit ConfigOptionBoolsTempl(std::initializer_list<bool> il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); }
explicit ConfigOptionBoolsTempl(std::initializer_list<unsigned char> il) { values.reserve(il.size()); for (unsigned char b : il) values.emplace_back(b); }
explicit ConfigOptionBoolsTempl(const std::vector<unsigned char>& vec) : ConfigOptionVector<unsigned char>(vec) {}
explicit ConfigOptionBoolsTempl(std::vector<unsigned char>&& vec) : ConfigOptionVector<unsigned char>(std::move(vec)) {}
static ConfigOptionType static_type() { return coBools; } static ConfigOptionType static_type() { return coBools; }
ConfigOptionType type() const override { return static_type(); } ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionBools(*this); } ConfigOption* clone() const override { return new ConfigOptionBoolsTempl(*this); }
ConfigOptionBools& operator=(const ConfigOption *opt) { this->set(opt); return *this; } ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionBools &rhs) const { return this->values == rhs.values; } bool operator==(const ConfigOptionBoolsTempl &rhs) const { return this->values == rhs.values; }
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
static unsigned char nil_value() { return std::numeric_limits<unsigned char>::max(); }
// A scalar is nil, or all values of a vector are nil.
bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; }
bool is_nil(size_t idx) const override { return this->values[idx] == nil_value(); }
bool& get_at(size_t i) { bool& get_at(size_t i) {
assert(! this->values.empty()); assert(! this->values.empty());
@ -911,19 +1079,20 @@ public:
std::string serialize() const override std::string serialize() const override
{ {
std::ostringstream ss; std::ostringstream ss;
for (std::vector<unsigned char>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { for (const unsigned char &v : this->values) {
if (it - this->values.begin() != 0) ss << ","; if (&v != &this->values.front())
ss << (*it ? "1" : "0"); ss << ",";
} this->serialize_single_value(ss, v);
}
return ss.str(); return ss.str();
} }
std::vector<std::string> vserialize() const override std::vector<std::string> vserialize() const override
{ {
std::vector<std::string> vv; std::vector<std::string> vv;
for (std::vector<unsigned char>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) { for (const unsigned char v : this->values) {
std::ostringstream ss; std::ostringstream ss;
ss << (*it ? "1" : "0"); this->serialize_single_value(ss, v);
vv.push_back(ss.str()); vv.push_back(ss.str());
} }
return vv; return vv;
@ -936,16 +1105,37 @@ public:
std::istringstream is(str); std::istringstream is(str);
std::string item_str; std::string item_str;
while (std::getline(is, item_str, ',')) { while (std::getline(is, item_str, ',')) {
this->values.push_back(item_str.compare("1") == 0); boost::trim(item_str);
if (item_str == "nil") {
if (NULLABLE)
this->values.push_back(nil_value());
else
std::runtime_error("Deserializing nil into a non-nullable object");
} else
this->values.push_back(item_str.compare("1") == 0);
} }
return true; return true;
} }
protected:
void serialize_single_value(std::ostringstream &ss, const unsigned char v) const {
if (v == nil_value()) {
if (NULLABLE)
ss << "nil";
else
std::runtime_error("Serializing NaN");
} else
ss << (v ? "1" : "0");
}
private: private:
friend class cereal::access; friend class cereal::access;
template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<unsigned char>>(this)); } template<class Archive> void serialize(Archive &ar) { ar(cereal::base_class<ConfigOptionVector<unsigned char>>(this)); }
}; };
using ConfigOptionBools = ConfigOptionBoolsTempl<false>;
using ConfigOptionBoolsNullable = ConfigOptionBoolsTempl<true>;
// Map from an enum integer value to an enum name. // Map from an enum integer value to an enum name.
typedef std::vector<std::string> t_config_enum_names; typedef std::vector<std::string> t_config_enum_names;
// Map from an enum name to an enum integer value. // Map from an enum name to an enum integer value.
@ -1096,6 +1286,8 @@ public:
t_config_option_key opt_key; t_config_option_key opt_key;
// What type? bool, int, string etc. // What type? bool, int, string etc.
ConfigOptionType type = coNone; ConfigOptionType type = coNone;
// If a type is nullable, then it accepts a "nil" value (scalar) or "nil" values (vector).
bool nullable = false;
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor. // Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
Slic3r::clonable_ptr<const ConfigOption> default_value; Slic3r::clonable_ptr<const ConfigOption> default_value;
void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr); } void set_default_value(const ConfigOption* ptr) { this->default_value = Slic3r::clonable_ptr<const ConfigOption>(ptr); }
@ -1107,45 +1299,65 @@ public:
ConfigOption* create_default_option() const; ConfigOption* create_default_option() const;
template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const { template<class Archive> ConfigOption* load_option_from_archive(Archive &archive) const {
switch (this->type) { if (this->nullable) {
case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; } switch (this->type) {
case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; } case coFloats: { auto opt = new ConfigOptionFloatsNullable(); archive(*opt); return opt; }
case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; } case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; } case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; } case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; } default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; } }
case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; } } else {
case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; } switch (this->type) {
case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; } case coFloat: { auto opt = new ConfigOptionFloat(); archive(*opt); return opt; }
case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; } case coFloats: { auto opt = new ConfigOptionFloats(); archive(*opt); return opt; }
case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; } case coInt: { auto opt = new ConfigOptionInt(); archive(*opt); return opt; }
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; } case coInts: { auto opt = new ConfigOptionInts(); archive(*opt); return opt; }
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; } case coString: { auto opt = new ConfigOptionString(); archive(*opt); return opt; }
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; } case coStrings: { auto opt = new ConfigOptionStrings(); archive(*opt); return opt; }
default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key); case coPercent: { auto opt = new ConfigOptionPercent(); archive(*opt); return opt; }
} case coPercents: { auto opt = new ConfigOptionPercents(); archive(*opt); return opt; }
case coFloatOrPercent: { auto opt = new ConfigOptionFloatOrPercent(); archive(*opt); return opt; }
case coPoint: { auto opt = new ConfigOptionPoint(); archive(*opt); return opt; }
case coPoints: { auto opt = new ConfigOptionPoints(); archive(*opt); return opt; }
case coPoint3: { auto opt = new ConfigOptionPoint3(); archive(*opt); return opt; }
case coBool: { auto opt = new ConfigOptionBool(); archive(*opt); return opt; }
case coBools: { auto opt = new ConfigOptionBools(); archive(*opt); return opt; }
case coEnum: { auto opt = new ConfigOptionEnumGeneric(this->enum_keys_map); archive(*opt); return opt; }
default: throw std::runtime_error(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
}
}
} }
template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const { template<class Archive> ConfigOption* save_option_to_archive(Archive &archive, const ConfigOption *opt) const {
switch (this->type) { if (this->nullable) {
case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break; switch (this->type) {
case coFloats: archive(*static_cast<const ConfigOptionFloats*>(opt)); break; case coFloats: archive(*static_cast<const ConfigOptionFloatsNullable*>(opt)); break;
case coInt: archive(*static_cast<const ConfigOptionInt*>(opt)); break; case coInts: archive(*static_cast<const ConfigOptionIntsNullable*>(opt)); break;
case coInts: archive(*static_cast<const ConfigOptionInts*>(opt)); break; case coPercents: archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break;
case coString: archive(*static_cast<const ConfigOptionString*>(opt)); break; case coBools: archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); break;
case coStrings: archive(*static_cast<const ConfigOptionStrings*>(opt)); break; default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
case coPercent: archive(*static_cast<const ConfigOptionPercent*>(opt)); break; }
case coPercents: archive(*static_cast<const ConfigOptionPercents*>(opt)); break; } else {
case coFloatOrPercent: archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt)); break; switch (this->type) {
case coPoint: archive(*static_cast<const ConfigOptionPoint*>(opt)); break; case coFloat: archive(*static_cast<const ConfigOptionFloat*>(opt)); break;
case coPoints: archive(*static_cast<const ConfigOptionPoints*>(opt)); break; case coFloats: archive(*static_cast<const ConfigOptionFloats*>(opt)); break;
case coPoint3: archive(*static_cast<const ConfigOptionPoint3*>(opt)); break; case coInt: archive(*static_cast<const ConfigOptionInt*>(opt)); break;
case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break; case coInts: archive(*static_cast<const ConfigOptionInts*>(opt)); break;
case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break; case coString: archive(*static_cast<const ConfigOptionString*>(opt)); break;
case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break; case coStrings: archive(*static_cast<const ConfigOptionStrings*>(opt)); break;
default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key); case coPercent: archive(*static_cast<const ConfigOptionPercent*>(opt)); break;
} case coPercents: archive(*static_cast<const ConfigOptionPercents*>(opt)); break;
case coFloatOrPercent: archive(*static_cast<const ConfigOptionFloatOrPercent*>(opt)); break;
case coPoint: archive(*static_cast<const ConfigOptionPoint*>(opt)); break;
case coPoints: archive(*static_cast<const ConfigOptionPoints*>(opt)); break;
case coPoint3: archive(*static_cast<const ConfigOptionPoint3*>(opt)); break;
case coBool: archive(*static_cast<const ConfigOptionBool*>(opt)); break;
case coBools: archive(*static_cast<const ConfigOptionBools*>(opt)); break;
case coEnum: archive(*static_cast<const ConfigOptionEnumGeneric*>(opt)); break;
default: throw std::runtime_error(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
}
}
// Make the compiler happy, shut up the warnings. // Make the compiler happy, shut up the warnings.
return nullptr; return nullptr;
} }
@ -1263,6 +1475,7 @@ public:
protected: protected:
ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type); ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type);
ConfigOptionDef* add_nullable(const t_config_option_key &opt_key, ConfigOptionType type);
}; };
// An abstract configuration store. // An abstract configuration store.
@ -1347,6 +1560,9 @@ public:
void load(const boost::property_tree::ptree &tree); void load(const boost::property_tree::ptree &tree);
void save(const std::string &file) const; void save(const std::string &file) const;
// Set all the nullable values to nils.
void null_nullables();
private: private:
// Set a configuration value from a string. // Set a configuration value from a string.
bool set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &str, bool append); bool set_deserialize_raw(const t_config_option_key &opt_key_src, const std::string &str, bool append);
@ -1444,9 +1660,12 @@ public:
return true; return true;
} }
// Remove options with all nil values, those are optional and it does not help to hold them.
size_t remove_nil_options();
// Allow DynamicConfig to be instantiated on ints own without a definition. // Allow DynamicConfig to be instantiated on ints own without a definition.
// If the definition is not defined, the method requiring the definition will throw NoDefinitionException. // If the definition is not defined, the method requiring the definition will throw NoDefinitionException.
const ConfigDef* def() const override { return nullptr; }; const ConfigDef* def() const override { return nullptr; }
template<class T> T* opt(const t_config_option_key &opt_key, bool create = false) template<class T> T* opt(const t_config_option_key &opt_key, bool create = false)
{ return dynamic_cast<T*>(this->option(opt_key, create)); } { return dynamic_cast<T*>(this->option(opt_key, create)); }
template<class T> const T* opt(const t_config_option_key &opt_key) const template<class T> const T* opt(const t_config_option_key &opt_key) const

View file

@ -1829,25 +1829,12 @@ void GCode::apply_print_config(const PrintConfig &print_config)
m_config.apply(print_config); m_config.apply(print_config);
} }
void GCode::append_full_config(const Print& print, std::string& str) void GCode::append_full_config(const Print &print, std::string &str)
{ {
const StaticPrintConfig *configs[] = { static_cast<const GCodeConfig*>(&print.config()), &print.default_object_config(), &print.default_region_config() }; const DynamicPrintConfig &cfg = print.full_print_config();
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) { for (const std::string &key : cfg.keys())
const StaticPrintConfig *cfg = configs[i]; if (key != "compatible_prints" && key != "compatible_printers" && ! cfg.option(key)->is_nil())
for (const std::string &key : cfg->keys()) str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
if (key != "compatible_printers")
str += "; " + key + " = " + cfg->opt_serialize(key) + "\n";
}
const DynamicConfig &full_config = print.placeholder_parser().config();
for (const char *key : {
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
"printer_model", "printer_variant",
"default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
"compatible_prints_condition_cummulative", "compatible_printers_condition_cummulative", "inherits_cummulative" }) {
const ConfigOption *opt = full_config.option(key);
if (opt != nullptr)
str += std::string("; ") + key + " = " + opt->serialize() + "\n";
}
} }
void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids) void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)

View file

@ -134,7 +134,7 @@ public:
m_filpar[idx].cooling_final_speed = cooling_final_speed; m_filpar[idx].cooling_final_speed = cooling_final_speed;
} }
m_filpar[idx].filament_area = (M_PI/4.f) * pow(filament_diameter, 2); // all extruders are assumed to have the same filament diameter at this point m_filpar[idx].filament_area = float((M_PI/4.f) * pow(filament_diameter, 2)); // all extruders are assumed to have the same filament diameter at this point
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
if (max_volumetric_speed != 0.f) if (max_volumetric_speed != 0.f)

View file

@ -62,7 +62,7 @@
namespace Slic3r { namespace Slic3r {
PlaceholderParser::PlaceholderParser() PlaceholderParser::PlaceholderParser(const DynamicConfig *external_config) : m_external_config(external_config)
{ {
this->set("version", std::string(SLIC3R_VERSION)); this->set("version", std::string(SLIC3R_VERSION));
this->apply_env_variables(); this->apply_env_variables();
@ -94,14 +94,6 @@ void PlaceholderParser::update_timestamp(DynamicConfig &config)
config.set_key_value("second", new ConfigOptionInt(timeinfo->tm_sec)); config.set_key_value("second", new ConfigOptionInt(timeinfo->tm_sec));
} }
// Ignore this key by the placeholder parser.
static inline bool placeholder_parser_ignore(const ConfigDef *def, const std::string &opt_key)
{
const ConfigOptionDef *opt_def = def->get(opt_key);
assert(opt_def != nullptr);
return (opt_def->multiline && boost::ends_with(opt_key, "_gcode")) || opt_key == "post_process";
}
static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConfig &config_new, const std::string &opt_key) static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConfig &config_new, const std::string &opt_key)
{ {
const ConfigOption *opt_old = config_old.option(opt_key); const ConfigOption *opt_old = config_old.option(opt_key);
@ -119,7 +111,7 @@ std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig
const ConfigDef *def = rhs.def(); const ConfigDef *def = rhs.def();
std::vector<std::string> diff_keys; std::vector<std::string> diff_keys;
for (const t_config_option_key &opt_key : rhs.keys()) for (const t_config_option_key &opt_key : rhs.keys())
if (! placeholder_parser_ignore(def, opt_key) && ! opts_equal(m_config, rhs, opt_key)) if (! opts_equal(m_config, rhs, opt_key))
diff_keys.emplace_back(opt_key); diff_keys.emplace_back(opt_key);
return diff_keys; return diff_keys;
} }
@ -135,8 +127,6 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
const ConfigDef *def = rhs.def(); const ConfigDef *def = rhs.def();
bool modified = false; bool modified = false;
for (const t_config_option_key &opt_key : rhs.keys()) { for (const t_config_option_key &opt_key : rhs.keys()) {
if (placeholder_parser_ignore(def, opt_key))
continue;
if (! opts_equal(m_config, rhs, opt_key)) { if (! opts_equal(m_config, rhs, opt_key)) {
// Store a copy of the config option. // Store a copy of the config option.
// Convert FloatOrPercent values to floats first. // Convert FloatOrPercent values to floats first.
@ -155,7 +145,6 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector<std::string> &keys) void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector<std::string> &keys)
{ {
for (const t_config_option_key &opt_key : keys) { for (const t_config_option_key &opt_key : keys) {
assert(! placeholder_parser_ignore(rhs.def(), opt_key));
// Store a copy of the config option. // Store a copy of the config option.
// Convert FloatOrPercent values to floats first. // Convert FloatOrPercent values to floats first.
//FIXME there are some ratio_over chains, which end with empty ratio_with. //FIXME there are some ratio_over chains, which end with empty ratio_with.
@ -167,6 +156,11 @@ void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vec
} }
} }
void PlaceholderParser::apply_config(DynamicPrintConfig &&rhs)
{
m_config += std::move(rhs);
}
void PlaceholderParser::apply_env_variables() void PlaceholderParser::apply_env_variables()
{ {
for (char** env = environ; *env; ++ env) { for (char** env = environ; *env; ++ env) {
@ -608,6 +602,7 @@ namespace client
} }
struct MyContext { struct MyContext {
const DynamicConfig *external_config = nullptr;
const DynamicConfig *config = nullptr; const DynamicConfig *config = nullptr;
const DynamicConfig *config_override = nullptr; const DynamicConfig *config_override = nullptr;
size_t current_extruder_id = 0; size_t current_extruder_id = 0;
@ -628,6 +623,8 @@ namespace client
opt = config_override->option(opt_key); opt = config_override->option(opt_key);
if (opt == nullptr) if (opt == nullptr)
opt = config->option(opt_key); opt = config->option(opt_key);
if (opt == nullptr && external_config != nullptr)
opt = external_config->option(opt_key);
return opt; return opt;
} }
@ -1255,6 +1252,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const
{ {
client::MyContext context; client::MyContext context;
context.external_config = this->external_config();
context.config = &this->config(); context.config = &this->config();
context.config_override = config_override; context.config_override = config_override;
context.current_extruder_id = current_extruder_id; context.current_extruder_id = current_extruder_id;
@ -1266,8 +1264,8 @@ std::string PlaceholderParser::process(const std::string &templ, unsigned int cu
bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override) bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override)
{ {
client::MyContext context; client::MyContext context;
context.config = &config; context.config = &config;
context.config_override = config_override; context.config_override = config_override;
// Let the macro processor parse just a boolean expression, not the full macro language. // Let the macro processor parse just a boolean expression, not the full macro language.
context.just_boolean_expression = true; context.just_boolean_expression = true;
return process_macro(templ, context) == "true"; return process_macro(templ, context) == "true";

View file

@ -12,13 +12,14 @@ namespace Slic3r {
class PlaceholderParser class PlaceholderParser
{ {
public: public:
PlaceholderParser(); PlaceholderParser(const DynamicConfig *external_config = nullptr);
// Return a list of keys, which should be changed in m_config from rhs. // Return a list of keys, which should be changed in m_config from rhs.
// This contains keys, which are found in rhs, but not in m_config. // This contains keys, which are found in rhs, but not in m_config.
std::vector<std::string> config_diff(const DynamicPrintConfig &rhs); std::vector<std::string> config_diff(const DynamicPrintConfig &rhs);
// Return true if modified. // Return true if modified.
bool apply_config(const DynamicPrintConfig &config); bool apply_config(const DynamicPrintConfig &config);
void apply_config(DynamicPrintConfig &&config);
// To be called on the values returned by PlaceholderParser::config_diff(). // To be called on the values returned by PlaceholderParser::config_diff().
// The keys should already be valid. // The keys should already be valid.
void apply_only(const DynamicPrintConfig &config, const std::vector<std::string> &keys); void apply_only(const DynamicPrintConfig &config, const std::vector<std::string> &keys);
@ -35,6 +36,8 @@ public:
DynamicConfig& config_writable() { return m_config; } DynamicConfig& config_writable() { return m_config; }
const DynamicConfig& config() const { return m_config; } const DynamicConfig& config() const { return m_config; }
const ConfigOption* option(const std::string &key) const { return m_config.option(key); } const ConfigOption* option(const std::string &key) const { return m_config.option(key); }
// External config is not owned by PlaceholderParser. It has a lowest priority when looking up an option.
const DynamicConfig* external_config() const { return m_external_config; }
// Fill in the template using a macro processing language. // Fill in the template using a macro processing language.
// Throws std::runtime_error on syntax or runtime error. // Throws std::runtime_error on syntax or runtime error.
@ -50,7 +53,9 @@ public:
void update_timestamp() { update_timestamp(m_config); } void update_timestamp() { update_timestamp(m_config); }
private: private:
DynamicConfig m_config; // config has a higher priority than external_config when looking up a symbol.
DynamicConfig m_config;
const DynamicConfig *m_external_config;
}; };
} }

View file

@ -485,25 +485,82 @@ bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_c
return true; return true;
} }
Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &config_in) // Collect diffs of configuration values at various containers,
// resolve the filament rectract overrides of extruder retract values.
void Print::config_diffs(
const DynamicPrintConfig &new_full_config,
t_config_option_keys &print_diff, t_config_option_keys &object_diff, t_config_option_keys &region_diff,
t_config_option_keys &full_config_diff,
DynamicPrintConfig &placeholder_parser_overrides,
DynamicPrintConfig &filament_overrides) const
{
// Collect changes to print config, account for overrides of extruder retract values by filament presets.
{
const std::vector<std::string> &extruder_retract_keys = print_config_def.extruder_retract_keys();
const std::string filament_prefix = "filament_";
for (const t_config_option_key &opt_key : m_config.keys()) {
const ConfigOption *opt_old = m_config.option(opt_key);
assert(opt_old != nullptr);
const ConfigOption *opt_new = new_full_config.option(opt_key);
// assert(opt_new != nullptr);
if (opt_new == nullptr)
//FIXME This may happen when executing some test cases.
continue;
const ConfigOption *opt_new_filament = std::binary_search(extruder_retract_keys.begin(), extruder_retract_keys.end(), opt_key) ? new_full_config.option(filament_prefix + opt_key) : nullptr;
if (opt_new_filament != nullptr && ! opt_new_filament->is_nil()) {
// An extruder retract override is available at some of the filament presets.
if (*opt_old != *opt_new || opt_new->overriden_by(opt_new_filament)) {
auto opt_copy = opt_new->clone();
opt_copy->apply_override(opt_new_filament);
if (*opt_old == *opt_copy)
delete opt_copy;
else {
filament_overrides.set_key_value(opt_key, opt_copy);
print_diff.emplace_back(opt_key);
}
}
} else if (*opt_new != *opt_old)
print_diff.emplace_back(opt_key);
}
}
// Collect changes to object and region configs.
object_diff = m_default_object_config.diff(new_full_config);
region_diff = m_default_region_config.diff(new_full_config);
// Prepare for storing of the full print config into new_full_config to be exported into the G-code and to be used by the PlaceholderParser.
// As the PlaceholderParser does not interpret the FloatOrPercent values itself, these values are stored into the PlaceholderParser converted to floats.
for (const t_config_option_key &opt_key : new_full_config.keys()) {
const ConfigOption *opt_old = m_full_print_config.option(opt_key);
const ConfigOption *opt_new = new_full_config.option(opt_key);
if (opt_old == nullptr || *opt_new != *opt_old)
full_config_diff.emplace_back(opt_key);
if (opt_new->type() == coFloatOrPercent) {
// The m_placeholder_parser is never modified by the background processing, GCode.cpp/hpp makes a copy.
const ConfigOption *opt_old_pp = this->placeholder_parser().config().option(opt_key);
double new_value = new_full_config.get_abs_value(opt_key);
if (opt_old_pp == nullptr || static_cast<const ConfigOptionFloat*>(opt_old_pp)->value != new_value)
placeholder_parser_overrides.set_key_value(opt_key, new ConfigOptionFloat(new_value));
}
}
}
Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config)
{ {
#ifdef _DEBUG #ifdef _DEBUG
check_model_ids_validity(model); check_model_ids_validity(model);
#endif /* _DEBUG */ #endif /* _DEBUG */
// Make a copy of the config, normalize it. // Normalize the config.
DynamicPrintConfig config(config_in); new_full_config.option("print_settings_id", true);
config.option("print_settings_id", true); new_full_config.option("filament_settings_id", true);
config.option("filament_settings_id", true); new_full_config.option("printer_settings_id", true);
config.option("printer_settings_id", true); new_full_config.normalize();
config.normalize();
// Collect changes to print config.
t_config_option_keys print_diff = m_config.diff(config);
t_config_option_keys object_diff = m_default_object_config.diff(config);
t_config_option_keys region_diff = m_default_region_config.diff(config);
t_config_option_keys placeholder_parser_diff = this->placeholder_parser().config_diff(config);
// Do not use the ApplyStatus as we will use the max function when updating apply_status. // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles.
t_config_option_keys print_diff, object_diff, region_diff, full_config_diff;
DynamicPrintConfig placeholder_parser_overrides, filament_overrides;
this->config_diffs(new_full_config, print_diff, object_diff, region_diff, full_config_diff, placeholder_parser_overrides, filament_overrides);
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
unsigned int apply_status = APPLY_STATUS_UNCHANGED; unsigned int apply_status = APPLY_STATUS_UNCHANGED;
auto update_apply_status = [&apply_status](bool invalidated) auto update_apply_status = [&apply_status](bool invalidated)
{ apply_status = std::max<unsigned int>(apply_status, invalidated ? APPLY_STATUS_INVALIDATED : APPLY_STATUS_CHANGED); }; { apply_status = std::max<unsigned int>(apply_status, invalidated ? APPLY_STATUS_INVALIDATED : APPLY_STATUS_CHANGED); };
@ -516,24 +573,25 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
// The following call may stop the background processing. // The following call may stop the background processing.
if (! print_diff.empty()) if (! print_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(print_diff)); update_apply_status(this->invalidate_state_by_config_options(print_diff));
// Apply variables to placeholder parser. The placeholder parser is used by G-code export, // Apply variables to placeholder parser. The placeholder parser is used by G-code export,
// which should be stopped if print_diff is not empty. // which should be stopped if print_diff is not empty.
if (! placeholder_parser_diff.empty()) { if (! full_config_diff.empty() || ! placeholder_parser_overrides.empty()) {
update_apply_status(this->invalidate_step(psGCodeExport)); update_apply_status(this->invalidate_step(psGCodeExport));
PlaceholderParser &pp = this->placeholder_parser(); m_placeholder_parser.apply_config(std::move(placeholder_parser_overrides));
pp.apply_only(config, placeholder_parser_diff);
// Set the profile aliases for the PrintBase::output_filename() // Set the profile aliases for the PrintBase::output_filename()
pp.set("print_preset", config.option("print_settings_id")->clone()); m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
pp.set("filament_preset", config.option("filament_settings_id")->clone()); m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
pp.set("printer_preset", config.option("printer_settings_id")->clone()); m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone());
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
m_config.apply_only(new_full_config, print_diff, true);
m_config.apply(filament_overrides);
// Handle changes to object config defaults
m_default_object_config.apply_only(new_full_config, object_diff, true);
// Handle changes to regions config defaults
m_default_region_config.apply_only(new_full_config, region_diff, true);
m_full_print_config = std::move(new_full_config);
} }
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
m_config.apply_only(config, print_diff, true);
// Handle changes to object config defaults
m_default_object_config.apply_only(config, object_diff, true);
// Handle changes to regions config defaults
m_default_region_config.apply_only(config, region_diff, true);
class LayerRanges class LayerRanges
{ {
@ -545,9 +603,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
m_ranges.reserve(in.size()); m_ranges.reserve(in.size());
// Input ranges are sorted lexicographically. First range trims the other ranges. // Input ranges are sorted lexicographically. First range trims the other ranges.
coordf_t last_z = 0; coordf_t last_z = 0;
for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in) { for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in)
// for (auto &range : in) { if (range.first.second > last_z) {
if (range.first.second > last_z) {
coordf_t min_z = std::max(range.first.first, 0.); coordf_t min_z = std::max(range.first.first, 0.);
if (min_z > last_z + EPSILON) { if (min_z > last_z + EPSILON) {
m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr); m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr);
@ -559,7 +616,6 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
last_z = range.first.second; last_z = range.first.second;
} }
} }
}
if (m_ranges.empty()) if (m_ranges.empty())
m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr); m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr);
else if (m_ranges.back().second == nullptr) else if (m_ranges.back().second == nullptr)
@ -1707,9 +1763,9 @@ void Print::_make_wipe_tower()
(float)m_config.filament_cooling_initial_speed.get_at(i), (float)m_config.filament_cooling_initial_speed.get_at(i),
(float)m_config.filament_cooling_final_speed.get_at(i), (float)m_config.filament_cooling_final_speed.get_at(i),
m_config.filament_ramming_parameters.get_at(i), m_config.filament_ramming_parameters.get_at(i),
m_config.filament_max_volumetric_speed.get_at(i), (float)m_config.filament_max_volumetric_speed.get_at(i),
m_config.nozzle_diameter.get_at(i), (float)m_config.nozzle_diameter.get_at(i),
m_config.filament_diameter.get_at(i)); (float)m_config.filament_diameter.get_at(i));
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>( m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));
@ -1791,47 +1847,7 @@ std::string Print::output_filename(const std::string &filename_base) const
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config); return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
} }
/*
// Shorten the dhms time by removing the seconds, rounding the dhm to full minutes
// and removing spaces.
static std::string short_time(const std::string &time)
{
// Parse the dhms time format.
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
if (time.find('d') != std::string::npos)
::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds);
else if (time.find('h') != std::string::npos)
::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds);
else if (time.find('m') != std::string::npos)
::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds);
else if (time.find('s') != std::string::npos)
::sscanf(time.c_str(), "%ds", &seconds);
// Round to full minutes.
if (days + hours + minutes > 0 && seconds >= 30) {
if (++ minutes == 60) {
minutes = 0;
if (++ hours == 24) {
hours = 0;
++ days;
}
}
}
// Format the dhm time.
char buffer[64];
if (days > 0)
::sprintf(buffer, "%dd%dh%dm", days, hours, minutes);
else if (hours > 0)
::sprintf(buffer, "%dh%dm", hours, minutes);
else if (minutes > 0)
::sprintf(buffer, "%dm", minutes);
else
::sprintf(buffer, "%ds", seconds);
return buffer;
}
*/
DynamicConfig PrintStatistics::config() const DynamicConfig PrintStatistics::config() const
{ {
DynamicConfig config; DynamicConfig config;

View file

@ -296,7 +296,7 @@ public:
void clear() override; void clear() override;
bool empty() const override { return m_objects.empty(); } bool empty() const override { return m_objects.empty(); }
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
void process() override; void process() override;
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file. // Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
@ -368,6 +368,13 @@ protected:
bool invalidate_step(PrintStep step); bool invalidate_step(PrintStep step);
private: private:
void config_diffs(
const DynamicPrintConfig &new_full_config,
t_config_option_keys &print_diff, t_config_option_keys &object_diff, t_config_option_keys &region_diff,
t_config_option_keys &full_config_diff,
DynamicPrintConfig &placeholder_parser_overrides,
DynamicPrintConfig &filament_overrides) const;
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
void _make_skirt(); void _make_skirt();

View file

@ -217,7 +217,7 @@ protected:
class PrintBase class PrintBase
{ {
public: public:
PrintBase() { this->restart(); } PrintBase() : m_placeholder_parser(&m_full_print_config) { this->restart(); }
inline virtual ~PrintBase() {} inline virtual ~PrintBase() {}
virtual PrinterTechnology technology() const noexcept = 0; virtual PrinterTechnology technology() const noexcept = 0;
@ -240,7 +240,7 @@ public:
// Some data was changed, which in turn invalidated already calculated steps. // Some data was changed, which in turn invalidated already calculated steps.
APPLY_STATUS_INVALIDATED, APPLY_STATUS_INVALIDATED,
}; };
virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0; virtual ApplyStatus apply(const Model &model, DynamicPrintConfig config) = 0;
const Model& model() const { return m_model; } const Model& model() const { return m_model; }
struct TaskParams { struct TaskParams {
@ -316,7 +316,7 @@ public:
virtual bool finished() const = 0; virtual bool finished() const = 0;
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; } const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; } const DynamicPrintConfig& full_print_config() const { return m_full_print_config; }
virtual std::string output_filename(const std::string &filename_base = std::string()) const = 0; virtual std::string output_filename(const std::string &filename_base = std::string()) const = 0;
// If the filename_base is set, it is used as the input for the template processing. In that case the path is expected to be the directory (may be empty). // If the filename_base is set, it is used as the input for the template processing. In that case the path is expected to be the directory (may be empty).
@ -341,6 +341,8 @@ protected:
void update_object_placeholders(DynamicConfig &config, const std::string &default_ext) const; void update_object_placeholders(DynamicConfig &config, const std::string &default_ext) const;
Model m_model; Model m_model;
DynamicPrintConfig m_full_print_config;
PlaceholderParser m_placeholder_parser;
private: private:
tbb::atomic<CancelStatus> m_cancel_status; tbb::atomic<CancelStatus> m_cancel_status;
@ -354,8 +356,6 @@ private:
// The mutex will be used to guard the worker thread against entering a stage // The mutex will be used to guard the worker thread against entering a stage
// while the data influencing the stage is modified. // while the data influencing the stage is modified.
mutable tbb::mutex m_state_mutex; mutable tbb::mutex m_state_mutex;
PlaceholderParser m_placeholder_parser;
}; };
template<typename PrintStepEnum, const size_t COUNT> template<typename PrintStepEnum, const size_t COUNT>

View file

@ -29,6 +29,7 @@ PrintConfigDef::PrintConfigDef()
this->init_common_params(); this->init_common_params();
assign_printer_technology_to_unknown(this->options, ptAny); assign_printer_technology_to_unknown(this->options, ptAny);
this->init_fff_params(); this->init_fff_params();
this->init_extruder_retract_keys();
assign_printer_technology_to_unknown(this->options, ptFFF); assign_printer_technology_to_unknown(this->options, ptFFF);
this->init_sla_params(); this->init_sla_params();
assign_printer_technology_to_unknown(this->options, ptSLA); assign_printer_technology_to_unknown(this->options, ptSLA);
@ -2238,6 +2239,48 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm"); def->sidetext = L("mm");
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0)); def->set_default_value(new ConfigOptionFloat(0));
// Declare retract values for filament profile, overriding the printer's extruder profile.
for (const char *opt_key : {
// floats
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed", "retract_restart_extra", "retract_before_travel",
// bools
"retract_layer_change", "wipe",
// percents
"retract_before_wipe"}) {
auto it_opt = options.find(opt_key);
assert(it_opt != options.end());
def = this->add_nullable(std::string("filament_") + opt_key, it_opt->second.type);
def->label = it_opt->second.label;
def->full_label = it_opt->second.full_label;
def->tooltip = it_opt->second.tooltip;
def->sidetext = it_opt->second.sidetext;
def->mode = it_opt->second.mode;
switch (def->type) {
case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast<const ConfigOptionFloats* >(it_opt->second.default_value.get())->values)); break;
case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast<const ConfigOptionPercents*>(it_opt->second.default_value.get())->values)); break;
case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast<const ConfigOptionBools* >(it_opt->second.default_value.get())->values)); break;
default: assert(false);
}
}
}
void PrintConfigDef::init_extruder_retract_keys()
{
m_extruder_retract_keys = {
"deretract_speed",
"retract_before_travel",
"retract_before_wipe",
"retract_layer_change",
"retract_length",
"retract_lift",
"retract_lift_above",
"retract_lift_below",
"retract_restart_extra",
"retract_speed",
"wipe"
};
assert(std::is_sorted(m_extruder_retract_keys.begin(), m_extruder_retract_keys.end()));
} }
void PrintConfigDef::init_sla_params() void PrintConfigDef::init_sla_params()
@ -2997,7 +3040,7 @@ std::string FullPrintConfig::validate()
} }
case coFloats: case coFloats:
case coPercents: case coPercents:
for (double v : static_cast<const ConfigOptionFloats*>(opt)->values) for (double v : static_cast<const ConfigOptionVector<double>*>(opt)->values)
if (v < optdef->min || v > optdef->max) { if (v < optdef->min || v > optdef->max) {
out_of_range = true; out_of_range = true;
break; break;
@ -3010,7 +3053,7 @@ std::string FullPrintConfig::validate()
break; break;
} }
case coInts: case coInts:
for (int v : static_cast<const ConfigOptionInts*>(opt)->values) for (int v : static_cast<const ConfigOptionVector<int>*>(opt)->values)
if (v < optdef->min || v > optdef->max) { if (v < optdef->min || v > optdef->max) {
out_of_range = true; out_of_range = true;
break; break;

View file

@ -185,10 +185,18 @@ public:
static void handle_legacy(t_config_option_key &opt_key, std::string &value); static void handle_legacy(t_config_option_key &opt_key, std::string &value);
// Options defining the extruder retract properties. These keys are sorted lexicographically.
// The extruder retract keys could be overidden by the same values defined at the Filament level
// (then the key is further prefixed with the "filament_" prefix).
const std::vector<std::string>& extruder_retract_keys() const { return m_extruder_retract_keys; }
private: private:
void init_common_params(); void init_common_params();
void init_fff_params(); void init_fff_params();
void init_extruder_retract_keys();
void init_sla_params(); void init_sla_params();
std::vector<std::string> m_extruder_retract_keys;
}; };
// The one and only global definition of SLic3r configuration options. // The one and only global definition of SLic3r configuration options.

View file

@ -145,14 +145,13 @@ static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &mo
return instances; return instances;
} }
SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConfig &config_in) SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig config)
{ {
#ifdef _DEBUG #ifdef _DEBUG
check_model_ids_validity(model); check_model_ids_validity(model);
#endif /* _DEBUG */ #endif /* _DEBUG */
// Make a copy of the config, normalize it. // Normalize the config.
DynamicPrintConfig config(config_in);
config.option("sla_print_settings_id", true); config.option("sla_print_settings_id", true);
config.option("sla_material_settings_id", true); config.option("sla_material_settings_id", true);
config.option("printer_settings_id", true); config.option("printer_settings_id", true);
@ -162,7 +161,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
t_config_option_keys printer_diff = m_printer_config.diff(config); t_config_option_keys printer_diff = m_printer_config.diff(config);
t_config_option_keys material_diff = m_material_config.diff(config); t_config_option_keys material_diff = m_material_config.diff(config);
t_config_option_keys object_diff = m_default_object_config.diff(config); t_config_option_keys object_diff = m_default_object_config.diff(config);
t_config_option_keys placeholder_parser_diff = this->placeholder_parser().config_diff(config); t_config_option_keys placeholder_parser_diff = m_placeholder_parser.config_diff(config);
// Do not use the ApplyStatus as we will use the max function when updating apply_status. // Do not use the ApplyStatus as we will use the max function when updating apply_status.
unsigned int apply_status = APPLY_STATUS_UNCHANGED; unsigned int apply_status = APPLY_STATUS_UNCHANGED;
@ -187,12 +186,11 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
// only to generate the output file name. // only to generate the output file name.
if (! placeholder_parser_diff.empty()) { if (! placeholder_parser_diff.empty()) {
// update_apply_status(this->invalidate_step(slapsRasterize)); // update_apply_status(this->invalidate_step(slapsRasterize));
PlaceholderParser &pp = this->placeholder_parser(); m_placeholder_parser.apply_config(config);
pp.apply_config(config);
// Set the profile aliases for the PrintBase::output_filename() // Set the profile aliases for the PrintBase::output_filename()
pp.set("print_preset", config.option("sla_print_settings_id")->clone()); m_placeholder_parser.set("print_preset", config.option("sla_print_settings_id")->clone());
pp.set("material_preset", config.option("sla_material_settings_id")->clone()); m_placeholder_parser.set("material_preset", config.option("sla_material_settings_id")->clone());
pp.set("printer_preset", config.option("printer_settings_id")->clone()); m_placeholder_parser.set("printer_preset", config.option("printer_settings_id")->clone());
} }
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call. // It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
@ -459,6 +457,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
check_model_ids_equal(m_model, model); check_model_ids_equal(m_model, model);
#endif /* _DEBUG */ #endif /* _DEBUG */
m_full_print_config = std::move(config);
return static_cast<ApplyStatus>(apply_status); return static_cast<ApplyStatus>(apply_status);
} }

View file

@ -349,7 +349,7 @@ public:
void clear() override; void clear() override;
bool empty() const override { return m_objects.empty(); } bool empty() const override { return m_objects.empty(); }
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
void set_task(const TaskParams &params) override; void set_task(const TaskParams &params) override;
void process() override; void process() override;
void finalize() override; void finalize() override;

View file

@ -106,6 +106,9 @@ void CopyrightsDialog::fill_entries()
"2001-2016 Expat maintainers" , "http://www.libexpat.org/" }, "2001-2016 Expat maintainers" , "http://www.libexpat.org/" },
{ "AVRDUDE" , "2018 Free Software Foundation, Inc." , "http://savannah.nongnu.org/projects/avrdude" }, { "AVRDUDE" , "2018 Free Software Foundation, Inc." , "http://savannah.nongnu.org/projects/avrdude" },
{ "Shinyprofiler" , "2007-2010 Aidin Abedi" , "http://code.google.com/p/shinyprofiler/" }, { "Shinyprofiler" , "2007-2010 Aidin Abedi" , "http://code.google.com/p/shinyprofiler/" },
{ "Real-Time DXT1/DXT5 C compression library"
, "Based on original by fabian \"ryg\" giesen v1.04. "
"Custom version, modified by Yann Collet" , "https://github.com/Cyan4973/RygsDXTc" },
{ "Icons for STL and GCODE files." { "Icons for STL and GCODE files."
, "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" } , "Akira Yasuda" , "http://3dp0.com/icons-for-stl-and-gcode/" }
}; };

View file

@ -136,6 +136,8 @@ bool Field::is_matched(const std::string& string, const std::string& pattern)
return std::regex_match(string, regex_pattern); return std::regex_match(string, regex_pattern);
} }
static wxString na_value() { return _(L("N/A")); }
void Field::get_value_by_opt_type(wxString& str) void Field::get_value_by_opt_type(wxString& str)
{ {
switch (m_opt.type) { switch (m_opt.type) {
@ -165,7 +167,9 @@ void Field::get_value_by_opt_type(wxString& str)
val = 0.0; val = 0.0;
else else
{ {
if (!str.ToCDouble(&val)) if (m_opt.nullable && str == na_value())
val = ConfigOptionFloatsNullable::nil_value();
else if (!str.ToCDouble(&val))
{ {
show_error(m_parent, _(L("Invalid numeric input."))); show_error(m_parent, _(L("Invalid numeric input.")));
set_value(double_to_string(val), true); set_value(double_to_string(val), true);
@ -256,6 +260,7 @@ void TextCtrl::BUILD() {
m_opt.default_value->getFloat() : m_opt.default_value->getFloat() :
m_opt.get_default_value<ConfigOptionPercents>()->get_at(m_opt_idx); m_opt.get_default_value<ConfigOptionPercents>()->get_at(m_opt_idx);
text_value = double_to_string(val); text_value = double_to_string(val);
m_last_meaningful_value = text_value;
break; break;
} }
case coString: case coString:
@ -325,24 +330,7 @@ void TextCtrl::BUILD() {
} }
propagate_value(); propagate_value();
}), temp->GetId()); }), temp->GetId());
/*
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt)
{
#ifdef __WXGTK__
if (bChangedValueEvent)
#endif //__WXGTK__
if(is_defined_input_value())
on_change_field();
}), temp->GetId());
#ifdef __WXGTK__
// to correct value updating on GTK we should:
// call on_change_field() on wxEVT_KEY_UP instead of wxEVT_TEXT
// and prevent value updating on wxEVT_KEY_DOWN
temp->Bind(wxEVT_KEY_DOWN, &TextCtrl::change_field_value, this);
temp->Bind(wxEVT_KEY_UP, &TextCtrl::change_field_value, this);
#endif //__WXGTK__
*/
// select all text using Ctrl+A // select all text using Ctrl+A
temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
{ {
@ -355,14 +343,70 @@ void TextCtrl::BUILD() {
window = dynamic_cast<wxWindow*>(temp); window = dynamic_cast<wxWindow*>(temp);
} }
bool TextCtrl::value_was_changed()
{
if (m_value.empty())
return true;
boost::any val = m_value;
wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
// update m_value!
get_value_by_opt_type(ret_str);
switch (m_opt.type) {
case coInt:
return boost::any_cast<int>(m_value) != boost::any_cast<int>(val);
case coPercent:
case coPercents:
case coFloats:
case coFloat: {
if (m_opt.nullable && std::isnan(boost::any_cast<double>(m_value)) &&
std::isnan(boost::any_cast<double>(val)))
return false;
return boost::any_cast<double>(m_value) != boost::any_cast<double>(val);
}
case coString:
case coStrings:
case coFloatOrPercent:
return boost::any_cast<std::string>(m_value) != boost::any_cast<std::string>(val);
default:
return true;
}
}
void TextCtrl::propagate_value() void TextCtrl::propagate_value()
{ {
if (is_defined_input_value<wxTextCtrl>(window, m_opt.type)) if (is_defined_input_value<wxTextCtrl>(window, m_opt.type) && value_was_changed())
on_change_field(); on_change_field();
else else
on_kill_focus(); on_kill_focus();
} }
void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) {
m_disable_change_event = !change_event;
if (m_opt.nullable) {
const bool m_is_na_val = boost::any_cast<wxString>(value) == na_value();
if (!m_is_na_val)
m_last_meaningful_value = value;
dynamic_cast<wxTextCtrl*>(window)->SetValue(m_is_na_val ? na_value() : boost::any_cast<wxString>(value));
}
else
dynamic_cast<wxTextCtrl*>(window)->SetValue(boost::any_cast<wxString>(value));
m_disable_change_event = false;
}
void TextCtrl::set_last_meaningful_value()
{
dynamic_cast<wxTextCtrl*>(window)->SetValue(boost::any_cast<wxString>(m_last_meaningful_value));
propagate_value();
}
void TextCtrl::set_na_value()
{
dynamic_cast<wxTextCtrl*>(window)->SetValue(na_value());
propagate_value();
}
boost::any& TextCtrl::get_value() boost::any& TextCtrl::get_value()
{ {
wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue(); wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
@ -409,6 +453,8 @@ void CheckBox::BUILD() {
m_opt.get_default_value<ConfigOptionBools>()->get_at(m_opt_idx) : m_opt.get_default_value<ConfigOptionBools>()->get_at(m_opt_idx) :
false; false;
m_last_meaningful_value = static_cast<unsigned char>(check_value);
// Set Label as a string of at least one space simbol to correct system scaling of a CheckBox // Set Label as a string of at least one space simbol to correct system scaling of a CheckBox
auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size); auto temp = new wxCheckBox(m_parent, wxID_ANY, wxString(" "), wxDefaultPosition, size);
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
@ -416,7 +462,10 @@ void CheckBox::BUILD() {
temp->SetValue(check_value); temp->SetValue(check_value);
if (m_opt.readonly) temp->Disable(); if (m_opt.readonly) temp->Disable();
temp->Bind(wxEVT_CHECKBOX, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); temp->Bind(wxEVT_CHECKBOX, ([this](wxCommandEvent e) {
m_is_na_val = false;
on_change_field();
}), temp->GetId());
temp->SetToolTip(get_tooltip_text(check_value ? "true" : "false")); temp->SetToolTip(get_tooltip_text(check_value ? "true" : "false"));
@ -424,6 +473,38 @@ void CheckBox::BUILD() {
window = dynamic_cast<wxWindow*>(temp); window = dynamic_cast<wxWindow*>(temp);
} }
void CheckBox::set_value(const boost::any& value, bool change_event)
{
m_disable_change_event = !change_event;
if (m_opt.nullable) {
m_is_na_val = boost::any_cast<unsigned char>(value) == ConfigOptionBoolsNullable::nil_value();
if (!m_is_na_val)
m_last_meaningful_value = value;
dynamic_cast<wxCheckBox*>(window)->SetValue(m_is_na_val ? false : boost::any_cast<unsigned char>(value) != 0);
}
else
dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<bool>(value));
m_disable_change_event = false;
}
void CheckBox::set_last_meaningful_value()
{
if (m_opt.nullable) {
m_is_na_val = false;
dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<unsigned char>(m_last_meaningful_value) != 0);
on_change_field();
}
}
void CheckBox::set_na_value()
{
if (m_opt.nullable) {
m_is_na_val = true;
dynamic_cast<wxCheckBox*>(window)->SetValue(false);
on_change_field();
}
}
boost::any& CheckBox::get_value() boost::any& CheckBox::get_value()
{ {
// boost::any m_value; // boost::any m_value;
@ -431,7 +512,7 @@ boost::any& CheckBox::get_value()
if (m_opt.type == coBool) if (m_opt.type == coBool)
m_value = static_cast<bool>(value); m_value = static_cast<bool>(value);
else else
m_value = static_cast<unsigned char>(value); m_value = m_is_na_val ? ConfigOptionBoolsNullable::nil_value() : static_cast<unsigned char>(value);
return m_value; return m_value;
} }

View file

@ -123,6 +123,8 @@ public:
/// subclasses should overload with a specific version /// subclasses should overload with a specific version
/// Postcondition: Method does not fire the on_change event. /// Postcondition: Method does not fire the on_change event.
virtual void set_value(const boost::any& value, bool change_event) = 0; virtual void set_value(const boost::any& value, bool change_event) = 0;
virtual void set_last_meaningful_value() {}
virtual void set_na_value() {}
/// Gets a boost::any representing this control. /// Gets a boost::any representing this control.
/// subclasses should overload with a specific version /// subclasses should overload with a specific version
@ -247,6 +249,8 @@ protected:
// current value // current value
boost::any m_value; boost::any m_value;
// last maeningful value
boost::any m_last_meaningful_value;
int m_em_unit; int m_em_unit;
@ -277,6 +281,7 @@ public:
~TextCtrl() {} ~TextCtrl() {}
void BUILD(); void BUILD();
bool value_was_changed();
// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER
void propagate_value(); void propagate_value();
wxWindow* window {nullptr}; wxWindow* window {nullptr};
@ -286,11 +291,9 @@ public:
dynamic_cast<wxTextCtrl*>(window)->SetValue(wxString(value)); dynamic_cast<wxTextCtrl*>(window)->SetValue(wxString(value));
m_disable_change_event = false; m_disable_change_event = false;
} }
virtual void set_value(const boost::any& value, bool change_event = false) { virtual void set_value(const boost::any& value, bool change_event = false) override;
m_disable_change_event = !change_event; virtual void set_last_meaningful_value() override;
dynamic_cast<wxTextCtrl*>(window)->SetValue(boost::any_cast<wxString>(value)); virtual void set_na_value() override;
m_disable_change_event = false;
}
boost::any& get_value() override; boost::any& get_value() override;
@ -303,6 +306,7 @@ public:
class CheckBox : public Field { class CheckBox : public Field {
using Field::Field; using Field::Field;
bool m_is_na_val {false};
public: public:
CheckBox(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} CheckBox(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
@ -316,11 +320,9 @@ public:
dynamic_cast<wxCheckBox*>(window)->SetValue(value); dynamic_cast<wxCheckBox*>(window)->SetValue(value);
m_disable_change_event = false; m_disable_change_event = false;
} }
void set_value(const boost::any& value, bool change_event = false) { void set_value(const boost::any& value, bool change_event = false) override;
m_disable_change_event = !change_event; void set_last_meaningful_value() override;
dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<bool>(value)); void set_na_value() override;
m_disable_change_event = false;
}
boost::any& get_value() override; boost::any& get_value() override;
void msw_rescale() override; void msw_rescale() override;

View file

@ -27,10 +27,13 @@ namespace GUI {
void GLTexture::Compressor::reset() void GLTexture::Compressor::reset()
{ {
// force compression completion, if any if (m_is_compressing)
m_abort_compressing = true; {
// wait for compression completion, if any // force compression completion, if any
while (m_is_compressing) {} m_abort_compressing = true;
// wait for compression completion, if any
while (m_is_compressing) {}
}
m_levels.clear(); m_levels.clear();
} }
@ -42,8 +45,6 @@ void GLTexture::Compressor::add_level(unsigned int w, unsigned int h, const std:
void GLTexture::Compressor::start_compressing() void GLTexture::Compressor::start_compressing()
{ {
m_is_compressing = true;
m_abort_compressing = false;
std::thread t(&GLTexture::Compressor::compress, this); std::thread t(&GLTexture::Compressor::compress, this);
t.detach(); t.detach();
} }
@ -97,6 +98,9 @@ void GLTexture::Compressor::compress()
{ {
// reference: https://github.com/Cyan4973/RygsDXTc // reference: https://github.com/Cyan4973/RygsDXTc
m_is_compressing = true;
m_abort_compressing = false;
for (Level& level : m_levels) for (Level& level : m_levels)
{ {
if (m_abort_compressing) if (m_abort_compressing)

View file

@ -32,6 +32,7 @@ namespace GUI {
public: public:
explicit Compressor(GLTexture& texture) : m_texture(texture), m_is_compressing(false), m_abort_compressing(false) {} explicit Compressor(GLTexture& texture) : m_texture(texture), m_is_compressing(false), m_abort_compressing(false) {}
~Compressor() { reset(); }
void reset(); void reset();

View file

@ -148,6 +148,13 @@ void config_wizard(int reason)
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/)
{ {
try{ try{
if (config.def()->get(opt_key)->type == coBools && config.def()->get(opt_key)->nullable) {
ConfigOptionBoolsNullable* vec_new = new ConfigOptionBoolsNullable{ boost::any_cast<unsigned char>(value) };
config.option<ConfigOptionBoolsNullable>(opt_key)->set_at(vec_new, opt_index, 0);
return;
}
switch (config.def()->get(opt_key)->type) { switch (config.def()->get(opt_key)->type) {
case coFloatOrPercent:{ case coFloatOrPercent:{
std::string str = boost::any_cast<std::string>(value); std::string str = boost::any_cast<std::string>(value);

View file

@ -2843,7 +2843,7 @@ void ObjectList::update_selections_on_canvas()
else else
{ {
mode = Selection::Instance; mode = Selection::Instance;
single_selection = false; single_selection &= (obj_idx != selection.get_object_idx());
std::vector<unsigned int> idxs = selection.get_volume_idxs_from_object(obj_idx); std::vector<unsigned int> idxs = selection.get_volume_idxs_from_object(obj_idx);
volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end());
} }

View file

@ -210,6 +210,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width); wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width);
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
btn->SetToolTip(wxString::Format(_(L("Toggle %c axis mirroring")), (int)label)); btn->SetToolTip(wxString::Format(_(L("Toggle %c axis mirroring")), (int)label));
btn->SetBitmapDisabled_(m_mirror_bitmap_hidden);
m_mirror_buttons[axis_idx].first = btn; m_mirror_buttons[axis_idx].first = btn;
m_mirror_buttons[axis_idx].second = mbShown; m_mirror_buttons[axis_idx].second = mbShown;
@ -286,6 +287,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
auto sizer = new wxBoxSizer(wxHORIZONTAL); auto sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(btn, wxBU_EXACTFIT); sizer->Add(btn, wxBU_EXACTFIT);
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Reset scale")));
change_scale_value(0, 100.); change_scale_value(0, 100.);
change_scale_value(1, 100.); change_scale_value(1, 100.);
change_scale_value(2, 100.); change_scale_value(2, 100.);
@ -323,7 +325,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
selection.synchronize_unselected_volumes(); selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing. // Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_rotate(L("Set Rotation")); canvas->do_rotate(L("Reset Rotation"));
UpdateAndShow(true); UpdateAndShow(true);
}); });
@ -350,6 +352,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation(); const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume)); Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume));
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Drop to bed")));
change_position_value(0, diff.x()); change_position_value(0, diff.x());
change_position_value(1, diff.y()); change_position_value(1, diff.y());
change_position_value(2, diff.z()); change_position_value(2, diff.z());
@ -646,13 +649,13 @@ void ObjectManipulation::update_mirror_buttons_visibility()
wxGetApp().CallAfter([this, new_states]{ wxGetApp().CallAfter([this, new_states]{
for (int i=0; i<3; ++i) { for (int i=0; i<3; ++i) {
if (new_states[i] != m_mirror_buttons[i].second) { if (new_states[i] != m_mirror_buttons[i].second) {
const wxBitmap* bmp; const ScalableBitmap* bmp;
switch (new_states[i]) { switch (new_states[i]) {
case mbHidden : bmp = &m_mirror_bitmap_hidden.bmp(); m_mirror_buttons[i].first->Enable(false); break; case mbHidden : bmp = &m_mirror_bitmap_hidden; m_mirror_buttons[i].first->Enable(false); break;
case mbShown : bmp = &m_mirror_bitmap_off.bmp(); m_mirror_buttons[i].first->Enable(true); break; case mbShown : bmp = &m_mirror_bitmap_off; m_mirror_buttons[i].first->Enable(true); break;
case mbActive : bmp = &m_mirror_bitmap_on.bmp(); m_mirror_buttons[i].first->Enable(true); break; case mbActive : bmp = &m_mirror_bitmap_on; m_mirror_buttons[i].first->Enable(true); break;
} }
m_mirror_buttons[i].first->SetBitmap(*bmp); m_mirror_buttons[i].first->SetBitmap_(*bmp);
m_mirror_buttons[i].second = new_states[i]; m_mirror_buttons[i].second = new_states[i];
} }
} }
@ -925,6 +928,9 @@ void ObjectManipulation::msw_rescale()
m_reset_rotation_button->msw_rescale(); m_reset_rotation_button->msw_rescale();
m_drop_to_bed_button->msw_rescale(); m_drop_to_bed_button->msw_rescale();
for (int id = 0; id < 3; ++id)
m_mirror_buttons[id].first->msw_rescale();
get_og()->msw_rescale(); get_og()->msw_rescale();
} }

View file

@ -900,6 +900,10 @@ RENDER_AGAIN:
ImGui::SameLine(diameter_slider_left); ImGui::SameLine(diameter_slider_left);
ImGui::PushItemWidth(window_width - diameter_slider_left); ImGui::PushItemWidth(window_width - diameter_slider_left);
// Following is a nasty way to:
// - save the initial value of the slider before one starts messing with it
// - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene
// - take correct undo/redo snapshot after the user is done with moving the slider
float initial_value = m_new_point_head_diameter; float initial_value = m_new_point_head_diameter;
ImGui::SliderFloat("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); ImGui::SliderFloat("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
@ -960,20 +964,35 @@ RENDER_AGAIN:
float density = static_cast<const ConfigOptionInt*>(opts[0])->value; float density = static_cast<const ConfigOptionInt*>(opts[0])->value;
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value; float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
bool value_changed = ImGui::SliderFloat("", &minimal_point_distance, 0.f, 20.f, "%.f mm"); ImGui::SliderFloat("", &minimal_point_distance, 0.f, 20.f, "%.f mm");
if (value_changed) bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance; bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
m_imgui->text(m_desc.at("points_density")); m_imgui->text(m_desc.at("points_density"));
ImGui::SameLine(settings_sliders_left); ImGui::SameLine(settings_sliders_left);
if (ImGui::SliderFloat(" ", &density, 0.f, 200.f, "%.f %%")) { ImGui::SliderFloat(" ", &density, 0.f, 200.f, "%.f %%");
value_changed = true; slider_clicked |= ImGui::IsItemClicked();
slider_edited |= ImGui::IsItemEdited();
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
m_minimal_point_distance_stash = minimal_point_distance;
m_density_stash = density;
}
if (slider_edited) {
m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density; m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
} }
if (slider_released) {
if (value_changed) // Update side panel m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash;
m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)m_density_stash;
wxGetApp().plater()->take_snapshot(_(L("Support parameter change")));
m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
wxGetApp().obj_list()->update_and_show_object_settings_item(); wxGetApp().obj_list()->update_and_show_object_settings_item();
}
bool generate = m_imgui->button(m_desc.at("auto_generate")); bool generate = m_imgui->button(m_desc.at("auto_generate"));

View file

@ -107,7 +107,8 @@ private:
float m_new_point_head_diameter; // Size of a new point. float m_new_point_head_diameter; // Size of a new point.
CacheEntry m_point_before_drag; // undo/redo - so we know what state was edited CacheEntry m_point_before_drag; // undo/redo - so we know what state was edited
float m_old_point_head_diameter = 0.; // the same float m_old_point_head_diameter = 0.; // the same
float m_minimal_point_distance = 20.f; float m_minimal_point_distance_stash = 0.f; // and again
float m_density_stash = 0.f; // and again
mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo

View file

@ -108,11 +108,15 @@ public:
ar(m_current); ar(m_current);
GLGizmoBase* curr = get_current(); GLGizmoBase* curr = get_current();
if (curr != nullptr) for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) {
{ GLGizmoBase* gizmo = it->second;
curr->set_state(GLGizmoBase::On); if (gizmo != nullptr) {
curr->load(ar); gizmo->set_hover_id(-1);
} gizmo->set_state((it->second == curr) ? GLGizmoBase::On : GLGizmoBase::Off);
if (gizmo == curr)
gizmo->load(ar);
}
}
} }
template<class Archive> template<class Archive>

View file

@ -411,6 +411,7 @@ void MainFrame::init_menubar()
}, wxID_FILE1, wxID_FILE9); }, wxID_FILE1, wxID_FILE9);
std::vector<std::string> recent_projects = wxGetApp().app_config->get_recent_projects(); std::vector<std::string> recent_projects = wxGetApp().app_config->get_recent_projects();
std::reverse(recent_projects.begin(), recent_projects.end());
for (const std::string& project : recent_projects) for (const std::string& project : recent_projects)
{ {
m_recent_projects.AddFileToHistory(from_u8(project)); m_recent_projects.AddFileToHistory(from_u8(project));

View file

@ -202,7 +202,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
// so we need a horizontal sizer to arrange these things // so we need a horizontal sizer to arrange these things
auto sizer = new wxBoxSizer(wxHORIZONTAL); auto sizer = new wxBoxSizer(wxHORIZONTAL);
grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT, 7); sizer->Add(m_near_label_widget_ptrs.back(), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7);
sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5);
} }
} }
@ -372,30 +372,10 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b
auto option = m_options.at(opt_id).opt; auto option = m_options.at(opt_id).opt;
// get value change_opt_value(*m_config, opt_key, value, opt_index == -1 ? 0 : opt_index);
//! auto field_value = get_value(opt_id);
if (option.gui_flags.compare("serialized")==0) {
if (opt_index != -1) {
// die "Can't set serialized option indexed value" ;
}
change_opt_value(*m_config, opt_key, value);
}
else {
if (opt_index == -1) {
// change_opt_value(*m_config, opt_key, field_value);
//!? why field_value?? in this case changed value will be lose! No?
change_opt_value(*m_config, opt_key, value);
}
else {
change_opt_value(*m_config, opt_key, value, opt_index);
// auto value = m_config->get($opt_key);
// $value->[$opt_index] = $field_value;
// $self->config->set($opt_key, $value);
}
}
} }
OptionsGroup::on_change_OG(opt_id, value); //!? Why doing this OptionsGroup::on_change_OG(opt_id, value);
} }
void ConfigOptionsGroup::back_to_initial_value(const std::string& opt_key) void ConfigOptionsGroup::back_to_initial_value(const std::string& opt_key)
@ -578,6 +558,34 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
boost::any ret; boost::any ret;
wxString text_value = wxString(""); wxString text_value = wxString("");
const ConfigOptionDef* opt = config.def()->get(opt_key); const ConfigOptionDef* opt = config.def()->get(opt_key);
if (opt->nullable)
{
switch (opt->type)
{
case coPercents:
case coFloats: {
if (config.option(opt_key)->is_nil())
ret = _(L("N/A"));
else {
double val = opt->type == coFloats ?
config.option<ConfigOptionFloatsNullable>(opt_key)->get_at(idx) :
config.option<ConfigOptionPercentsNullable>(opt_key)->get_at(idx);
ret = double_to_string(val); }
}
break;
case coBools:
ret = config.option<ConfigOptionBoolsNullable>(opt_key)->values[idx];
break;
case coInts:
ret = config.option<ConfigOptionIntsNullable>(opt_key)->get_at(idx);
break;
default:
break;
}
return ret;
}
switch (opt->type) { switch (opt->type) {
case coFloatOrPercent:{ case coFloatOrPercent:{
const auto &value = *config.option<ConfigOptionFloatOrPercent>(opt_key); const auto &value = *config.option<ConfigOptionFloatOrPercent>(opt_key);

View file

@ -252,6 +252,9 @@ public:
Option option = get_option(title, idx); Option option = get_option(title, idx);
return OptionsGroup::create_single_option_line(option); return OptionsGroup::create_single_option_line(option);
} }
Line create_single_option_line(const Option& option) const {
return OptionsGroup::create_single_option_line(option);
}
void append_single_option_line(const Option& option) { void append_single_option_line(const Option& option) {
OptionsGroup::append_single_option_line(option); OptionsGroup::append_single_option_line(option);
} }

View file

@ -4406,6 +4406,12 @@ void Plater::reslice()
{ {
// Stop arrange and (or) optimize rotation tasks. // Stop arrange and (or) optimize rotation tasks.
this->stop_jobs(); this->stop_jobs();
if (printer_technology() == ptSLA) {
for (auto& object : model().objects)
if (object->sla_points_status == sla::PointsStatus::NoPoints)
object->sla_points_status = sla::PointsStatus::Generating;
}
//FIXME Don't reslice if export of G-code or sending to OctoPrint is running. //FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
// bitmask of UpdateBackgroundProcessReturnState // bitmask of UpdateBackgroundProcessReturnState

View file

@ -400,6 +400,10 @@ const std::vector<std::string>& Preset::filament_options()
"temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed",
"max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
"start_filament_gcode", "end_filament_gcode", "start_filament_gcode", "end_filament_gcode",
// Retract overrides
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
// Profile compatibility
"compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits" "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
}; };
return s_opts; return s_opts;

View file

@ -72,6 +72,8 @@ PresetBundle::PresetBundle() :
this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values = { "" }; this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values = { "" };
this->filaments.default_preset().compatible_printers_condition(); this->filaments.default_preset().compatible_printers_condition();
this->filaments.default_preset().inherits(); this->filaments.default_preset().inherits();
// Set all the nullable values to nils.
this->filaments.default_preset().config.null_nullables();
this->sla_materials.default_preset().config.optptr("sla_material_settings_id", true); this->sla_materials.default_preset().config.optptr("sla_material_settings_id", true);
this->sla_materials.default_preset().compatible_printers_condition(); this->sla_materials.default_preset().compatible_printers_condition();

View file

@ -1497,6 +1497,105 @@ void TabPrint::OnActivate()
Tab::OnActivate(); Tab::OnActivate();
} }
void TabFilament::add_filament_overrides_page()
{
PageShp page = add_options_page(_(L("Filament Overrides")), "wrench");
ConfigOptionsGroupShp optgroup = page->new_optgroup(_(L("Retraction")));
auto append_single_option_line = [optgroup, this](const std::string& opt_key, int opt_index)
{
Line line {"",""};
if (opt_key == "filament_retract_lift_above" || opt_key == "filament_retract_lift_below") {
Option opt = optgroup->get_option(opt_key);
opt.opt.label = opt.opt.full_label;
line = optgroup->create_single_option_line(opt);
}
else
line = optgroup->create_single_option_line(optgroup->get_option(opt_key));
line.near_label_widget = [this, optgroup, opt_key, opt_index](wxWindow* parent) {
wxCheckBox* check_box = new wxCheckBox(parent, wxID_ANY, "");
check_box->Bind(wxEVT_CHECKBOX, [this, optgroup, opt_key, opt_index](wxCommandEvent& evt) {
const bool is_checked = evt.IsChecked();
Field* field = optgroup->get_fieldc(opt_key, opt_index);
if (field != nullptr) {
field->toggle(is_checked);
if (is_checked)
field->set_last_meaningful_value();
else
field->set_na_value();
}
}, check_box->GetId());
m_overrides_options[opt_key] = check_box;
return check_box;
};
optgroup->append_line(line);
};
const int extruder_idx = 0; // #ys_FIXME
for (const std::string opt_key : { "filament_retract_length",
"filament_retract_lift",
"filament_retract_lift_above",
"filament_retract_lift_below",
"filament_retract_speed",
"filament_deretract_speed",
"filament_retract_restart_extra",
"filament_retract_before_travel",
"filament_retract_layer_change",
"filament_wipe",
"filament_retract_before_wipe"
})
append_single_option_line(opt_key, extruder_idx);
}
void TabFilament::update_filament_overrides_page()
{
const auto page_it = std::find_if(m_pages.begin(), m_pages.end(), [](const PageShp page) {return page->title() == _(L("Filament Overrides")); });
if (page_it == m_pages.end())
return;
PageShp page = *page_it;
const auto og_it = std::find_if(page->m_optgroups.begin(), page->m_optgroups.end(), [](const ConfigOptionsGroupShp og) {return og->title == _(L("Retraction")); });
if (og_it == page->m_optgroups.end())
return;
ConfigOptionsGroupShp optgroup = *og_it;
std::vector<std::string> opt_keys = { "filament_retract_length",
"filament_retract_lift",
"filament_retract_lift_above",
"filament_retract_lift_below",
"filament_retract_speed",
"filament_deretract_speed",
"filament_retract_restart_extra",
"filament_retract_before_travel",
"filament_retract_layer_change",
"filament_wipe",
"filament_retract_before_wipe"
};
const int extruder_idx = 0; // #ys_FIXME
const bool have_retract_length = m_config->option("filament_retract_length")->is_nil() ||
m_config->opt_float("filament_retract_length", extruder_idx) > 0;
for (const std::string& opt_key : opt_keys)
{
bool is_checked = opt_key=="filament_retract_length" ? true : have_retract_length;
m_overrides_options[opt_key]->Enable(is_checked);
is_checked &= !m_config->option(opt_key)->is_nil();
m_overrides_options[opt_key]->SetValue(is_checked);
Field* field = optgroup->get_fieldc(opt_key, extruder_idx);
if (field != nullptr)
field->toggle(is_checked);
}
}
void TabFilament::build() void TabFilament::build()
{ {
m_presets = &m_preset_bundle->filaments; m_presets = &m_preset_bundle->filaments;
@ -1594,10 +1693,14 @@ void TabFilament::build()
}; };
optgroup->append_line(line); optgroup->append_line(line);
add_filament_overrides_page();
const int gcode_field_height = 15; // 150 const int gcode_field_height = 15; // 150
const int notes_field_height = 25; // 250 const int notes_field_height = 25; // 250
page = add_options_page(_(L("Custom G-code")), "cog"); page = add_options_page(_(L("Custom G-code")), "cog");
optgroup = page->new_optgroup(_(L("Start G-code")), 0); optgroup = page->new_optgroup(_(L("Start G-code")), 0);
Option option = optgroup->get_option("start_filament_gcode"); Option option = optgroup->get_option("start_filament_gcode");
option.opt.full_width = true; option.opt.full_width = true;
@ -1661,7 +1764,7 @@ void TabFilament::update()
return; // ys_FIXME return; // ys_FIXME
m_update_cnt++; m_update_cnt++;
// Freeze();
wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset())); wxString text = from_u8(PresetHints::cooling_description(m_presets->get_edited_preset()));
m_cooling_description_line->SetText(text); m_cooling_description_line->SetText(text);
text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle)); text = from_u8(PresetHints::maximum_volumetric_flow_description(*m_preset_bundle));
@ -1676,7 +1779,9 @@ void TabFilament::update()
for (auto el : { "min_fan_speed", "disable_fan_first_layers" }) for (auto el : { "min_fan_speed", "disable_fan_first_layers" })
get_field(el)->toggle(fan_always_on); get_field(el)->toggle(fan_always_on);
// Thaw();
update_filament_overrides_page();
m_update_cnt--; m_update_cnt--;
if (m_update_cnt == 0) if (m_update_cnt == 0)

View file

@ -337,6 +337,11 @@ class TabFilament : public Tab
{ {
ogStaticText* m_volumetric_speed_description_line; ogStaticText* m_volumetric_speed_description_line;
ogStaticText* m_cooling_description_line; ogStaticText* m_cooling_description_line;
void add_filament_overrides_page();
void update_filament_overrides_page();
std::map<std::string, wxCheckBox*> m_overrides_options;
public: public:
TabFilament(wxNotebook* parent) : TabFilament(wxNotebook* parent) :
// Tab(parent, _(L("Filament Settings")), L("filament")) {} // Tab(parent, _(L("Filament Settings")), L("filament")) {}

View file

@ -513,6 +513,15 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
init_container(); init_container();
} }
#ifndef NDEBUG
bool ObjectDataViewModelNode::valid()
{
// Verify that the object was not deleted yet.
assert(m_idx >= -1);
return m_idx >= -1;
}
#endif /* NDEBUG */
void ObjectDataViewModelNode::set_action_icon() void ObjectDataViewModelNode::set_action_icon()
{ {
m_action_icon_name = m_type & itObject ? "advanced_plus" : m_action_icon_name = m_type & itObject ? "advanced_plus" :
@ -1457,6 +1466,7 @@ wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const
return wxDataViewItem(0); return wxDataViewItem(0);
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
assert(node != nullptr && node->valid());
// objects nodes has no parent too // objects nodes has no parent too
if (node->m_type == itObject) if (node->m_type == itObject)
@ -2783,21 +2793,20 @@ LockButton::LockButton( wxWindow *parent,
const wxSize& size /*= wxDefaultSize*/): const wxSize& size /*= wxDefaultSize*/):
wxButton(parent, id, wxEmptyString, pos, size, wxBU_EXACTFIT | wxNO_BORDER) wxButton(parent, id, wxEmptyString, pos, size, wxBU_EXACTFIT | wxNO_BORDER)
{ {
m_bmp_lock_on = ScalableBitmap(this, "one_layer_lock_on.png"); m_bmp_lock_closed = ScalableBitmap(this, "lock_closed");
m_bmp_lock_off = ScalableBitmap(this, "one_layer_lock_off.png"); m_bmp_lock_closed_f = ScalableBitmap(this, "lock_closed_f");
m_bmp_unlock_on = ScalableBitmap(this, "one_layer_unlock_on.png"); m_bmp_lock_open = ScalableBitmap(this, "lock_open");
m_bmp_unlock_off = ScalableBitmap(this, "one_layer_unlock_off.png"); m_bmp_lock_open_f = ScalableBitmap(this, "lock_open_f");
#ifdef __WXMSW__ #ifdef __WXMSW__
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
#endif // __WXMSW__ #endif // __WXMSW__
SetBitmap(m_bmp_unlock_on.bmp()); SetBitmap(m_bmp_lock_open.bmp());
SetBitmapDisabled(m_bmp_lock_on.bmp()); SetBitmapDisabled(m_bmp_lock_open.bmp());
SetBitmapHover(m_bmp_lock_closed_f.bmp());
//button events //button events
Bind(wxEVT_BUTTON, &LockButton::OnButton, this); Bind(wxEVT_BUTTON, &LockButton::OnButton, this);
Bind(wxEVT_ENTER_WINDOW, &LockButton::OnEnterBtn, this);
Bind(wxEVT_LEAVE_WINDOW, &LockButton::OnLeaveBtn, this);
} }
void LockButton::OnButton(wxCommandEvent& event) void LockButton::OnButton(wxCommandEvent& event)
@ -2806,7 +2815,7 @@ void LockButton::OnButton(wxCommandEvent& event)
return; return;
m_is_pushed = !m_is_pushed; m_is_pushed = !m_is_pushed;
enter_button(true); update_button_bitmaps();
event.Skip(); event.Skip();
} }
@ -2814,23 +2823,21 @@ void LockButton::OnButton(wxCommandEvent& event)
void LockButton::SetLock(bool lock) void LockButton::SetLock(bool lock)
{ {
m_is_pushed = lock; m_is_pushed = lock;
enter_button(true); update_button_bitmaps();
} }
void LockButton::msw_rescale() void LockButton::msw_rescale()
{ {
m_bmp_lock_on .msw_rescale(); m_bmp_lock_closed.msw_rescale();
m_bmp_lock_off .msw_rescale(); m_bmp_lock_closed_f.msw_rescale();
m_bmp_unlock_on .msw_rescale(); m_bmp_lock_open.msw_rescale();
m_bmp_unlock_off.msw_rescale(); m_bmp_lock_open_f.msw_rescale();
} }
void LockButton::enter_button(const bool enter) void LockButton::update_button_bitmaps()
{ {
const wxBitmap& icon = m_is_pushed ? SetBitmap(m_is_pushed ? m_bmp_lock_closed.bmp() : m_bmp_lock_open.bmp());
enter ? m_bmp_lock_off.bmp() : m_bmp_lock_on.bmp() : SetBitmapHover(m_is_pushed ? m_bmp_lock_closed_f.bmp() : m_bmp_lock_open_f.bmp());
enter ? m_bmp_unlock_off.bmp() : m_bmp_unlock_on.bmp();
SetBitmap(icon);
Refresh(); Refresh();
Update(); Update();
@ -2999,6 +3006,13 @@ ScalableButton::ScalableButton( wxWindow * parent,
#endif // __WXMSW__ #endif // __WXMSW__
SetBitmap(create_scaled_bitmap(parent, icon_name)); SetBitmap(create_scaled_bitmap(parent, icon_name));
if (size != wxDefaultSize)
{
const int em = em_unit(parent);
m_width = size.x/em;
m_height= size.y/em;
}
} }
@ -3025,11 +3039,24 @@ void ScalableButton::SetBitmap_(const ScalableBitmap& bmp)
m_current_icon_name = bmp.name(); m_current_icon_name = bmp.name();
} }
void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp)
{
SetBitmapDisabled(bmp.bmp());
m_disabled_icon_name = bmp.name();
}
void ScalableButton::msw_rescale() void ScalableButton::msw_rescale()
{ {
const wxBitmap bmp = create_scaled_bitmap(m_parent, m_current_icon_name); SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name));
if (!m_disabled_icon_name.empty())
SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name));
SetBitmap(bmp); if (m_width > 0 || m_height>0)
{
const int em = em_unit(m_parent);
wxSize size(m_width * em, m_height * em);
SetMinSize(size);
}
} }

View file

@ -161,7 +161,7 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ObjectDataViewModelNode: a node inside PrusaObjectDataViewModel // ObjectDataViewModelNode: a node inside ObjectDataViewModel
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
enum ItemType { enum ItemType {
@ -259,6 +259,10 @@ public:
ObjectDataViewModelNode *child = m_children[i]; ObjectDataViewModelNode *child = m_children[i];
delete child; delete child;
} }
#ifndef NDEBUG
// Indicate that the object was deleted.
m_idx = -2;
#endif /* NDEBUG */
} }
void init_container(); void init_container();
@ -269,6 +273,7 @@ public:
ObjectDataViewModelNode* GetParent() ObjectDataViewModelNode* GetParent()
{ {
assert(m_parent == nullptr || m_parent->valid());
return m_parent; return m_parent;
} }
MyObjectTreeModelNodePtrArray& GetChildren() MyObjectTreeModelNodePtrArray& GetChildren()
@ -357,6 +362,11 @@ public:
bool update_settings_digest(const std::vector<std::string>& categories); bool update_settings_digest(const std::vector<std::string>& categories);
int volume_type() const { return int(m_volume_type); } int volume_type() const { return int(m_volume_type); }
void msw_rescale(); void msw_rescale();
#ifndef NDEBUG
bool valid();
#endif /* NDEBUG */
private: private:
friend class ObjectDataViewModel; friend class ObjectDataViewModel;
}; };
@ -859,8 +869,6 @@ public:
~LockButton() {} ~LockButton() {}
void OnButton(wxCommandEvent& event); void OnButton(wxCommandEvent& event);
void OnEnterBtn(wxMouseEvent& event) { enter_button(true); event.Skip(); }
void OnLeaveBtn(wxMouseEvent& event) { enter_button(false); event.Skip(); }
bool IsLocked() const { return m_is_pushed; } bool IsLocked() const { return m_is_pushed; }
void SetLock(bool lock); void SetLock(bool lock);
@ -872,16 +880,16 @@ public:
void msw_rescale(); void msw_rescale();
protected: protected:
void enter_button(const bool enter); void update_button_bitmaps();
private: private:
bool m_is_pushed = false; bool m_is_pushed = false;
bool m_disabled = false; bool m_disabled = false;
ScalableBitmap m_bmp_lock_on; ScalableBitmap m_bmp_lock_closed;
ScalableBitmap m_bmp_lock_off; ScalableBitmap m_bmp_lock_closed_f;
ScalableBitmap m_bmp_unlock_on; ScalableBitmap m_bmp_lock_open;
ScalableBitmap m_bmp_unlock_off; ScalableBitmap m_bmp_lock_open_f;
}; };
@ -912,12 +920,16 @@ public:
~ScalableButton() {} ~ScalableButton() {}
void SetBitmap_(const ScalableBitmap& bmp); void SetBitmap_(const ScalableBitmap& bmp);
void SetBitmapDisabled_(const ScalableBitmap &bmp);
void msw_rescale(); void msw_rescale();
private: private:
wxWindow* m_parent; wxWindow* m_parent;
std::string m_current_icon_name = ""; std::string m_current_icon_name = "";
std::string m_disabled_icon_name = "";
int m_width {-1}; // should be multiplied to em_unit
int m_height{-1}; // should be multiplied to em_unit
}; };

View file

@ -3,7 +3,7 @@
set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_NAME "PrusaSlicer")
set(SLIC3R_APP_KEY "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer")
set(SLIC3R_VERSION "2.0.0") set(SLIC3R_VERSION "2.1.0-alpha0")
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_RC_VERSION "2,0,0,0") set(SLIC3R_RC_VERSION "2,1,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.0.0.0") set(SLIC3R_RC_VERSION_DOTS "2.1.0.0")

View file

@ -75,7 +75,7 @@ _constant()
Ref<StaticPrintConfig> config() Ref<StaticPrintConfig> config()
%code%{ RETVAL = const_cast<GCodeConfig*>(static_cast<const GCodeConfig*>(&THIS->config())); %}; %code%{ RETVAL = const_cast<GCodeConfig*>(static_cast<const GCodeConfig*>(&THIS->config())); %};
Ref<PlaceholderParser> placeholder_parser() Ref<PlaceholderParser> placeholder_parser()
%code%{ RETVAL = &THIS->placeholder_parser(); %}; %code%{ RETVAL = const_cast<PlaceholderParser*>(&THIS->placeholder_parser()); %};
Ref<ExtrusionEntityCollection> skirt() Ref<ExtrusionEntityCollection> skirt()
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->skirt()); %}; %code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->skirt()); %};
Ref<ExtrusionEntityCollection> brim() Ref<ExtrusionEntityCollection> brim()