Merge branch 'master' into fs_QuadricEdgeCollapse

This commit is contained in:
Filip Sykala 2021-08-16 11:56:56 +02:00
commit b90ca142a5
116 changed files with 3328 additions and 1335 deletions

View File

@ -569,7 +569,7 @@ elseif (SLIC3R_FHS)
# CMAKE_INSTALL_FULL_DATAROOTDIR: read-only architecture-independent data root (share)
set(SLIC3R_FHS_RESOURCES "${CMAKE_INSTALL_FULL_DATAROOTDIR}/PrusaSlicer")
install(DIRECTORY ${SLIC3R_RESOURCES_DIR}/ DESTINATION ${SLIC3R_FHS_RESOURCES}
PATTERN "*/data" EXCLUDE PATTERN "*/udev" EXCLUDE
PATTERN "*/udev" EXCLUDE
)
install(FILES src/platform/unix/PrusaSlicer.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES src/platform/unix/PrusaGcodeviewer.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)

View File

@ -1,3 +1,94 @@
# THIS DOCUMENT CONTAINS DATA FOR HINTS NOTIFICATIONS
#
# Each notification is divided by
# [hint:*name of notification*]
#
# Each notification MUST have text var in format:
# text = Headline of hint\nBody of hint.
# Headline is divided by new line (\n) from body.
# Headline is automaticaly printed as Bold.
# Body can contain bold marks: <b>text to be bold</b> (currently rendered as different color, not bold due to font limitations)
# Body can contain hypertext: <a>hypertext text</a>
# Hypertext must be max one per notification and must be closed by </a>
#
# Notification can have documentation link:
# documentation_link = https://help.prusa3d.com/en/article/name-of-article
#
# If notification contains hypertext, it needs to be specified by hypertext_type var.
# each type needs to be supported with one or more additional vars.
# These types are possible:
#
# Settings highlight (like search feature)
# hypertext_type = settings
# hypertext_settings_opt = name_of_settings (hover over settings value and copy last line of hover text)
# hypertext_settings_type = 1 (1 - 5 according to settings tab - to be channged to name of tabs instead of numbers)
# hypertext_settings_category = Infill (name of panel - written on left in settings)
#
# Plater top toolbar highlight
# hypertext_type = plater
# hypertext_plater_item = nameofbutton (internal name of GLToolbar items)
#
# Plater gizmos (left) toolbar highlight
# hypertext_type = gizmo
# hypertext_gizmo_item = name (name of svg icon of gizmo in resources without .svg suffix)
#
# Open preferences (might add item to highlight)
# hypertext_type = preferences
# hypertext_preferences_page = 0 (values 0-2 according to prefernces tab to be opened)
#
# Open gallery (no aditional var)
# hypertext_type = gallery
#
#
# Each notification can have disabled and enabled modes and techs - divided by ; and space
# enabled_tags = ...
# disabled_tags = ...
# supported tags are: simple; advanced; expert; FFF; MMU; SLA; Windows; Linux; OSX;
# Tags are case sensitive.
# FFF is affirmative for both one or more extruder printers.
# Algorithm shows hint only if ALL enabled tags are affirmative. (so never do enabled_tags = FFF; SLA;)
# Algorithm shows hint only if not in all disabled tags.
# if there are both disabled and preferred, only preferred that are not in disabled are valid.
[hint:Fuzzy skin]
text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using the<a>Fuzzy skin</a>feature? You can also use modifiers to apply fuzzy-skin only to a portion of your model.
hypertext_type = settings
hypertext_settings_opt = fuzzy_skin
hypertext_settings_type = 1
hypertext_settings_category = Layers and perimeters
disabled_tags = SLA
[hint:Shapes gallery]
text = Shapes gallery\nDid you know that PrusaSlicer has a Shapes Gallery? You can use the included models as modifiers, negative volumes or as printable objects. Right-click the platter and select<a>Add Shape - Gallery.</a>
hypertext_type = gallery
disable_modes = simple
[hint:Auto-arrange settings]
text = Auto-arrange settings\nDid you know that you can right-click the<a>auto-arrange icon</a>to adjust the size of the gap between objects and to allow automatic rotations?
hypertext_type = plater
hypertext_plater_item = arrange
[hint:Negative volume]
text = Negative volume\nDid you know that you can subtract one mesh from another using the Negative volume modifier? That way you can, for example, create easily resizable holes directly in PrusaSlicer. Read more in the documentation. (Requires Advanced or Expert mode.)
hypertext_type = link
documentation_link = https://help.prusa3d.com/en/article/negative-volume_238503
disabled_tags = SLA; simple
[hint:Simplify mesh]
text = Simplify mesh\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the documentation.
hypertext_type = link
documentation_link = https://help.prusa3d.com/en/article/simplify-mesh_238941
[hint:Reload from disk]
text = Reload from disk\nDid you know that if you created a newer version of your model, you can simply reload it in PrusaSlicer? Right-click the model in the 3D view and choose Reload from disk. Read more in the documentation.
hypertext_type = link
documentation_link = https://help.prusa3d.com/en/article/reload-from-disk_120427
[hint:Hiding sidebar]
text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut <b>Shift+Tab</b>? You can also enable the icon for this from the<a>Preferences.</a>
hypertext_type = preferences
hypertext_preferences_page = 2
[hint:Perspective camera]
text = Perspective camera\nDid you know that you can use the <b>K</b> key to quickly switch between an orthographic and perspective camera?
@ -19,38 +110,24 @@ hypertext_type = settings
hypertext_settings_opt = infill_every_layers
hypertext_settings_type = 1
hypertext_settings_category = Infill
disabled_modes = SLA; simple
[hint:Hiding sidebar]
text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut <b>Shift+Tab</b>? You can also enable the icon for this from the<a>Preferences.</a>
hypertext_type = preferences
hypertext_preferences_page = 2
disabled_tags = SLA; simple
[hint:Variable layer height]
text = Variable layer height\nDid you know that you can print different regions of your model with a different layer height and smooth the transitions between them? Try the<a>Variable layer height tool.</a>(Not available for SLA printers.)
hypertext_type = plater
hypertext_plater_item = layersediting
disabled_modes = SLA
disabled_tags = SLA
[hint:Undo/redo history]
text = Undo/redo history\nDid you know that you can right-click the<a>undo/redo arrows</a>to see the history of changes and to undo or redo several actions at once?
hypertext_type = plater
hypertext_plater_item = undo
[hint:Auto-arrange settings]
text = Auto-arrange settings\nDid you know that you can right-click the<a>auto-arrange icon</a>to adjust the size of the gap between objects and to allow automatic rotations?
hypertext_type = plater
hypertext_plater_item = arrange
[hint:Reload from disk]
text = Reload from disk\nDid you know that if you created a newer version of your model, you can simply reload it in PrusaSlicer? Right-click the model in the 3D view and choose Reload from disk. Read more in the<a>documentation.</a>
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/reload-from-disk_120427
[hint:Different layer height for each model]
text = Different layer height for each model\nDid you know that you can print each model on the plater with a different layer height? Right-click the model in the 3D view, choose Layers and Perimeters and adjust the values in the right panel. Read more in the<a>documentation.</a>
text = Different layer height for each model\nDid you know that you can print each model on the plater with a different layer height? Right-click the model in the 3D view, choose Layers and Perimeters and adjust the values in the right panel. Read more in the documentation.
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/per-model-settings_1674
documentation_link= https://help.prusa3d.com/en/article/per-model-settings_1674
disabled_tags = SLA
[hint:Solid infill threshold area]
text = Solid infill threshold area\nDid you know that you can make parts of your model with a small cross-section be filled with solid infill automatically? Set the<a>Solid infill threshold area.</a>(Expert mode only.)
@ -58,7 +135,7 @@ hypertext_type = settings
hypertext_settings_opt = solid_infill_below_area
hypertext_settings_type = 1
hypertext_settings_category = Infill
disabled_modes = SLA; simple; advanced
enabled_tags = FFF; expert
[hint:Search functionality]
text = Search functionality\nDid you know that you use the<a>Search</a>tool to quickly find a specific PrusaSlicer setting? Or use the familiar shortcut <b>Ctrl+F</b>.
@ -71,11 +148,6 @@ text = Box selection\nDid you know that you can do a box selection with Shift+Mo
[hint:Zoom on selected objects or on all objects if none selected]
text =Zoom on selected objects or on all objects if none selected\nDid you know that you can zoom in on selected objects by pressing the <b>Z</b> key? If none are selected, the camera will zoom on all objects in the scene.
[hint:Shapes gallery]
text = Shapes gallery\nDid you know that PrusaSlicer has a Shapes Gallery? You can use the included models as modifiers, negative volumes or as printable objects. Right-click the platter and select<a>Add Shape - Gallery.</a>
hypertext_type = gallery
disable_modes = simple
[hint:Printable toggle]
text = Printable toggle\nDid you know that you can disable the G-code generation for the selected model without having to move or delete it? Toggle the Printable property of a model from the Right-click context menu.
@ -89,51 +161,39 @@ text = PageUp / PageDown quick rotation by 45 degrees\nDid you know that you can
text = Load config from G-code\nDid you know that you can use File-Import Config to load print, filament and printer profiles from an existing G-code file? Similarly, you can use File-Import SL1 archive, which also lets you reconstruct 3D models from the voxel data.
[hint:Ironing]
text = Ironing\nDid you know that you can smooth top surfaces of prints using Ironing? The nozzle will run a special second infill phase at the same layer to fill in holes and flatten any lifted plastic. Read more in the<a>documentation.</a> (Requires Advanced or Expert mode.)
text = Ironing\nDid you know that you can smooth top surfaces of prints using Ironing? The nozzle will run a special second infill phase at the same layer to fill in holes and flatten any lifted plastic. Read more in the documentation. (Requires Advanced or Expert mode.)
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/ironing_177488
disabled_modes = SLA; simple
[hint:Fuzzy skin]
text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using the<a>Fuzzy skin</a>feature? You can also use modifiers to apply fuzzy-skin only to a portion of your model.
hypertext_type = settings
hypertext_settings_opt = fuzzy_skin
hypertext_settings_type = 1
hypertext_settings_category = Layers and perimeters
disabled_modes = SLA
[hint:Negative volume]
text = Negative volume\nDid you know that you can subtract one mesh from another using the Negative volume modifier? That way you can, for example, create easily resizable holes directly in PrusaSlicer. Read more in the<a>documentation.</a>(Requires Advanced or Expert mode.)
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/negative-volume_238503
disabled_modes = SLA; simple
documentation_link = https://help.prusa3d.com/en/article/ironing_177488
disabled_tags = SLA; simple
[hint:Paint-on supports]
text = Paint-on supports\nDid you know that you can paint directly on the object and select areas, where supports should be enforced or blocked? Try the<a>Paint-on supports</a>feature. (Requires Advanced or Expert mode.)
hypertext_type = gizmo
hypertext_gizmo_item = fdm_supports
disabled_modes = SLA; simple
disabled_tags = SLA; simple
[hint:Paint-on seam]
text = Paint-on seam\nDid you know that you can paint directly on the object and select where to place the start/endpoint of each perimeter loop? Try the<a>Seam painting</a>feature. (Requires Advanced or Expert mode.)
hypertext_type = gizmo
hypertext_gizmo_item = seam
disabled_modes = SLA; simple
disabled_tags = SLA; simple
[hint:Insert Pause]
text = Insert Pause\nDid you know that you can schedule the print to pause at a specific layer? Right-click the layer slider in the Preview and select Add pause print (M601). This can be used to insert magnets, weights or nuts into your prints. Read more in the<a>documentation.</a>
text = Insert Pause\nDid you know that you can schedule the print to pause at a specific layer? Right-click the layer slider in the Preview and select Add pause print (M601). This can be used to insert magnets, weights or nuts into your prints. Read more in the documentation.
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer
documentation_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer
disabled_tags = SLA
[hint:Insert Custom G-code]
text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Right-click the layer in the Preview and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in the<a>documentation.</a>
text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Right-click the layer in the Preview and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in the documentation.
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer
documentation_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer
disabled_tags = SLA
[hint:Configuration snapshots]
text = Configuration snapshots\nDid you know that roll back to a complete backup of all system and user profiles? You can view and move back and forth between snapshots using the Configuration - Configuration snapshots menu. Read more in the<a>documentation.</a>
text = Configuration snapshots\nDid you know that roll back to a complete backup of all system and user profiles? You can view and move back and forth between snapshots using the Configuration - Configuration snapshots menu. Read more in the documentation.
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/configuration-snapshots_1776
documentation_link = https://help.prusa3d.com/en/article/configuration-snapshots_1776
[hint:Minimum wall thickness]
text = Minimum wall thickness\nDid you know that instead of the number of top and bottom layers, you can define the<a>Minimum shell thickness</a>in millimeters? This feature is especially useful when using the variable layer height function.
@ -141,7 +201,7 @@ hypertext_type = settings
hypertext_settings_opt = top_solid_min_thickness
hypertext_settings_type = 1
hypertext_settings_category = Layers and perimeters
disabled_modes = SLA
disabled_tags = SLA
[hint:Settings in non-modal window]
text = Settings in non-modal window\nDid you know that you can open the Settings in a new non-modal window? This means you can have settings open on one screen and the G-code Preview on the other. Go to the<a>Preferences</a>and select Settings in non-modal window.
@ -149,17 +209,14 @@ hypertext_type = preferences
hypertext_preferences_page = 2
[hint:Adaptive infills]
text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in the<a>documentation.</a>
text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in the documentation.
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/infill-patterns_177130
documentation_link = https://help.prusa3d.com/en/article/infill-patterns_177130
disabled_tags = SLA
[hint:Fullscreen mode]
text = Fullscreen mode\nDid you know that you can switch PrusaSlicer to fullscreen mode? Use the <b>F11</b> hotkey.
[hint:Simplify mesh]
text = Simplify mesh\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the<a>documentation.</a>
hypertext_type = link
hypertext_link = https://help.prusa3d.com/en/article/simplify-mesh_238941
enabled_tags = Windows
#[hint:]
#text =

View File

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 25.4.1, 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>
<circle fill="#808080" cx="8" cy="8" r="0"/>
</g>
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path fill="#808080" d="M14,14.5c-0.28,0-0.5-0.22-0.5-0.5v-3c0-0.38-0.29-0.93-0.61-1.14L8.55,6.97c-0.29-0.19-0.82-0.19-1.11,0
L3.11,9.86C2.79,10.07,2.5,10.62,2.5,11v3c0,0.28-0.22,0.5-0.5,0.5S1.5,14.28,1.5,14v-3c0-0.72,0.45-1.57,1.05-1.97l4.34-2.89
c0.62-0.42,1.6-0.42,2.22,0l4.34,2.89c0.6,0.4,1.05,1.25,1.05,1.97v3C14.5,14.28,14.28,14.5,14,14.5z"/>
<path fill="#ED6B21" d="M14.11,8c-0.54,0-0.98-0.43-1-0.97C11.8,6.98,11.11,5.96,11.11,5l-1-0.01c-1.26,0-1.95-0.97-2-1.91
c-0.01,0-0.01,0-0.02,0H8c0,0-0.01,0-0.02,0c-0.05,0.96-0.75,1.91-2,1.91h-1c0.03,0-0.02,0.02-0.04,0.03C4.99,5.97,4.3,7,3,7.03
C2.95,7.54,2.52,7.97,2,7.97C1.45,7.97,1,7.55,1,7c0-0.74,0.31-1.19,0.57-1.44C2.14,5.02,2.86,5.02,3,5.03c0-1.44,1.17-2,1.95-2.04
l1.04,0c0-0.69,0.3-1.12,0.55-1.36c0.58-0.56,1.35-0.56,1.5-0.55l0.07,0c0.11,0,0.88-0.01,1.46,0.55c0.25,0.24,0.55,0.68,0.55,1.37
l1,0c0.83,0.03,2,0.6,2,2.01c0.13,0.02,0.86,0.02,1.42,0.56c0.26,0.25,0.57,0.7,0.57,1.44C15.11,7.55,14.66,8,14.11,8z"/>
</svg>

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

71
resources/icons/info.svg Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
id="error"
x="0px"
y="0px"
viewBox="0 0 200 200"
enable-background="new 0 0 100 100"
xml:space="preserve"
sodipodi:docname="notification_error.svg"
width="200"
height="200"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
id="metadata19"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs17" /><sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1377"
id="namedview15"
showgrid="false"
inkscape:zoom="5.04"
inkscape:cx="117.17146"
inkscape:cy="98.609664"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="error" />
<g
id="g4"
transform="matrix(2.52,0,0,2.52,-26,-26)">
<path
fill="#808080"
d="m 50,54.25 c -2.35,0 -4.25,-1.9 -4.25,-4.25 V 35 c 0,-2.35 1.9,-4.25 4.25,-4.25 2.35,0 4.25,1.9 4.25,4.25 v 15 c 0,2.35 -1.9,4.25 -4.25,4.25 z"
id="path2" />
</g>
<g
id="g8"
transform="matrix(2.52,0,0,2.52,-26,-26)">
<circle
fill="#808080"
cx="50"
cy="65"
r="5"
id="circle6" />
</g>
<g
id="g12"
transform="matrix(2.52,0,0,2.52,-26,-26)">
<path
fill="#808080"
d="M 50,89.25 C 28.36,89.25 10.75,71.64 10.75,50 10.75,28.36 28.36,10.75 50,10.75 71.64,10.75 89.25,28.36 89.25,50 89.25,71.64 71.64,89.25 50,89.25 Z m 0,-70 C 33.05,19.25 19.25,33.04 19.25,50 19.25,66.95 33.04,80.75 50,80.75 66.95,80.75 80.75,66.96 80.75,50 80.75,33.05 66.95,19.25 50,19.25 Z"
id="path10" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, 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"
width="128px" height="128px" viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
<path fill="#FFFFFF" d="M52.87,108.38c-5.24,0-9.5-4.26-9.5-9.5s4.26-9.5,9.5-9.5s9.5,4.26,9.5,9.5S58.11,108.38,52.87,108.38z
M52.87,92.38c-3.58,0-6.5,2.92-6.5,6.5s2.92,6.5,6.5,6.5s6.5-2.92,6.5-6.5S56.46,92.38,52.87,92.38z M29.82,83.59
c-5.24,0-9.5-4.26-9.5-9.5s4.26-9.5,9.5-9.5s9.5,4.26,9.5,9.5S35.06,83.59,29.82,83.59z M29.82,67.59c-3.58,0-6.5,2.92-6.5,6.5
s2.92,6.5,6.5,6.5s6.5-2.92,6.5-6.5S33.4,67.59,29.82,67.59z M34,49.86c-5.24,0-9.5-4.26-9.5-9.5s4.26-9.5,9.5-9.5s9.5,4.26,9.5,9.5
S39.24,49.86,34,49.86z M34,33.86c-3.58,0-6.5,2.92-6.5,6.5s2.92,6.5,6.5,6.5s6.5-2.92,6.5-6.5S37.59,33.86,34,33.86z M64,35.21
c-5.24,0-9.5-4.26-9.5-9.5s4.26-9.5,9.5-9.5s9.5,4.26,9.5,9.5S69.24,35.21,64,35.21z M64,19.21c-3.58,0-6.5,2.92-6.5,6.5
s2.92,6.5,6.5,6.5s6.5-2.92,6.5-6.5S67.58,19.21,64,19.21z M96.1,52.24c-5.24,0-9.5-4.26-9.5-9.5s4.26-9.5,9.5-9.5s9.5,4.26,9.5,9.5
S101.34,52.24,96.1,52.24z M96.1,36.24c-3.58,0-6.5,2.92-6.5,6.5s2.92,6.5,6.5,6.5s6.5-2.92,6.5-6.5S99.69,36.24,96.1,36.24z
M72.54,120.87c2.6-0.39,4.78-2.06,5.81-4.46c1.06-2.47,0.77-5.29-0.8-7.52c-3.1-4.43-4.49-9.87-3.92-15.31
c0.26-2.47,0.94-4.89,2.03-7.17c0.36-0.75,0.04-1.64-0.71-2c-0.75-0.36-1.64-0.04-2,0.71c-1.23,2.6-2.01,5.34-2.3,8.15
c-0.64,6.16,0.94,12.32,4.45,17.34c0.96,1.38,1.15,3.11,0.5,4.62c-0.63,1.47-1.91,2.44-3.5,2.68c-3.29,0.49-6.66,0.68-10.01,0.57
c-28.61-0.99-51.7-24.18-52.56-52.79c-0.46-15.2,5.2-29.48,15.94-40.21S50.49,9.07,65.68,9.53c28.62,0.86,51.8,23.94,52.79,52.56
c0.11,3.25-0.06,6.51-0.52,9.69c-0.24,1.66-1.31,3.06-2.87,3.73c-1.52,0.66-3.16,0.5-4.49-0.42c-3.29-2.3-7.17-3.8-11.21-4.34
c-0.83-0.11-1.58,0.47-1.68,1.29c-0.11,0.82,0.47,1.58,1.29,1.68c3.57,0.47,6.99,1.79,9.89,3.82c2.17,1.52,4.94,1.78,7.4,0.72
c2.52-1.09,4.26-3.36,4.65-6.06c0.48-3.36,0.67-6.8,0.55-10.22c-1.04-30.19-25.5-54.55-55.7-55.45
c-16.02-0.48-31.1,5.49-42.42,16.81C12.02,34.66,6.05,49.73,6.53,65.77c0.9,30.19,25.26,54.66,55.45,55.7
c0.67,0.02,1.34,0.04,2.01,0.04C66.86,121.5,69.73,121.29,72.54,120.87z"/>
<path fill="#ED6B21" d="M115.41,105.01l-27.66-38.8c7.76-12.6-22.89-18.09-27.92-23.34c-2.48-2.6-0.44,35.31,15.58,32.26
l29.74,37.59c0.54,0.91,3.45,5.54,7.39,6.36c0.39,0.08,0.78,0.12,1.16,0.12c1.26,0,2.48-0.42,3.58-1.25
c1.36-1.02,2.14-2.41,2.27-4.01C119.87,109.95,116.14,105.79,115.41,105.01z M78.44,74.13c1.24-0.57,2.54-1.37,3.92-2.42
c1.39-1.05,2.53-2.06,3.45-3.04l6.94,9.73l-6.85,5.15L78.44,74.13z M116.56,113.69c-0.06,0.76-0.4,1.35-1.08,1.85
c-0.77,0.58-1.51,0.76-2.33,0.6c-2.38-0.49-4.75-3.78-5.46-5.01c-0.04-0.06-0.08-0.12-0.12-0.18L87.76,85.91l6.73-5.06l18.53,25.99
c0.04,0.06,0.09,0.12,0.14,0.17C114.11,107.98,116.75,111.3,116.56,113.69z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 105.1 105.1"
xml:space="preserve"
sodipodi:docname="notification_clippy.svg"
width="105.1"
height="105.1"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
id="metadata99"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs97" /><sodipodi:namedview
inkscape:pagecheckerboard="true"
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1377"
id="namedview95"
showgrid="false"
inkscape:zoom="9.590866"
inkscape:cx="31.799999"
inkscape:cy="52.549999"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<style
type="text/css"
id="style2">
.st0{fill:#FFFFFF;}
.st1{fill:#ED6B21;}
.st2{fill:#B6D2FB;}
.st3{fill:#CCCCCC;}
.st4{fill:#909097;}
.st5{fill:#90BDFE;}
.st6{fill:#C9C9C9;}
.st7{fill:#4E595F;}
</style>
<path
style="fill:#ffffff;fill-opacity:1"
class="st0"
d="m 9.5127976,51.5 c -1.6,9.4 3.0000004,29.7 4.7000004,34.2 3,7.9 5.8,16.1 16.2,18.5 10.4,2.4 19.2,-0.5 22.5,-5.6 6.9,-10.4 6.2,-17.8 4.7,-23.3 -1.5,-5.5 -2.9,-9.1 0.5,-15.2 3.4,-6.1 -0.7,-8 0.8,-12.1 1.5,-4.1 5.2,-6.5 5.1,-8.3 -0.1,-1.8 -3.1,-3.1 -4.3,-5 -1.2,-1.9 1.3,-5.1 1.8,-7.5 0.5,-2.4 0,-11.7 -7,-17.9 -4.7,-4.1 -8.9,-9.3 -22.3,-9.3 -5.7,0 -13.6,3 -18.8,8.2 -5.2000004,5.2 -6.0000004,13 -5.4000004,15.7 0.6,2.7 -7.19999999,-0.5 -7.39999999,3.3 -0.2,3.8 -1.1,16 1.49999999,19.2 4.3,5.2 7.4,5.1 7.4,5.1 z"
id="path4" />
<path
class="st0"
d="m 33.612798,39 c -0.8,1.8 -2,11.3 7.3,13.8 9.3,2.5 13.1,-4.9 13.6,-10.4 0.5,-5.5 -6.9,-4.9 -10.6,-5.1 -3.7,-0.2 -9.1,-0.9 -10.3,1.7 z"
id="path6" />
<path
class="st0"
d="m 8.6127976,30.9 c 0,0 -2.2,5.1 -2.2,6.3 0,1.2 0.7,6 1.8,7.4 1.1,1.4 7.0000004,3.4 7.5000004,3.4 0.5,0 9.3,-0.2 12,-8.3 2.7,-8.1 -17.2,-9.6 -17.2,-9.6 z"
id="path8" />
<path
style="fill:#000000;fill-opacity:1"
d="m 54.012798,29.6 c 10,-16.9 -30,-22.5 -40.8,-11.5 -2.6,2.7 2.6,15.4 7,11 0.5,-0.8 0.7,-1.5 1.3,-2.4 4,-6.3 7.1,-6.4 13.5,-5.8 9.1,-0.1 10.1,0.3 14.8,9.2 0.4,0.8 3.9,-0.2 4.2,-0.5 z"
id="path10" />
<path
style="fill:#ed6b21;fill-opacity:1"
class="st1"
d="m 24.012798,94.2 v 0 c -8.4,-13.3 -10.7,-30.6 -9.5,-46 0.1,-1.2 3.7,-0.2 4.6,-0.1 -0.6,13.7 0.5,45.9 17.8,48.1 4.3,0.2 8.2,-2.3 9.9,-6.3 3.6,-12 -5.6,-26.6 4.9,-36.9 v 0 c 1.9,-2.1 5.4,0.5 3.6,2.8 -1.8,2.3 -2.9,3.6 -3.5,5.9 -3.1,9.2 2.8,18.9 -0.1,28.1 -2.9,9.2 -16.1,14.3 -24.3,7.7 v 0"
id="path12" />
<path
style="fill:#ed6b21;fill-opacity:1"
class="st1"
d="m 42.212798,25.9 c -1.9,-4.7 -8.4,-6.5 -12.5,-3.6 l -0.9,1 c -1.5,-0.7 -3.1,-1.3 -4.7,-1.8 3.9,-5.8 12.2,-6.5 17.9,-3 l 2.5,2.4 v 0 c 2.1,2.6 3.1,5.9 2.8,9.2 -1.6,-0.8 -3.2,-1.4 -4.9,-1.8 0.1,0 0.3,0 0.3,-0.1 -0.1,-0.8 -0.3,-1.5 -0.5,-2.3 z"
id="path14" />
<path
class="st2"
d="M 24.912798,95.1"
id="path16" />
<path
class="st2"
d="M 26.512798,96.7 Z"
id="path18" />
<path
class="st2"
d="M 39.012798,17.2 Z"
id="path20" />
<path
class="st2"
d="m 38.412798,17 c 0,-0.1 0,-0.1 -0.1,-0.1 0.1,0 0.1,0 0.1,0.1 z"
id="path22" />
<path
class="st1"
d="m 26.512798,74.3 c -0.8,-2.9 -4.1,-22 2.6,-18.1 1.9,2.2 0.1,5.8 0.6,8.5 0.6,4.2 0.2,10.6 4.7,12.5 6.7,0.5 3,-8.6 2.9,-12.4 -0.1,-3.8 -0.2,-6.8 -0.2,-10.1 0.1,-0.9 0,-1.8 -0.3,-2.6 3.1,1.8 5.1,1.7 8.9,2.1 -6.5,0.8 -0.4,17.8 -3.3,22.9 -3.5,7.9 -14.3,4.9 -15.9,-2.8 z"
id="path24" />
<path
d="m 39.512798,40.3 c 5.6,-3.2 10.7,5.4 5.1,8.7 -5.6,3.3 -10.7,-5.4 -5.1,-8.7 z"
id="path26" />
<path
class="st1"
d="m 23.012798,32.2 c -1.5,0.3 -2.9,-1.1 -4.2,-1.4 l 1.5,-3.9 c 1.9,0 3.7,-0.5 5.6,-0.1 -1.2,1.2 -2.2,3.9 -2.9,5.4 z"
id="path28" />
<path
class="st1"
d="m 41.912798,33.2 2.9,1.3 1.7,1.1 c -0.3,-0.1 -0.6,0.2 -0.7,0.5 0,0.1 0,0.1 0,0.2 -0.2,1.1 -0.2,1.1 -1.3,0.8 l -3,-0.6 h -0.6 z"
id="path30" />
<path
class="st3"
d="m 37.712798,42 c -1.5,3.5 1.4,9 5.7,7.4 -4.6,1.8 -8.3,-3.9 -5.7,-7.4 z"
id="path32" />
<path
class="st4"
d="m 46.912798,35.9 0.6,0.6 z"
id="path34" />
<path
class="st4"
d="M 48.512798,36.8 Z"
id="path36" />
<path
class="st4"
d="m 47.612798,36.5 0.6,0.3 z"
id="path38" />
<path
class="st4"
d="m 50.112798,36.6 0.3,-0.2 z"
id="path40" />
<path
class="st4"
d="M 50.912798,33.1 Z"
id="path42" />
<path
class="st4"
d="m 50.912798,35.7 0.2,-0.2 z"
id="path44" />
<path
class="st4"
d="M 49.612798,36.8 Z"
id="path46" />
<path
class="st5"
d="m 42.212798,25.9 c 0,0.1 0,0.1 0.1,0.2 -0.1,-0.1 -0.1,-0.1 -0.1,-0.2 z"
id="path48" />
<path
class="st5"
d="M 42.012798,25.4 Z"
id="path50" />
<path
class="st4"
d="M 30.512798,24 Z"
id="path52" />
<path
class="st4"
d="M 30.612798,25.6 Z"
id="path54" />
<path
class="st4"
d="M 51.212798,35.1 Z"
id="path56" />
<path
class="st4"
d="M 26.712798,26.9 Z"
id="path58" />
<path
d="m 15.312798,35.8 c 5.3,-3.9 11.4,4.2 6,7.9 -5.4,3.7 -10.9,-3.8 -6.2,-7.8 z"
id="path60" />
<path
class="st6"
d="m 13.712798,37.7 c -0.5,3.2 1.7,6.2 4.9,6.7 0.5,0.1 0.9,0.1 1.4,0.1 -2.7,0.9 -5.6,-0.6 -6.4,-3.3 -0.4,-1.1 -0.4,-2.4 0.1,-3.5 z"
id="path62" />
<path
class="st4"
d="m 22.012798,46.5 1.4,-0.6 -0.3,0.4 h -1.1 z"
id="path64" />
<path
class="st2"
d="m 19.512798,67.3 c 0.1,0.1 0.1,0.2 0.1,0.3 0,-0.1 0,-0.2 -0.1,-0.3 z"
id="path66" />
<path
class="st4"
d="m 23.412798,45.9 0.8,-0.4 z"
id="path68" />
<path
class="st2"
d="M 26.212798,73.2 Z"
id="path70" />
<path
class="st2"
d="M 26.712798,42 Z"
id="path72" />
<path
class="st2"
d="M 26.112798,72.6 Z"
id="path74" />
<path
class="st2"
d="M 26.812798,41.5 Z"
id="path76" />
<path
class="st2"
d="M 26.912798,39.4 Z"
id="path78" />
<path
class="st2"
d="M 22.912798,46.4 Z"
id="path80" />
<path
class="st2"
d="M 26.512798,74.3 Z"
id="path82" />
<path
class="st2"
d="M 42.912798,75.3 Z"
id="path84" />
<path
style="fill:#000000;fill-opacity:1"
d="m 58.812798,39.5 c -6.3,-1.7 -12.8,-3.3 -19.3,-3.6 -3.2,0.3 -6.3,1 -9.4,-0.3 -6.3,-3.4 -13.2,-6.5 -20.5000004,-6.2 -1.2,0 -2.3,-0.1 -3.5,-0.3 -0.4,1.4 -0.1,0.1 -0.6,2 0.3,0.7 0.5,1.4 0.6,2.1 -0.9,4.3 -0.8,10 3.1,12.9 4.8000004,3.8 11.8000004,3.2 15.9000004,-1.3 0.8,-0.8 1.3,-1.8 2,-2.6 0.7,-0.8 1.6,-3.1 3.2,-2.9 1.2,0.2 2.1,1.2 2.1,2.4 0.3,3.8 1,8.4 4.4,10.7 8.4,4.1 15,2.3 18,-7 0.7,-1.6 2.1,-2.8 3.8,-3.1 0.5,-0.4 0.2,-2.1 0.2,-2.8 z m -31.7,-1.1 c -1.2,4.6 -5.6,8.8 -10.5,8.9 -4.9,0.1 -9.1000004,-2.1 -9.5000004,-6.6 -0.4,-4.5 0.7,-9.3 4.7000004,-9.8 4,-0.5 15.5,2 15.3,7.5 z m 26.5,5.1 c -0.4,5 -4.6,10.2 -10,9.2 -3.9,-0.6 -8.3,-2.7 -9.2,-6.8 -0.9,-4.1 -0.8,-8.2 5.2,-8.2 3.4,0 14,-0.2 14,5.8 z"
id="path86" />
<path
style="fill:#4e595f;fill-opacity:1"
class="st7"
d="m 53.412798,30.1 c 7,-20 -29.5,-19.9 -40.4,-11.8 4.5,-10.3 19.5,-15.6 29.6,-11 7.6,4.1 19.9,15.8 10.8,22.8 z"
id="path88" />
<path
style="fill:#4e595f;fill-opacity:1"
class="st7"
d="m 24.112798,21.5 c 2.5,0.7 6.9,0.3 6.5,4 -0.4,3.7 -4,1.2 -6,1.1 -9.4,2.5 -9.9,-5.6 -0.5,-5.1 z"
id="path90" />
<path
style="fill:#4e595f;fill-opacity:1"
class="st7"
d="m 42.112798,28 c 3.4,0.8 11.2,3.6 9.3,8 -1.9,4.4 -6.3,-2.4 -9.7,-2.7 -3.4,-0.3 -4.3,-6.5 0.4,-5.3 z"
id="path92" />
<path
id="path907"
d="m 18.203847,44.251067 c -2.585952,-0.625707 -4.478069,-3.00093 -4.482221,-5.626647 -0.0011,-0.68342 0.04118,-0.908987 0.22645,-1.208766 0.441896,-0.715002 0.880695,-1.188019 1.507624,-1.625187 0.800402,-0.558135 1.608194,-0.86189 2.488286,-0.935673 2.081527,-0.174508 4.256505,1.315589 5.114618,3.504069 0.333045,0.849378 0.330531,2.330672 -0.0054,3.174942 -0.353649,0.888833 -1.35261,1.910112 -2.402796,2.456479 -0.918889,0.478058 -1.356034,0.524654 -2.446572,0.260783 z"
style="fill:#000000;fill-opacity:1;stroke-width:0.104266" /><path
id="path909"
d="m 43.217112,54.362256 c -1.943218,-0.297512 -3.33888,-0.695069 -5.161161,-1.47017 -1.305359,-0.555231 -1.994482,-1.04951 -2.764143,-1.982606 -1.495878,-1.813522 -2.40778,-4.627277 -2.762975,-8.525403 -0.102151,-1.121063 -0.171339,-1.444217 -0.400105,-1.868746 -0.326236,-0.605409 -0.869849,-1.030551 -1.530406,-1.19688 -1.019338,-0.256673 -1.750342,0.238123 -2.983689,2.019573 -2.508173,3.622814 -3.600603,4.733874 -5.753345,5.851461 -1.821647,0.945701 -3.395384,1.328823 -5.440505,1.324476 -2.547169,-0.0054 -4.845125,-0.75357 -6.8207806,-2.220671 C 7.6204019,44.82326 6.5440009,43.087949 5.9755831,40.450215 5.705185,39.195436 5.7069633,35.746995 5.978813,34.186736 L 6.1717353,33.079474 5.9432039,32.257817 C 5.6045903,31.040373 5.599982,30.882333 5.8782008,30.028571 l 0.2548315,-0.781994 0.3997782,0.02038 c 0.219878,0.01121 1.7135282,0.06673 3.3192226,0.123387 3.3674269,0.118812 5.1309339,0.341238 7.4960049,0.94545 3.274014,0.836422 5.951877,1.892767 10.333459,4.07627 1.98671,0.99005 3.18594,1.524443 3.753571,1.67264 1.336652,0.348972 3.220015,0.37873 5.952537,0.09405 2.06175,-0.214796 2.428949,-0.226305 3.766452,-0.118047 3.128919,0.253253 6.304237,0.75368 7.172083,1.130311 0.475333,0.206287 0.838465,0.279371 1.511855,0.304275 0.916849,0.03391 2.659862,0.416264 6.859779,1.504796 l 2.107086,0.546114 v 1.184337 c 0,1.045317 -0.02448,1.208817 -0.208532,1.39287 -0.114693,0.114692 -0.279941,0.208532 -0.36722,0.208532 -0.399071,0 -1.553858,0.653076 -2.135083,1.207471 -0.803627,0.766531 -1.163082,1.338414 -1.56757,2.493967 -1.269217,3.62593 -3.359798,6.269806 -5.910062,7.474222 -1.253059,0.591784 -2.249827,0.819533 -3.78316,0.864403 -0.716828,0.02098 -1.444082,0.01659 -1.616121,-0.0097 z m 3.182819,-1.647337 c 1.514866,-0.321157 2.87975,-1.09633 4.097362,-2.327056 1.255255,-1.268773 2.027096,-2.541243 2.615639,-4.312181 0.891164,-2.681533 0.651771,-4.328111 -0.830909,-5.715085 -1.251949,-1.171137 -2.939613,-1.849937 -5.728403,-2.304036 -2.556217,-0.416229 -6.983049,-0.548668 -8.646042,-0.258667 -2.109031,0.367784 -3.297459,1.361334 -3.762093,3.145187 -0.331474,1.272612 -0.133889,3.885116 0.429383,5.677372 0.45329,1.442308 1.681515,2.976999 3.170323,3.961384 1.33698,0.883996 3.354989,1.686242 5.054857,2.009523 0.45877,0.08725 0.927967,0.178572 1.042659,0.202941 0.472239,0.100334 1.921768,0.05534 2.557224,-0.07938 z M 18.803694,47.037565 c 1.040805,-0.278608 2.517066,-0.984883 3.458594,-1.654666 2.130276,-1.515432 3.785931,-3.70126 4.628677,-6.110867 0.297814,-0.851521 0.314685,-0.971769 0.219366,-1.563641 -0.377369,-2.343245 -2.74543,-4.273287 -6.934379,-5.651728 -2.776474,-0.913644 -6.416073,-1.446889 -8.25518,-1.209484 -2.7814215,0.359046 -4.3821575,2.474641 -4.8396737,6.396303 -0.1508038,1.292635 -0.066449,3.597072 0.1671795,4.567069 0.4244128,1.762109 1.6258649,3.27225 3.3857492,4.255647 0.776664,0.433989 2.314765,0.935665 3.418401,1.114965 1.313296,0.213363 3.685606,0.141665 4.751266,-0.143598 z"
style="fill:#000000;fill-opacity:1;stroke-width:0.104266" /><path
id="path911"
d="M 34.354513,100.34287 C 32.636205,100.08376 31.2567,99.666463 29.892044,98.992995 28.514652,98.313242 27.769121,97.742627 25.838289,95.890325 24.227126,94.344691 24.020387,94.103877 23.356838,92.999893 17.48238,83.226214 14.287653,70.121179 14.283972,55.782241 c -5.51e-4,-2.145727 0.170082,-7.169062 0.246702,-7.262774 0.0073,-0.009 0.4356,0.02759 0.951716,0.08123 0.858983,0.08927 2.710027,-0.0084 3.336508,-0.176031 0.206602,-0.05528 0.208588,-0.0034 0.214625,5.605874 0.0046,4.287333 0.04966,6.256461 0.185566,8.111924 1.459457,19.925157 6.774837,31.21635 15.891611,33.757743 0.88693,0.247241 1.202189,0.283006 2.476055,0.280901 1.188142,-0.002 1.62461,-0.04681 2.345982,-0.241068 3.658803,-0.985257 6.479522,-3.812988 7.243904,-7.261912 0.347392,-1.567446 0.467852,-2.611776 0.541206,-4.691964 0.07559,-2.143451 -0.05225,-4.145496 -0.592334,-9.276936 -0.479678,-4.557473 -0.656907,-7.371033 -0.56829,-9.021724 0.290852,-5.417702 1.715904,-9.024223 4.831427,-12.227378 0.729882,-0.750412 0.981987,-0.941994 1.404813,-1.06756 0.659795,-0.195938 1.173275,-0.112988 1.865009,0.301281 0.727845,0.435896 1.184405,1.270675 1.079084,1.973009 -0.08007,0.533956 -0.303524,0.891663 -1.670256,2.673779 -1.220102,1.59092 -1.913107,2.940695 -2.40918,4.69239 -0.663476,2.342819 -0.725984,2.868697 -0.719438,6.052594 0.0063,3.042357 0.01296,3.115024 0.721562,7.81994 0.704671,4.678809 0.731973,4.974663 0.731264,7.924206 -7.3e-4,2.970111 -0.0829,3.696434 -0.633993,5.602807 -1.301694,4.502915 -5.185635,8.324439 -10.244257,10.079627 -1.801781,0.625161 -2.849081,0.802741 -4.969162,0.842581 -1.032232,0.0194 -2.017544,0.014 -2.189583,-0.0119 z"
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.104266" /><path
id="path913"
d="m 34.669114,81.623916 c -1.97568,-0.19567 -3.845887,-1.089074 -5.409188,-2.583989 -1.849916,-1.768992 -2.615443,-3.587976 -3.337625,-7.930603 -1.206148,-7.252808 -1.149117,-12.637889 0.153983,-14.539638 0.575104,-0.83931 1.470536,-1.03146 2.535223,-0.54403 0.506065,0.231684 0.589723,0.32046 0.904466,0.959793 0.300933,0.611282 0.352491,0.834111 0.389667,1.684118 0.02397,0.547975 -0.03759,1.714216 -0.139703,2.646779 -0.204973,1.87195 -0.184892,2.659837 0.151269,5.935141 0.452166,4.40558 0.881102,6.169497 1.887904,7.763655 0.505546,0.800478 1.385228,1.633031 2.117597,2.004151 0.471884,0.239121 0.615985,0.262464 1.321663,0.214096 2.354093,-0.161353 3.365104,-1.685375 3.19599,-4.817713 -0.03415,-0.632474 -0.232806,-2.135266 -0.441465,-3.339536 -0.679615,-3.922395 -0.689251,-4.084539 -0.824012,-13.867361 -0.01738,-1.261617 -0.06525,-2.374361 -0.106387,-2.472764 -0.05861,-0.140199 0.124744,-0.0924 0.84733,0.220917 1.919334,0.832222 3.937271,1.375916 5.679096,1.530121 l 0.794874,0.07037 -0.414173,0.414173 c -0.526913,0.526912 -0.956452,1.454655 -1.195989,2.583164 -0.295217,1.39083 -0.250663,5.093945 0.114785,9.540327 0.238753,2.904873 0.282279,3.931023 0.241039,5.68249 -0.05886,2.499602 -0.206448,3.220069 -0.957579,4.674396 -1.558396,3.017343 -4.222293,4.49743 -7.508765,4.171942 z"
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.104266" /><path
id="path917"
d="m 53.591566,29.761694 c 0,-0.03612 0.09315,-0.377943 0.207004,-0.759596 0.734444,-2.461979 0.679593,-5.291878 -0.141586,-7.304807 -0.956968,-2.345782 -3.124331,-4.439793 -6.054027,-5.849133 -2.576132,-1.239256 -5.828787,-2.070447 -9.859803,-2.519596 -1.809858,-0.20166 -7.265169,-0.171342 -9.279663,0.05157 -6.204926,0.686607 -11.322453,2.186475 -14.595817,4.277808 -0.314632,0.201018 -0.587492,0.350051 -0.606356,0.331187 -0.074,-0.074 0.641349,-1.355111 1.295036,-2.31925 3.289046,-4.851102 8.99613,-8.3620988 15.566879,-9.576741 3.65383,-0.6754324 7.441625,-0.4654261 10.686031,0.5924645 1.439666,0.4694263 2.455868,0.9869658 4.128235,2.1024625 4.92363,3.284143 8.882307,7.481577 10.642178,11.284035 1.285177,2.77681 1.292948,5.437442 0.02201,7.535411 -0.585813,0.967015 -2.010122,2.493402 -2.010122,2.154183 z"
style="fill:#4e595f;fill-opacity:1;stroke-width:0.104266" /><path
id="path919"
d="m 50.123834,30.254164 c -0.100845,-0.0399 -0.632062,-0.891655 -1.180483,-1.892785 -0.54842,-1.00113 -1.289411,-2.267206 -1.646648,-2.813502 -0.357236,-0.546295 -0.732559,-1.204403 -0.83405,-1.462461 -0.657522,-1.671846 -1.615336,-2.997145 -3.306173,-4.574654 -1.143669,-1.067016 -1.387477,-1.241714 -2.429945,-1.741154 -2.03795,-0.976369 -3.947244,-1.399028 -6.319889,-1.399028 -3.655857,0 -6.681054,1.161315 -8.95888,3.439142 -0.390609,0.390607 -0.860567,0.919583 -1.044354,1.175501 l -0.334157,0.465305 -1.478254,0.05945 c -2.053627,0.0826 -3.2152,0.433446 -4.306334,1.300717 -0.726052,0.577092 -1.016585,1.186849 -0.957132,2.008782 0.03561,0.492297 0.108962,0.69814 0.360194,1.010787 0.355478,0.442376 1.429806,1.036615 2.081372,1.151262 l 0.428874,0.07546 -0.530428,1.37547 c -0.399491,1.035935 -0.582573,1.389481 -0.741671,1.432232 -0.405858,0.109057 -1.211531,0.05833 -1.590858,-0.100163 -1.130942,-0.472538 -2.38385,-1.926808 -3.309217,-3.841063 -1.043836,-2.159325 -1.460147,-3.864225 -1.390243,-5.6934 0.0564,-1.475757 0.217649,-1.782089 1.304447,-2.47808 4.52876,-2.900242 12.766469,-4.687599 20.62304,-4.474636 5.308389,0.143892 9.407956,0.982927 12.869464,2.633921 3.842502,1.832712 6.081214,4.449477 6.675071,7.802295 0.252386,1.424929 0.07669,3.596454 -0.432937,5.350877 -0.214762,0.739332 -0.229187,0.758823 -0.644338,0.870611 -1.380475,0.371723 -2.470908,0.491444 -2.906471,0.319107 z"
style="fill:#000000;fill-opacity:1;stroke-width:0.104266" /><path
id="path921"
d="m 26.534572,26.993447 c -1.595431,-0.452756 -1.732326,-0.458843 -3.38864,-0.150679 -1.177941,0.219161 -2.979364,0.176973 -3.82717,-0.08963 -1.120411,-0.352326 -1.907453,-1.203012 -1.907453,-2.061701 0,-1.651129 2.015933,-2.910989 4.952629,-3.09515 1.173341,-0.07358 1.615692,-0.0374 3.545039,0.289971 2.380703,0.403955 3.193038,0.677597 3.895503,1.31223 0.589645,0.53271 0.782974,1.099257 0.723817,2.121143 -0.05554,0.959527 -0.298736,1.518867 -0.812038,1.867694 -0.534452,0.3632 -1.405721,0.310109 -3.181687,-0.193878 z"
style="fill:#4e595f;fill-opacity:1;stroke-width:0.104266" /><path
id="path923"
d="M 46.188689,29.297886 C 45.701246,29.080623 44.734882,28.724033 44.041214,28.505463 L 42.779997,28.108064 42.547268,27.0612 c -0.367291,-1.652151 -0.85657,-2.568746 -1.960451,-3.672627 -1.701052,-1.701053 -4.248385,-2.643901 -6.753634,-2.499734 -0.573462,0.033 -1.324176,0.133798 -1.668253,0.223994 -0.840302,0.220275 -2.011068,0.782671 -2.472224,1.187571 l -0.376075,0.330199 -0.784285,-0.263276 C 28.100989,22.222525 27.170048,22.009558 26.463588,21.894066 25.757129,21.778575 24.956722,21.63332 24.684907,21.571279 l -0.494209,-0.112803 0.494209,-0.629665 c 1.698222,-2.16368 4.339866,-3.674759 7.318679,-4.186448 1.270961,-0.218321 3.526396,-0.219146 4.808868,-0.0018 1.292775,0.219133 3.003137,0.775347 4.136405,1.345169 0.760002,0.382139 1.140301,0.675866 2.271907,1.754724 0.799164,0.76191 1.564074,1.601247 1.856596,2.037245 0.713833,1.06395 1.478032,2.724479 1.781794,3.871662 0.422632,1.596106 0.634675,4.080247 0.346125,4.054937 -0.07168,-0.0063 -0.529149,-0.189192 -1.016592,-0.406455 z"
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.104266" /><path
id="path925"
d="m 22.363938,31.839918 c -0.344078,-0.140532 -1.249612,-0.471824 -2.012298,-0.736205 -0.79632,-0.276039 -1.370058,-0.52955 -1.347608,-0.595452 0.0215,-0.06312 0.317081,-0.848408 0.656841,-1.74509 l 0.617747,-1.630329 1.303324,-0.04644 c 0.716827,-0.02554 1.70214,-0.131856 2.189583,-0.236252 0.855364,-0.183193 1.876786,-0.162471 1.876786,0.03808 0,0.04351 -0.249885,0.458935 -0.5553,0.923157 -0.305414,0.464223 -0.898854,1.610466 -1.318754,2.547208 -0.4199,0.936742 -0.768241,1.710744 -0.774091,1.720005 -0.0058,0.0093 -0.292153,-0.09814 -0.63623,-0.238675 z"
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.104266" /><path
id="path927"
d="m 22.414732,31.861261 c -0.31614,-0.128793 -1.221588,-0.460309 -2.012107,-0.736702 -0.823805,-0.288031 -1.420348,-0.551305 -1.397577,-0.616795 0.02185,-0.06285 0.315392,-0.847373 0.652314,-1.743396 l 0.612586,-1.629133 1.30766,-0.05472 c 0.719212,-0.03009 1.709651,-0.136418 2.200975,-0.236276 0.906757,-0.184291 1.86973,-0.148395 1.86973,0.0697 0,0.05766 -0.113537,0.254192 -0.252305,0.436741 -0.431226,0.567279 -0.993848,1.626954 -1.69859,3.199219 -0.372714,0.83152 -0.684463,1.519432 -0.692774,1.528693 -0.0083,0.0093 -0.273771,-0.08854 -0.589912,-0.217331 z"
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.104266" /><path
id="path929"
d="m 44.937499,36.386054 c -0.258058,-0.0445 -1.211203,-0.164146 -2.1181,-0.265891 l -1.648904,-0.18499 0.06493,-0.268455 c 0.03571,-0.14765 0.205678,-0.728219 0.377699,-1.290152 0.288229,-0.941544 0.330696,-1.016756 0.541312,-0.958702 0.557516,0.153671 2.17893,1.039474 2.965461,1.620076 0.741086,0.547055 0.845709,0.661879 0.755928,0.829637 -0.05731,0.107088 -0.104203,0.291629 -0.104203,0.410092 0,0.23359 -0.06157,0.241591 -0.834127,0.108385 z"
style="fill:#ed6b21;fill-opacity:1;stroke-width:0.104266" /><path
id="path931"
d="m 42.904314,52.511337 c -2.932693,-0.632088 -5.038855,-1.704993 -6.642986,-3.384017 -1.412519,-1.478468 -2.012846,-3.140383 -2.134526,-5.909116 -0.06871,-1.563479 0.03909,-2.248069 0.49889,-3.168212 0.378776,-0.757998 0.951273,-1.291674 1.823479,-1.699828 0.943721,-0.441621 2.000438,-0.598226 4.057028,-0.60125 7.48589,-0.01101 11.758325,1.445143 12.835036,4.374498 0.612957,1.667643 -0.425455,5.157963 -2.189672,7.359948 -2.174521,2.714101 -4.959473,3.736596 -8.247249,3.027977 z m 0.131319,-2.839529 c 0.244264,-0.02988 0.822819,-0.243873 1.285678,-0.475542 2.380074,-1.191265 3.34156,-3.652001 2.397622,-6.136245 -0.693333,-1.824706 -2.211432,-3.133221 -3.993342,-3.442036 -2.850628,-0.49403 -5.913352,2.0991 -5.919593,5.011968 -0.004,1.889485 1.1862,3.815593 2.873043,4.649276 1.00906,0.498704 1.765643,0.587193 3.356592,0.392579 z"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.104266" /><path
id="path933"
d="M 14.022668,47.069341 C 10.366037,46.383187 8.0926808,44.573506 7.3510665,41.758481 7.1259269,40.903895 7.0362648,38.651765 7.1767225,37.379315 7.5998889,33.545718 9.201248,31.360352 11.883045,30.956621 c 1.930474,-0.290624 6.328855,0.434143 9.132939,1.504928 3.560735,1.359724 5.591281,3.133412 5.977213,5.22111 0.100711,0.544793 0.08574,0.684966 -0.147315,1.379218 -1.230784,3.666446 -4.356388,6.742 -7.946008,7.818774 -0.773239,0.231946 -1.157562,0.279982 -2.479091,0.309856 -1.086799,0.02457 -1.818489,-0.0124 -2.398115,-0.121166 z m 5.161161,-2.332388 c 0.75189,-0.126086 2.06879,-0.848758 2.835073,-1.555799 1.974831,-1.822154 1.897673,-4.78598 -0.178805,-6.868402 -1.787781,-1.792897 -4.037134,-2.082777 -6.193591,-0.798182 -1.578022,0.940022 -2.572959,2.850383 -2.349706,4.511625 0.32364,2.408233 1.860133,4.177051 4.039868,4.650716 0.796056,0.172986 1.112326,0.183266 1.847161,0.06004 z"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.104266" /></svg>

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="notification_documentation.svg"
xml:space="preserve"
style="enable-background:new 0 0 100 100;"
viewBox="0 0 100 100"
y="0px"
x="0px"
id="minimalize_window"
version="1.1"><metadata
id="metadata23"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs21" /><sodipodi:namedview
inkscape:current-layer="minimalize_window"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="-8"
inkscape:cy="50"
inkscape:cx="50"
inkscape:zoom="10.08"
showgrid="false"
id="namedview19"
inkscape:window-height="1377"
inkscape:window-width="2560"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<style
id="style2"
type="text/css">
.st0{fill:#ED6B21;}
.st1{fill:#EB6B21;}
.st2{fill:none;stroke:#ED6B21;stroke-width:2.8346;stroke-miterlimit:10;}
</style>
<g
id="g6">
<path
id="path4"
d="M80,92.8H20c-7.1,0-12.8-5.8-12.8-12.8V20c0-7.1,5.8-12.8,12.8-12.8h60c7.1,0,12.8,5.8,12.8,12.8v60 C92.8,87.1,87.1,92.8,80,92.8z M20,12.8c-4,0-7.2,3.2-7.2,7.2v60c0,3.9,3.2,7.2,7.2,7.2h60c3.9,0,7.2-3.2,7.2-7.2V20 c0-4-3.2-7.2-7.2-7.2H20z"
class="st0" />
</g>
<g
id="g10">
<path
id="path8"
d="M31.9,67.7H65c0.1,0,0.2,0,0.3,0c0,0,0,0,0,0c0.7,0,1.3-0.6,1.3-1.3V47.9C57.1,50.8,51.6,43.4,47,36 c-1.8-2.7,2-4.6,2.8-7.1H33.9h-2c-3.4,0-6.2,2.8-6.2,6.2c0,0,0,0.1,0,0.1c0,3.1,0,32.1,0,35.9c0,0.1,0,0.1,0,0.2 c0,3.3,2.6,6,5.8,6.2c0.1,0,0.1,0,0.2,0h33.6c0.7,0,1.3-0.6,1.3-1.3v-4.8c0-0.7-0.6-1.3-1.3-1.3c-0.7,0-1.3,0.6-1.3,1.3v3.5H31.9 c-1.9,0-3.5-1.5-3.6-3.5c0,0,0-0.1,0-0.1c0-0.1,0-0.1,0-0.3C28.4,69.2,29.9,67.7,31.9,67.7z M32.7,35.1c0-0.7,0.6-1.3,1.3-1.3 c0.7,0,1.3,0.6,1.3,1.3v26c0,0.7-0.6,1.3-1.3,1.3c-0.7,0-1.3-0.6-1.3-1.3V35.1z"
class="st1" />
</g>
<polygon
id="polygon12"
points="71.1,19.8 54.9,19.8 46.9,33.8 54.9,47.8 71.1,47.8 79.2,33.8 "
class="st2" />
<g
id="g16">
<path
id="path14"
d="M59.6,31.6c1.6-0.4,2.9-0.6,3.8-0.6c0.6,0,1,0.1,1.4,0.3c0.3,0.2,0.5,0.5,0.5,1c0,0.2,0,0.4-0.1,0.5l-1.7,8.3 c0,0.2-0.1,0.4-0.1,0.5c0,0.4,0.1,0.6,0.4,0.7c0.3,0.1,0.8,0.2,1.6,0.2l-0.1,0.6c-1.5,0.4-2.7,0.6-3.6,0.6c-0.7,0-1.2-0.1-1.5-0.4 c-0.4-0.3-0.5-0.6-0.5-1.2c0-0.2,0-0.6,0.1-0.9l1.6-7.6c0.1-0.4,0.1-0.6,0.1-0.7c0-0.2-0.1-0.4-0.3-0.5s-0.8-0.1-1.7-0.1L59.6,31.6 z M66.2,26.3c0,0.6-0.2,1.1-0.6,1.5s-0.8,0.6-1.4,0.6c-0.5,0-1-0.2-1.3-0.5s-0.5-0.8-0.5-1.3c0-0.6,0.2-1.1,0.6-1.5 c0.4-0.4,0.8-0.5,1.4-0.5c0.5,0,1,0.2,1.3,0.5C66,25.3,66.2,25.7,66.2,26.3z"
class="st0" />
</g>
<path
id="path25"
d="M 18.75,92.696085 C 16.846525,92.418222 15.645289,92.057103 14.248486,91.342827 10.768164,89.563113 8.3399658,86.370876 7.4768461,82.440476 7.2982304,81.627112 7.2916667,80.477245 7.2916667,50 c 0,-30.186048 0.00806,-31.633856 0.1805113,-32.417478 C 8.6132236,12.397531 12.392318,8.6115694 17.559524,7.4768461 18.372888,7.2982304 19.522755,7.2916667 50,7.2916667 c 30.186048,0 31.633856,0.00806 32.417478,0.1805113 3.232976,0.7114715 5.949953,2.4425305 7.826838,4.98669 1.078165,1.461476 1.917759,3.360629 2.286745,5.172592 0.168029,0.825133 0.177272,2.515491 0.177272,32.418143 0,30.365281 -0.0069,31.579027 -0.184138,32.385657 -0.592788,2.697863 -1.665191,4.687627 -3.53325,6.555685 -1.820587,1.820588 -3.639881,2.823244 -6.352056,3.500774 l -0.843254,0.210654 -31.39881,0.01496 C 33.12748,92.725556 18.886409,92.716002 18.75,92.696085 Z m 63.033409,-5.68899 c 2.670161,-0.682912 4.81496,-2.945768 5.315692,-5.608285 0.08202,-0.436105 0.104156,-8.923253 0.08281,-31.746032 L 87.152778,18.501984 86.882499,17.708333 C 86.496691,16.575445 85.97299,15.736341 85.118324,14.881675 84.26366,14.02701 83.424556,13.503308 82.291667,13.117501 L 81.498016,12.847222 H 50 18.501984 l -0.793651,0.270279 c -1.132888,0.385807 -1.971992,0.909509 -2.826658,1.764174 -0.854665,0.854666 -1.378367,1.69377 -1.764174,2.826658 l -0.270279,0.793651 -0.02736,31.200397 c -0.0307,35.008562 -0.09842,31.873352 0.723863,33.513124 0.958398,1.911204 2.60508,3.255124 4.642945,3.789286 0.689685,0.180778 1.691694,0.186837 31.772663,0.192128 30.5793,0.0054 31.07235,0.0024 31.82408,-0.189824 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
id="path27"
d="M 31.10119,77.410956 C 29.236131,77.16359 27.26527,75.760742 26.456573,74.104943 25.743058,72.644028 25.793651,74.24 25.793651,53.192882 c 0,-21.105337 -0.05179,-19.498035 0.673442,-20.901215 0.516693,-0.999701 1.719795,-2.185863 2.699574,-2.661563 1.41717,-0.688061 1.004089,-0.66185 10.430458,-0.66185 h 8.503851 l 3.004296,-5.257937 3.004296,-5.257936 h 8.891965 8.891965 l 4.392702,7.595571 c 2.415987,4.177565 4.398432,7.65483 4.405434,7.727255 0.007,0.07243 -1.973876,3.572492 -4.401951,7.777925 l -4.414683,7.646241 -2.65377,0.0035 -2.65377,0.0035 v 8.690364 c 0,9.52089 0.02413,9.12352 -0.578983,9.532993 -0.251764,0.17093 -1.088238,0.181768 -17.674985,0.229024 l -17.410714,0.0496 -0.545635,0.26067 c -0.808178,0.386097 -1.334723,0.894639 -1.70493,1.646635 -0.956715,1.943364 -0.03137,4.335797 1.966064,5.083131 0.535211,0.200248 0.68474,0.202025 17.004492,0.202025 h 16.464533 v -1.970748 c 0,-1.848306 0.01287,-1.987112 0.207172,-2.234125 0.246407,-0.313256 0.686109,-0.557032 1.004726,-0.557032 0.370158,0 0.891455,0.335976 1.086984,0.700561 0.162558,0.303108 0.181276,0.610677 0.181276,2.978657 0,2.58018 -0.0052,2.648365 -0.225191,2.977738 -0.123856,0.1854 -0.380553,0.415147 -0.570437,0.510549 -0.32502,0.163295 -1.341884,0.172595 -17.359134,0.158746 -9.357638,-0.0081 -17.147817,-0.03247 -17.311508,-0.05418 z m 3.7961,-15.349752 0.370567,-0.339589 0.02942,-13.474895 c 0.03317,-15.191489 0.09901,-13.919802 -0.741808,-14.326836 -0.714682,-0.345971 -1.475711,-0.06077 -1.77979,0.666999 -0.209076,0.500389 -0.203248,26.569953 0.0061,27.070877 0.19169,0.458779 0.677232,0.742196 1.272308,0.742663 0.400151,2.97e-4 0.529552,-0.05174 0.843254,-0.339219 z m 39.069271,-21.92944 c 1.987042,-3.435962 3.612804,-6.287187 3.612804,-6.336054 0,-0.04887 -1.638286,-2.918428 -3.640635,-6.376803 l -3.640635,-6.287955 -7.296865,10e-4 -7.296865,0.001 -3.521825,6.16072 c -1.937004,3.388396 -3.561749,6.244218 -3.610545,6.346273 -0.07048,0.147404 0.651296,1.481256 3.510617,6.487682 l 3.599337,6.302129 7.335903,-0.02543 7.335903,-0.02543 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
id="path29"
d="m 60.760765,43.552387 c -0.165409,-0.05195 -0.442153,-0.232699 -0.614986,-0.401675 -0.568258,-0.555577 -0.556378,-0.699058 0.458545,-5.537922 0.499397,-2.380983 0.907009,-4.491004 0.905804,-4.688936 -0.0031,-0.504502 -0.187277,-0.612246 -1.131453,-0.661803 l -0.817141,-0.04289 0.04188,-0.285344 c 0.04934,-0.336185 0.171481,-0.37906 1.942233,-0.681785 1.404394,-0.240093 2.132279,-0.2524 2.821555,-0.04771 0.613954,0.182325 0.859926,0.494928 0.849606,1.079751 -0.0039,0.222429 -0.415921,2.361006 -0.915544,4.752394 -0.885195,4.236877 -0.985384,4.85158 -0.830464,5.09522 0.114081,0.179414 0.50949,0.301375 1.225775,0.378083 0.616868,0.06606 0.646862,0.08131 0.603738,0.306901 -0.04922,0.257458 -0.168385,0.303858 -1.51063,0.588184 -0.90986,0.192734 -2.619763,0.276018 -3.028918,0.147529 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
id="path31"
d="m 63.669778,28.27496 c -0.763916,-0.230278 -1.194145,-0.869586 -1.183525,-1.758685 0.0075,-0.627237 0.328621,-1.275203 0.77853,-1.570898 0.617142,-0.405606 1.675768,-0.348886 2.29435,0.122929 1.508376,1.150494 -0.03285,3.766287 -1.889355,3.206654 z"
style="fill:#ed6b21;stroke-width:0.0992064" /></svg>

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="minimalize_window"
x="0px"
y="0px"
viewBox="0 0 100 100"
style="enable-background:new 0 0 100 100;"
xml:space="preserve"
sodipodi:docname="notification_documentation_hover.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
id="metadata23"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs21" /><sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1377"
id="namedview19"
showgrid="false"
inkscape:zoom="10.08"
inkscape:cx="50"
inkscape:cy="50"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="minimalize_window" />
<style
type="text/css"
id="style2">
.st0{fill:#ED6B21;}
.st1{fill:#EB6B21;}
.st2{fill:none;stroke:#ED6B21;stroke-width:2.8346;stroke-miterlimit:10;}
</style>
<g
id="g6"
transform="matrix(1.15,0,0,1.15,-7.5,-7.5)">
<path
class="st0"
d="M 80,92.8 H 20 C 12.9,92.8 7.2,87 7.2,80 V 20 C 7.2,12.9 13,7.2 20,7.2 h 60 c 7.1,0 12.8,5.8 12.8,12.8 v 60 c 0,7.1 -5.7,12.8 -12.8,12.8 z m -60,-80 c -4,0 -7.2,3.2 -7.2,7.2 v 60 c 0,3.9 3.2,7.2 7.2,7.2 h 60 c 3.9,0 7.2,-3.2 7.2,-7.2 V 20 C 87.2,16 84,12.8 80,12.8 Z"
id="path4" />
</g>
<g
id="g10"
transform="matrix(1.15,0,0,1.15,-7.5,-7.5)">
<path
class="st1"
d="M 31.9,67.7 H 65 c 0.1,0 0.2,0 0.3,0 0,0 0,0 0,0 0.7,0 1.3,-0.6 1.3,-1.3 V 47.9 C 57.1,50.8 51.6,43.4 47,36 c -1.8,-2.7 2,-4.6 2.8,-7.1 h -15.9 -2 c -3.4,0 -6.2,2.8 -6.2,6.2 0,0 0,0.1 0,0.1 0,3.1 0,32.1 0,35.9 0,0.1 0,0.1 0,0.2 0,3.3 2.6,6 5.8,6.2 0.1,0 0.1,0 0.2,0 h 33.6 c 0.7,0 1.3,-0.6 1.3,-1.3 v -4.8 c 0,-0.7 -0.6,-1.3 -1.3,-1.3 -0.7,0 -1.3,0.6 -1.3,1.3 v 3.5 H 31.9 c -1.9,0 -3.5,-1.5 -3.6,-3.5 0,0 0,-0.1 0,-0.1 0,-0.1 0,-0.1 0,-0.3 0.1,-1.8 1.6,-3.3 3.6,-3.3 z m 0.8,-32.6 c 0,-0.7 0.6,-1.3 1.3,-1.3 0.7,0 1.3,0.6 1.3,1.3 v 26 c 0,0.7 -0.6,1.3 -1.3,1.3 -0.7,0 -1.3,-0.6 -1.3,-1.3 z"
id="path8" />
</g>
<polygon
class="st2"
points="54.9,19.8 46.9,33.8 54.9,47.8 71.1,47.8 79.2,33.8 71.1,19.8 "
id="polygon12"
transform="matrix(1.15,0,0,1.15,-7.5,-7.5)" />
<g
id="g16"
transform="matrix(1.15,0,0,1.15,-7.5,-7.5)">
<path
class="st0"
d="m 59.6,31.6 c 1.6,-0.4 2.9,-0.6 3.8,-0.6 0.6,0 1,0.1 1.4,0.3 0.3,0.2 0.5,0.5 0.5,1 0,0.2 0,0.4 -0.1,0.5 l -1.7,8.3 c 0,0.2 -0.1,0.4 -0.1,0.5 0,0.4 0.1,0.6 0.4,0.7 0.3,0.1 0.8,0.2 1.6,0.2 l -0.1,0.6 c -1.5,0.4 -2.7,0.6 -3.6,0.6 -0.7,0 -1.2,-0.1 -1.5,-0.4 -0.4,-0.3 -0.5,-0.6 -0.5,-1.2 0,-0.2 0,-0.6 0.1,-0.9 l 1.6,-7.6 c 0.1,-0.4 0.1,-0.6 0.1,-0.7 0,-0.2 -0.1,-0.4 -0.3,-0.5 -0.2,-0.1 -0.8,-0.1 -1.7,-0.1 z m 6.6,-5.3 c 0,0.6 -0.2,1.1 -0.6,1.5 -0.4,0.4 -0.8,0.6 -1.4,0.6 -0.5,0 -1,-0.2 -1.3,-0.5 -0.3,-0.3 -0.5,-0.8 -0.5,-1.3 0,-0.6 0.2,-1.1 0.6,-1.5 0.4,-0.4 0.8,-0.5 1.4,-0.5 0.5,0 1,0.2 1.3,0.5 0.3,0.2 0.5,0.6 0.5,1.2 z"
id="path14" />
</g>
<path
id="path15"
d="M 14.048833,99.095468 C 10.758797,98.776287 7.5585129,97.246225 5.156144,94.843856 2.702378,92.39009 1.2229673,89.248663 0.90064133,85.807586 c -0.14895496,-1.590207 -0.14895496,-70.024965 0,-71.615172 C 1.5626661,7.1247937 7.1461659,1.5575143 14.236111,0.89568416 c 1.551488,-0.14482788 70.023035,-0.14008542 71.571475,0.004957 4.714923,0.44164734 8.90055,3.11165724 11.36025,7.24669874 1.053844,1.7716328 1.752116,4.0052851 1.940273,6.2065901 0.07688,0.899426 0.09971,11.568412 0.07809,36.489324 -0.02915,33.604835 -0.03884,35.26143 -0.211522,36.160714 -0.593346,3.090004 -1.947825,5.664097 -4.12722,7.843492 -2.179385,2.179385 -4.753372,3.533814 -7.843492,4.127235 -0.900554,0.172942 -2.523851,0.181552 -36.507936,0.193651 -19.561012,0.007 -35.962251,-0.02583 -36.447199,-0.07288 z m 71.469642,-6.342539 c 3.509574,-0.435077 6.434988,-3.150322 7.155917,-6.641818 0.109946,-0.532474 0.133148,-6.842325 0.133148,-36.210317 V 14.335317 L 92.58317,13.492063 C 91.76058,10.400506 89.599494,8.2394197 86.507937,7.4168301 L 85.664683,7.1924603 H 50 14.335317 L 13.492063,7.4168301 C 10.424882,8.2329338 8.2941745,10.346391 7.4172519,13.44246 l -0.2247916,0.793651 -0.029436,35.119048 c -0.020768,24.777514 0.00225,35.396574 0.078183,36.061508 0.432718,3.78947 3.4199857,6.848151 7.1628477,7.334081 0.970581,0.12601 70.098451,0.128129 71.114421,0.0022 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
id="path17"
d="m 27.402334,81.347356 c -2.46563,-0.645993 -4.441405,-2.667097 -5.08098,-5.19755 -0.195316,-0.772763 -0.198338,-1.11524 -0.198338,-22.479171 0,-21.262694 0.0039,-21.709667 0.195519,-22.458924 0.630167,-2.46393 2.411238,-4.32372 4.963211,-5.182573 0.512441,-0.172459 1.154556,-0.186717 10.55483,-0.23436 l 10.009195,-0.05073 3.433266,-6.023277 3.433265,-6.023276 10.227283,-0.0035 10.227284,-0.0035 4.947674,8.556548 c 2.72122,4.706101 5.022042,8.690476 5.112937,8.854166 l 0.165263,0.29762 -5.085935,8.779761 -5.085937,8.779762 -3.085249,0.02621 -3.08525,0.02621 -0.02618,10.15999 c -0.02599,10.086364 -0.02766,10.161975 -0.230721,10.433928 -0.112498,0.150664 -0.327816,0.365981 -0.478485,0.478479 l -0.273943,0.204542 -20.007625,0.0496 -20.007626,0.0496 -0.64532,0.30517 c -0.863407,0.408303 -1.610615,1.150455 -2.012489,1.998871 -0.297084,0.627187 -0.318048,0.74183 -0.313398,1.713816 0.0041,0.850376 0.04647,1.141866 0.230898,1.587301 0.503415,1.215869 1.462305,2.105354 2.676354,2.482637 0.61847,0.1922 0.988675,0.195935 19.419643,0.195935 h 18.789153 v -2.217472 c 0,-2.136287 0.0082,-2.229479 0.223214,-2.545442 0.333394,-0.489856 0.678773,-0.704629 1.143441,-0.711041 0.472685,-0.0065 0.949227,0.238892 1.251943,0.644742 0.200471,0.26877 0.209871,0.405024 0.236118,3.422619 0.02536,2.915086 0.01385,3.167854 -0.15889,3.489927 -0.102423,0.190972 -0.33338,0.447669 -0.513236,0.570437 l -0.327012,0.223214 -19.950606,-0.0055 c -19.303761,-0.0053 -19.974038,-0.0116 -20.673273,-0.194797 z m 4.918865,-17.249815 c 0.21646,-0.110429 0.46075,-0.351687 0.591286,-0.583944 l 0.222436,-0.395771 -0.0016,-15.313873 -0.0016,-15.313874 -0.221583,-0.386498 c -0.57383,-1.000911 -2.022858,-1.00842 -2.605918,-0.0135 l -0.244632,0.417435 V 47.812673 63.11783 l 0.209179,0.372185 c 0.407473,0.725 1.302779,0.990007 2.052496,0.60753 z M 76.611628,40.277778 c 1.786692,-3.082838 3.676401,-6.349242 4.199352,-7.258677 l 0.95082,-1.653518 -4.19361,-7.250805 -4.193609,-7.250805 -8.434517,0.02535 -8.434516,0.02536 -4.093798,7.142857 c -2.547059,4.444106 -4.082321,7.220788 -4.063423,7.349119 0.03558,0.241604 8.073435,14.342072 8.237262,14.45028 0.06096,0.04027 3.86084,0.06259 8.444173,0.0496 l 8.333333,-0.02361 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
id="path19"
d="m 62.103975,42.442311 c -0.622813,-0.321464 -0.893312,-0.762703 -0.895015,-1.459958 -8.07e-4,-0.330477 0.427325,-2.594263 1.056162,-5.58455 1.288645,-6.127847 1.317398,-5.681554 -0.373774,-5.801597 -0.808155,-0.05736 -0.87932,-0.07931 -0.877924,-0.270784 0.0028,-0.3827 0.164573,-0.474726 1.244533,-0.707914 2.655322,-0.573345 4.18941,-0.539022 4.89721,0.109569 0.324612,0.297458 0.354127,0.36998 0.347372,0.853564 -0.0041,0.290667 -0.461556,2.693665 -1.01666,5.339994 -0.555103,2.646329 -1.036614,5.017302 -1.070022,5.268827 -0.11023,0.829884 0.170767,1.055853 1.449222,1.165421 l 0.744048,0.06377 -0.03233,0.296879 c -0.01778,0.163282 -0.0401,0.303981 -0.0496,0.312662 -0.0095,0.0087 -0.552989,0.138865 -1.207751,0.289294 -0.864367,0.198586 -1.54376,0.284648 -2.480158,0.314172 -1.198015,0.03777 -1.321357,0.02431 -1.735311,-0.189347 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
id="path21"
d="m 65.653905,25.00115 c -1.412607,-0.425822 -1.792539,-2.40789 -0.681087,-3.553165 0.738955,-0.761443 1.931874,-0.828272 2.893189,-0.16208 0.479355,0.332193 0.68558,0.775979 0.68558,1.47533 0,0.66711 -0.157427,1.080128 -0.606778,1.591911 -0.565433,0.643992 -1.462474,0.897729 -2.290904,0.648004 z"
style="fill:#ed6b21;stroke-width:0.0992064" /><path
style="fill:#000000;fill-opacity:0;stroke-width:0.0992064"
d="m 56.2668,45.16369 c -0.213828,-0.368303 -2.006867,-3.504464 -3.984532,-6.969246 -1.977664,-3.464781 -3.665189,-6.419326 -3.750055,-6.565655 -0.152861,-0.263568 -0.115931,-0.333262 3.955354,-7.464657 l 4.109655,-7.198605 8.365484,0.02418 8.365485,0.02418 4.155528,7.183237 c 2.414733,4.174103 4.125947,7.233027 4.084913,7.302091 -0.03884,0.06537 -1.922726,3.317288 -4.186416,7.226485 l -4.115798,7.107631 h -8.305421 -8.30542 z m 9.060581,-2.54511 c 0.381944,-0.07091 1.057974,-0.209062 1.502288,-0.307016 0.805389,-0.177555 0.808018,-0.179166 0.864998,-0.530295 0.03143,-0.193709 0.03824,-0.371112 0.01513,-0.394228 -0.02312,-0.02312 -0.390044,-0.07712 -0.815395,-0.120015 -1.267326,-0.127799 -1.521223,-0.342968 -1.372926,-1.163511 0.03691,-0.204255 0.516108,-2.536551 1.064875,-5.18288 0.548766,-2.646329 1.016471,-4.990079 1.039344,-5.208333 0.128191,-1.223204 -1.101585,-1.796204 -3.302095,-1.538575 -0.912954,0.106886 -3.201538,0.552099 -3.289335,0.639896 -0.02147,0.02147 -0.06257,0.214441 -0.09132,0.428823 l -0.05228,0.389786 0.967632,0.05773 c 1.140886,0.06807 1.29529,0.164771 1.268794,0.79465 -0.0097,0.229992 -0.467226,2.546734 -1.016782,5.148317 -1.027858,4.865846 -1.126212,5.58727 -0.843081,6.183925 0.142543,0.300386 0.665851,0.741863 1.034364,0.872619 0.292418,0.103755 2.343938,0.05569 3.025794,-0.07089 z M 67.07349,25.083729 c 0.915135,-0.311219 1.577304,-1.268088 1.577304,-2.279289 0,-0.651129 -0.118532,-1.027765 -0.428235,-1.360722 -0.523722,-0.563041 -1.606209,-0.838493 -2.42525,-0.617133 -1.308437,0.353627 -1.971739,2.041196 -1.30878,3.329792 0.438649,0.852604 1.590098,1.265685 2.584961,0.927352 z"
id="path18" /><path
id="path20"
d="m 56.2668,45.16369 c -0.213828,-0.368303 -2.006867,-3.504464 -3.984532,-6.969246 -1.977664,-3.464781 -3.665189,-6.419326 -3.750055,-6.565655 -0.152861,-0.263568 -0.115931,-0.333262 3.955354,-7.464657 l 4.109655,-7.198605 8.365484,0.02418 8.365485,0.02418 4.155528,7.183237 c 2.414733,4.174103 4.125947,7.233027 4.084913,7.302091 -0.03884,0.06537 -1.922726,3.317288 -4.186416,7.226485 l -4.115798,7.107631 h -8.305421 -8.30542 z m 9.060581,-2.54511 c 0.381944,-0.07091 1.057974,-0.209062 1.502288,-0.307016 0.805389,-0.177555 0.808018,-0.179166 0.864998,-0.530295 0.03143,-0.193709 0.03824,-0.371112 0.01513,-0.394228 -0.02312,-0.02312 -0.390044,-0.07712 -0.815395,-0.120015 -1.267326,-0.127799 -1.521223,-0.342968 -1.372926,-1.163511 0.03691,-0.204255 0.516108,-2.536551 1.064875,-5.18288 0.548766,-2.646329 1.016471,-4.990079 1.039344,-5.208333 0.128191,-1.223204 -1.101585,-1.796204 -3.302095,-1.538575 -0.912954,0.106886 -3.201538,0.552099 -3.289335,0.639896 -0.02147,0.02147 -0.06257,0.214441 -0.09132,0.428823 l -0.05228,0.389786 0.967632,0.05773 c 1.140886,0.06807 1.29529,0.164771 1.268794,0.79465 -0.0097,0.229992 -0.467226,2.546734 -1.016782,5.148317 -1.027858,4.865846 -1.126212,5.58727 -0.843081,6.183925 0.142543,0.300386 0.665851,0.741863 1.034364,0.872619 0.292418,0.103755 2.343938,0.05569 3.025794,-0.07089 z M 67.07349,25.083729 c 0.915135,-0.311219 1.577304,-1.268088 1.577304,-2.279289 0,-0.651129 -0.118532,-1.027765 -0.428235,-1.360722 -0.523722,-0.563041 -1.606209,-0.838493 -2.42525,-0.617133 -1.308437,0.353627 -1.971739,2.041196 -1.30878,3.329792 0.438649,0.852604 1.590098,1.265685 2.584961,0.927352 z"
style="fill:#000000;fill-opacity:0;stroke-width:0.0992064" /></svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, 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"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path fill="#808080" d="M13,14.5H3.5c-0.55,0-1-0.45-1-1V13c0-1.98,1.31-2.5,2-2.5h2c-0.46,0-1-0.43-1-2.5V7c0-1.98,1.31-2.5,2-2.5
h1c0.69,0,2,0.52,2,2.5v1c0,2.07-0.54,2.5-1,2.5h2c0.69,0,2,0.52,2,2.5v1C13.5,14.28,13.28,14.5,13,14.5z M4.5,11.5
c-0.16,0-1,0.1-1,1.5v0.5h9V13c0-1.48-0.96-1.5-1-1.5h-2c-0.55,0-1-0.45-1-1c0-0.49,0.35-0.89,0.81-0.98C9.37,9.39,9.5,9,9.5,8V7
c0-1.48-0.96-1.5-1-1.5h-1c-0.16,0-1,0.1-1,1.5v1c0,1,0.13,1.39,0.19,1.52c0.46,0.09,0.81,0.5,0.81,0.98c0,0.55-0.45,1-1,1H4.5z"/>
<path fill="#ED6B21" d="M13.43,5.49c-0.12-0.24-0.14-0.64-0.05-0.91l0.12-0.35c0.09-0.26,0-0.63-0.2-0.83L12.6,2.7
c-0.19-0.19-0.57-0.28-0.83-0.2l-0.35,0.12c-0.26,0.09-0.67,0.06-0.91-0.05s-1-0.54-1.12-0.79L9.22,1.45C9.1,1.2,8.77,1,8.5,1h-1
C7.22,1,6.9,1.2,6.78,1.45L6.61,1.78C6.49,2.02,6.18,2.3,5.93,2.38S4.84,2.7,4.58,2.62L4.23,2.5C3.97,2.41,3.6,2.5,3.4,2.7L2.7,3.4
C2.5,3.6,2.41,3.97,2.5,4.23l0.12,0.35C2.7,4.84,2.68,5.25,2.57,5.49s-0.54,1-0.79,1.12L1.45,6.78C1.2,6.9,1,7.22,1,7.5v1
c0,0.27,0.2,0.6,0.45,0.72l0.33,0.17c0.25,0.12,0.47,0.28,0.49,0.35S2.58,10,2.86,10h0.06c0.28,0,0.43-0.21,0.34-0.48
C3.27,9.52,3,8.71,3,8c0-2.76,2.24-5,5-5s5,2.24,5,5c0,0.71-0.27,1.52-0.27,1.52C12.65,9.79,12.8,10,13.08,10h0.06
c0.27,0,0.52-0.06,0.55-0.13s0.29-0.36,0.53-0.48l0.33-0.17C14.8,9.1,15,8.77,15,8.5v-1c0-0.28-0.2-0.6-0.45-0.72l-0.33-0.17
C13.98,6.49,13.55,5.72,13.43,5.49z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,79 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="toolbar_arrow1.svg"
id="svg10"
version="1.1"
viewBox="0 0 119.8 298.8"
height="298.8"
width="119.8">
<metadata
id="metadata16">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14" />
<sodipodi:namedview
inkscape:current-layer="svg10"
inkscape:window-maximized="0"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:cy="149.39999"
inkscape:cx="59.900002"
inkscape:zoom="3.3734941"
showgrid="false"
id="namedview12"
inkscape:window-height="1299"
inkscape:window-width="2295"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<line
id="line2"
style="fill: none;stroke: #ed6b21;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 17.007874015748033px"
y2="99.8"
x2="59.2"
y1="290.3"
x1="59.2" />
<line
id="line4"
style="fill: none;stroke: #ed6b21;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 17.007874015748033px"
y2="8.5"
x2="59.2"
y1="96.6"
x1="8.5" />
<line
id="line6"
style="fill: none;stroke: #ed6b21;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 17.007874015748033px"
y2="8.5"
x2="59.2"
y1="96.6"
x1="111.2" />
<line
id="line8"
style="fill: none;stroke: #ed6b21;stroke-linecap: round;stroke-miterlimit: 10;stroke-width: 17.007874015748033px"
y2="96.6"
x2="111.2"
y1="96.6"
x1="8.5" />
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" 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 330 330" style="enable-background:new 0 0 330 330;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{fill:none;stroke:#ED6B21;stroke-width:17.0079;stroke-linecap:round;stroke-miterlimit:10;}
</style>
<path id="XMLID_28_" class="st0" d="M180,315V51.2l49.4,49.4c5.9,5.9,15.4,5.9,21.2,0c5.9-5.9,5.9-15.4,0-21.2l-75-75
c-5.9-5.9-15.4-5.9-21.2,0l-75,75C76.5,82.3,75,86.2,75,90s1.5,7.7,4.4,10.6c5.9,5.9,15.4,5.9,21.2,0L150,51.2V315
c0,8.3,6.7,15,15,15S180,323.3,180,315z"/>
<g id="XMLID_1_">
<g>
</g>
<g>
<polyline class="st1" points="113.6,84.5 164.3,18.3 164.3,18.3 "/>
<polyline class="st1" points="216.4,84.5 164.3,18.3 164.3,18.3 "/>
</g>
</g>
<line class="st1" x1="164.3" y1="263.3" x2="164.3" y2="18.3"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
id="error"
x="0px"
y="0px"
viewBox="0 0 200 200"
enable-background="new 0 0 100 100"
xml:space="preserve"
sodipodi:docname="notification_error.svg"
width="200"
height="200"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
id="metadata19"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs17" /><sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1377"
id="namedview15"
showgrid="false"
inkscape:zoom="5.04"
inkscape:cx="117.17146"
inkscape:cy="98.609664"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="error" />
<g
id="g4"
transform="matrix(2.52,0,0,2.52,-26,-26)">
<path
fill="#FFFFFF"
d="m 50,54.25 c -2.35,0 -4.25,-1.9 -4.25,-4.25 V 35 c 0,-2.35 1.9,-4.25 4.25,-4.25 2.35,0 4.25,1.9 4.25,4.25 v 15 c 0,2.35 -1.9,4.25 -4.25,4.25 z"
id="path2" />
</g>
<g
id="g8"
transform="matrix(2.52,0,0,2.52,-26,-26)">
<circle
fill="#FFFFFF"
cx="50"
cy="65"
r="5"
id="circle6" />
</g>
<g
id="g12"
transform="matrix(2.52,0,0,2.52,-26,-26)">
<path
fill="#FFFFFF"
d="M 50,89.25 C 28.36,89.25 10.75,71.64 10.75,50 10.75,28.36 28.36,10.75 50,10.75 71.64,10.75 89.25,28.36 89.25,50 89.25,71.64 71.64,89.25 50,89.25 Z m 0,-70 C 33.05,19.25 19.25,33.04 19.25,50 19.25,66.95 33.04,80.75 50,80.75 66.95,80.75 80.75,66.96 80.75,50 80.75,33.05 66.95,19.25 50,19.25 Z"
id="path10" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,3 +1,5 @@
min_slic3r_version = 2.3.2-alpha0
0.0.11 Added bed model and texture for i3 Mega, i3 Mega S.
min_slic3r_version = 2.3.1-beta
0.0.10 Various updates for Anycubic Mega. Added filament profiles.
0.0.9 Updated bed textures

View File

@ -5,7 +5,7 @@
name = Anycubic
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.0.10
config_version = 0.0.11
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anycubic/
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -46,12 +46,16 @@ name = Anycubic i3 Mega
variants = 0.4
technology = FFF
family = MEGA
bed_model = i3megas_bed.stl
bed_texture = i3megas.svg
[printer_model:I3MEGAS]
name = Anycubic i3 Mega S
variants = 0.4
technology = FFF
family = MEGA
bed_model = i3megas_bed.stl
bed_texture = i3megas.svg
[printer_model:PREDATOR]
name = Anycubic Predator

View File

@ -1,4 +1,5 @@
min_slic3r_version = 2.4.0-alpha0
1.4.0-alpha6 Added nozzle priming after M600. Added nozzle diameter checks for 0.8 nozzle printer profiles. Updated FW version. Increased number of top solid infill layers (0.2 layer height).
1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
1.4.0-alpha4 Decreased Area Fill (SL1S).
1.4.0-alpha3 Updated SL1S tilt times.
@ -10,7 +11,7 @@ min_slic3r_version = 2.4.0-alpha0
1.3.0-alpha0 Disabled thick bridges, updated support settings.
min_slic3r_version = 2.3.2-alpha0
1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S).
1.3.0 Added SL1S profiles.
1.3.0 Added SL1S SPEED profiles.
min_slic3r_version = 2.3.0-rc1
1.2.8 Added multiple add:north and Extrudr filament profiles.
1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI.
@ -29,6 +30,7 @@ min_slic3r_version = 2.3.0-alpha4
1.2.0-alpha1 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
1.2.0-alpha0 Added filament spool weights
min_slic3r_version = 2.2.0-alpha3
1.1.14 Updated firmware version.
1.1.13 Updated firmware version. Updated end g-code in MMU2 printer profiles.
1.1.12 Added Prusament PVB filament profile. Added 0.8mm nozzle profiles.
1.1.11 Renamed MK3S and MINI printer profiles. Updated end g-code (MINI). Added new SLA materials and filament profiles.
@ -52,6 +54,7 @@ min_slic3r_version = 2.2.0-alpha0
1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles.
1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0
min_slic3r_version = 2.1.1-beta0
1.0.12 Updated firmware version.
1.0.11 Updated firmware version.
1.0.10 Updated firmware version for MK2.5/S and MK3/S.
1.0.9 Updated firmware version for MK2.5/S and MK3/S.
@ -71,6 +74,7 @@ min_slic3r_version = 2.1.0-alpha0
1.0.0-alpha1 Added Prusament ASA profile
1.0.0-alpha0 Filament specific retract for PET and similar copolymers, and for FLEX
min_slic3r_version = 1.42.0-alpha6
0.8.11 Updated firmware version.
0.8.10 Updated firmware version.
0.8.9 Updated firmware version for MK2.5/S and MK3/S.
0.8.8 Updated firmware version for MK2.5/S and MK3/S.

View File

@ -5,7 +5,7 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.4.0-alpha5
config_version = 1.4.0-alpha6
# Where to get the updates from?
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -488,7 +488,7 @@ perimeter_acceleration = 800
perimeter_speed = 50
solid_infill_speed = 50
top_infill_extrusion_width = 0.4
top_solid_layers = 5
top_solid_layers = 6
[print:*0.25mm*]
inherits = *common*
@ -5832,6 +5832,7 @@ printer_model = MK2S
printer_variant = 0.4
default_print_profile = 0.15mm OPTIMAL
default_filament_profile = Prusament PLA
color_change_gcode = M600\nG1 E0.4 F1500 ; prime after color change
[printer:*multimaterial*]
inherits = *common*
@ -5888,6 +5889,7 @@ variable_layer_height = 1
printer_variant = 0.25
retract_lift = 0.15
default_print_profile = 0.10mm DETAIL 0.25 nozzle
color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK2S 0.6 nozzle]
inherits = *common*
@ -5896,6 +5898,7 @@ min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
# XXXXXXXXXXXXXXXXXXX
# XXX--- MK2MM ---XXX
@ -5937,21 +5940,21 @@ inherits = Original Prusa i3 MK2S
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
[printer:Original Prusa i3 MK2.5 0.25 nozzle]
inherits = Original Prusa i3 MK2S 0.25 nozzle
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
[printer:Original Prusa i3 MK2.5 0.6 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle
printer_model = MK2.5
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
[printer:Original Prusa i3 MK2.5 0.8 nozzle]
inherits = Original Prusa i3 MK2S 0.6 nozzle
@ -5963,9 +5966,10 @@ min_layer_height = 0.2
retract_length = 1
remaining_times = 1
machine_max_jerk_e = 4.5
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5 MMU2 Single]
inherits = *25mm2*
@ -5975,7 +5979,7 @@ max_print_height = 200
default_print_profile = 0.15mm OPTIMAL @MK2.5
default_filament_profile = Prusament PLA
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; load to nozzle\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.20 F1000\nG1 X5 E4 F1000\nG92 E0\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\n; select extruder\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; load to nozzle\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.20 F1000\nG1 X5 E4 F1000\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors
[printer:Original Prusa i3 MK2.5 MMU2 Single 0.8 nozzle]
@ -5999,7 +6003,7 @@ printer_notes = Don't remove the following keywords! These keywords are used in
single_extruder_multi_material = 1
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM900 K0 ; reset LA\nM84 ; disable motors\n
[printer:Original Prusa i3 MK2.5S]
@ -6026,7 +6030,7 @@ max_print_height = 200
default_print_profile = 0.15mm OPTIMAL @MK2.5
default_filament_profile = Prusament PLA
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2.5\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM104 S0 ; turn off temperature\nM900 K0 ; reset LA\nM84 ; disable motors
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.8 nozzle]
@ -6037,9 +6041,10 @@ min_layer_height = 0.2
nozzle_diameter = 0.8
printer_variant = 0.8
retract_length = 1
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.6 nozzle]
inherits = Original Prusa i3 MK2.5S MMU2S Single
@ -6049,6 +6054,7 @@ min_layer_height = 0.1
nozzle_diameter = 0.6
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5S MMU2S Single 0.25 nozzle]
inherits = Original Prusa i3 MK2.5S MMU2S Single
@ -6059,7 +6065,8 @@ nozzle_diameter = 0.25
printer_variant = 0.25
retract_lift = 0.15
default_print_profile = 0.10mm DETAIL 0.25 nozzle
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n
color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5S MMU2S]
inherits = *25mm2s*
@ -6070,7 +6077,7 @@ printer_notes = Don't remove the following keywords! These keywords are used in
single_extruder_multi_material = 1
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\nG92 E0\n
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM900 K0 ; reset LA\nM84 ; disable motors\n
[printer:Original Prusa i3 MK2.5S MMU2S 0.6 nozzle]
@ -6080,6 +6087,7 @@ max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK2.5 MMU2 0.6 nozzle]
inherits = Original Prusa i3 MK2.5 MMU2
@ -6088,6 +6096,7 @@ max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
default_print_profile = 0.20mm NORMAL @0.6 nozzle
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
## 0.8mm nozzle profiles are only available for MMU2 Single mode at the moment.
@ -6099,7 +6108,7 @@ default_print_profile = 0.20mm NORMAL @0.6 nozzle
## printer_variant = 0.8
## retract_length = 1
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
## [printer:Original Prusa i3 MK2.5 MMU2 0.8 nozzle]
## inherits = Original Prusa i3 MK2.5 MMU2
@ -6109,7 +6118,7 @@ default_print_profile = 0.20mm NORMAL @0.6 nozzle
## printer_variant = 0.8
## retract_length = 1
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG92 E0.0\n
# XXXXXXXXXXXXXXXXX
# XXX--- MK3 ---XXX
@ -6139,7 +6148,7 @@ remaining_times = 1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209
max_print_height = 210
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
printer_model = MK3
default_print_profile = 0.15mm QUALITY @MK3
@ -6150,8 +6159,9 @@ max_layer_height = 0.15
min_layer_height = 0.05
printer_variant = 0.25
retract_lift = 0.15
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E8 F700 ; intro line\nG1 X100 E12.5 F700 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E8 F700 ; intro line\nG1 X100 E12.5 F700 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
default_print_profile = 0.10mm DETAIL @0.25 nozzle MK3
color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 0.6 nozzle]
inherits = Original Prusa i3 MK3
@ -6159,8 +6169,9 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S{if layer_height<0.075}100{else}95{endif}
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 0.8 nozzle]
inherits = Original Prusa i3 MK3
@ -6169,9 +6180,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S95
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Z0.2 F720\nG1 Y-3 F1000 ; go outside print area\nG92 E0\nG1 X60 E9 F1000 ; intro line\nG1 X100 E12.5 F1000 ; intro line\nG92 E0\nM221 S95
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+]
inherits = Original Prusa i3 MK3
@ -6240,7 +6252,7 @@ default_filament_profile = Prusament PLA @MMU2
inherits = *mm2*
single_extruder_multi_material = 0
default_filament_profile = Prusament PLA
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors
[printer:Original Prusa i3 MK3 MMU2 Single 0.6 nozzle]
@ -6250,8 +6262,9 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2 Single 0.8 nozzle]
inherits = Original Prusa i3 MK3 MMU2 Single 0.6 nozzle
@ -6261,9 +6274,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2 Single 0.25 nozzle]
inherits = Original Prusa i3 MK3 MMU2 Single
@ -6273,15 +6287,16 @@ max_layer_height = 0.15
min_layer_height = 0.05
printer_variant = 0.25
retract_lift = 0.15
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F1000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 E8 F1000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
default_print_profile = 0.10mm DETAIL @0.25 nozzle MK3
color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2]
inherits = *mm2*
machine_max_acceleration_e = 8000,8000
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM84 ; disable motors\n
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single]
@ -6289,7 +6304,7 @@ inherits = *mm2s*
renamed_from = "Original Prusa i3 MK3S MMU2S Single"
single_extruder_multi_material = 0
default_filament_profile = Prusament PLA
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = {if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+10, max_print_height)}{endif} F720 ; Move print head up\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM702 C\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nM84 ; disable motors
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.6 nozzle]
@ -6300,8 +6315,9 @@ nozzle_diameter = 0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.8 nozzle]
inherits = Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.6 nozzle
@ -6311,9 +6327,10 @@ max_layer_height = 0.6
min_layer_height = 0.2
printer_variant = 0.8
retract_length = 1
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.40mm QUALITY @0.8 nozzle
default_filament_profile = Prusament PLA @0.8 nozzle
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S Single 0.25 nozzle]
inherits = Original Prusa i3 MK3S & MK3S+ MMU2S Single
@ -6324,8 +6341,9 @@ max_layer_height = 0.15
min_layer_height = 0.05
printer_variant = 0.25
retract_lift = 0.15
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nTx\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nTc\n; purge line\nG1 X55 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F1400\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E value below. Excessive value can damage the printer.\n{if print_settings_id=~/.*@0.25 nozzle MK3.*/}M907 E430 ; set extruder motor current{endif}
default_print_profile = 0.10mm DETAIL @0.25 nozzle MK3
color_change_gcode = M600\nG1 E0.3 F1500 ; prime after color change
[printer:Original Prusa i3 MK3S & MK3S+ MMU2S]
inherits = *mm2s*
@ -6333,7 +6351,7 @@ renamed_from = "Original Prusa i3 MK3S MMU2S"
machine_max_acceleration_e = 8000,8000
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FF8000;#DB5182;#3EC0FF;#FF4F4F;#FBEB7D
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0\n\n; Don't change E values below. Excessive value can damage the printer.\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE).*/}M907 E430 ; set extruder motor current{endif}\n{if print_settings_id=~/.*(SPEED @MK3|DRAFT @MK3).*/}M907 E538 ; set extruder motor current{endif}
end_gcode = ; Lift print head a bit\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} ; Move print head up\n{if has_wipe_tower}\nG1 E-15 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15 F5800\nG1 E-20 F5500\nG1 E10 F3000\nG1 E-10 F3100\nG1 E10 F3150\nG1 E-10 F3250\nG1 E10 F3300\n{endif}\n\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM221 S100 ; reset flow\nM900 K0 ; reset LA\n{if print_settings_id=~/.*(DETAIL @MK3|QUALITY @MK3|SOLUBLE|@0.25 nozzle MK3).*/}M907 E538 ; reset extruder motor current{endif}\nM104 S0 ; turn off temperature\nG1 X0 Y210 F3000 ; home X axis\nM84 ; disable motors\n
## 0.6mm nozzle MMU2/S printer profiles
@ -6345,8 +6363,9 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E29 F1073\nG1 X5 E29 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
[printer:Original Prusa i3 MK3 MMU2 0.6 nozzle]
inherits = Original Prusa i3 MK3 MMU2
@ -6354,8 +6373,9 @@ nozzle_diameter = 0.6,0.6,0.6,0.6,0.6
max_layer_height = 0.40
min_layer_height = 0.15
printer_variant = 0.6
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55 E32 F1073\nG1 X5 E32 F1800\nG1 X55 E8 F2000\nG1 Z0.3 F1000\nG92 E0\nG1 X240 E25 F2200\nG1 Y-2 F1000\nG1 X55 E25 F1400\nG1 Z0.2 F1000\nG1 X5 E4 F1000\nG92 E0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0
default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
color_change_gcode = M600\nG1 E0.5 F1500 ; prime after color change
## 0.8mm nozzle MMU2/S printer profiles
@ -6367,7 +6387,7 @@ default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
## max_layer_height = 0.6
## min_layer_height = 0.2
## printer_variant = 0.8
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000\nG1 Z0.4 F1000\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
## [printer:Original Prusa i3 MK3S & MK3S+ MMU2S 0.8 nozzle]
@ -6376,7 +6396,7 @@ default_print_profile = 0.30mm QUALITY @0.6 nozzle MK3
## max_layer_height = 0.6
## min_layer_height = 0.2
## printer_variant = 0.8
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM115 U3.9.3 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
## start_gcode = M862.3 P \"[printer_model]\" ; printer model check\nM862.1 P[nozzle_diameter] ; nozzle diameter check\nM115 U3.10.0 ; tell printer latest fw version\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG92 E0.0
## default_print_profile = 0.40mm QUALITY @0.8 nozzle
## MINI
@ -6430,6 +6450,7 @@ start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104
end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)}{endif} F720 ; Move print head up\nG1 X178 Y178 F4200 ; park print head\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)}{endif} F720 ; Move print head further up\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM900 K0 ; reset LA\nM84 ; disable motors
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MINI\n
extruder_colour =
color_change_gcode = M600\nG1 E0.8 F1500 ; prime after color change
[printer:Original Prusa MINI & MINI+ 0.25 nozzle]
inherits = Original Prusa MINI & MINI+
@ -6443,6 +6464,7 @@ retract_length = 3
retract_lift = 0.15
retract_before_travel = 1
start_gcode = G90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM204 T1250 ; set travel acceleration\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM204 T[machine_max_acceleration_travel] ; restore travel acceleration\nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0\nG1 Y-2 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110 E8 F600\nG1 X40 E10 F400\nG92 E0\n\nM221 S95 ; set flow
color_change_gcode = M600\nG1 E0.6 F1500 ; prime after color change
[printer:Original Prusa MINI & MINI+ 0.6 nozzle]
inherits = Original Prusa MINI & MINI+
@ -6454,6 +6476,7 @@ min_layer_height = 0.15
default_print_profile = 0.30mm QUALITY @0.6 nozzle MINI
retract_length = 3.5
retract_before_travel = 1.5
color_change_gcode = M600\nG1 E1 F1500 ; prime after color change
[printer:Original Prusa MINI & MINI+ 0.8 nozzle]
inherits = Original Prusa MINI & MINI+
@ -6465,6 +6488,7 @@ default_print_profile = 0.40mm QUALITY @0.8 nozzle MINI
default_filament_profile = Prusament PLA @0.8 nozzle
retract_length = 3.5
retract_before_travel = 1.5
color_change_gcode = M600\nG1 E1.2 F1500 ; prime after color change
[printer:Original Prusa SL1]
printer_technology = SLA

View File

@ -0,0 +1,6 @@
#version 110
void main()
{
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

View File

@ -0,0 +1,6 @@
#version 110
void main()
{
gl_Position = ftransform();
}

View File

@ -124,32 +124,34 @@ namespace ImGui
const char ColorMarkerEnd = 0x3; // ETX
// Special ASCII characters are used here as an ikons markers
const char PrintIconMarker = 0x4;
const char PrinterIconMarker = 0x5;
const char PrinterSlaIconMarker = 0x6;
const char FilamentIconMarker = 0x7;
const char MaterialIconMarker = 0x8;
const char CloseNotifButton = 0xB;
const char CloseNotifHoverButton = 0xC;
const char MinimalizeButton = 0xE;
const char MinimalizeHoverButton = 0xF;
const char WarningMarker = 0x10;
const char ErrorMarker = 0x11;
const char EjectButton = 0x12;
const char EjectHoverButton = 0x13;
const char CancelButton = 0x14;
const char CancelHoverButton = 0x15;
const char VarLayerHeightMarker = 0x16;
const char RightArrowButton = 0x18;
const char RightArrowHoverButton = 0x19;
const char PreferencesButton = 0x1A;
const char PreferencesHoverButton = 0x1B;
const char SinkingObjectMarker = 0x1C;
const char CustomSupportsMarker = 0x1D;
const char CustomSeamMarker = 0x1E;
const char MmuSegmentationMarker = 0x1F;
const wchar_t PrintIconMarker = 0x4;
const wchar_t PrinterIconMarker = 0x5;
const wchar_t PrinterSlaIconMarker = 0x6;
const wchar_t FilamentIconMarker = 0x7;
const wchar_t MaterialIconMarker = 0x8;
const wchar_t CloseNotifButton = 0xB;
const wchar_t CloseNotifHoverButton = 0xC;
const wchar_t MinimalizeButton = 0xE;
const wchar_t MinimalizeHoverButton = 0xF;
const wchar_t WarningMarker = 0x10;
const wchar_t ErrorMarker = 0x11;
const wchar_t EjectButton = 0x12;
const wchar_t EjectHoverButton = 0x13;
const wchar_t CancelButton = 0x14;
const wchar_t CancelHoverButton = 0x15;
const wchar_t VarLayerHeightMarker = 0x16;
const wchar_t RightArrowButton = 0x18;
const wchar_t RightArrowHoverButton = 0x19;
const wchar_t PreferencesButton = 0x1A;
const wchar_t PreferencesHoverButton = 0x1B;
const wchar_t SinkingObjectMarker = 0x1C;
const wchar_t CustomSupportsMarker = 0x1D;
const wchar_t CustomSeamMarker = 0x1E;
const wchar_t MmuSegmentationMarker = 0x1F;
const wchar_t DocumentationButton = 0x2600;
const wchar_t DocumentationHoverButton = 0x2601;
const wchar_t ClippyMarker = 0x2602;
// void MyFunction(const char* name, const MyMatrix44& v);

View File

@ -223,10 +223,13 @@ std::vector<std::string> ConfigOptionDef::cli_args(const std::string &key) const
{
std::vector<std::string> args;
if (this->cli != ConfigOptionDef::nocli) {
std::string cli = this->cli.substr(0, this->cli.find("="));
boost::trim_right_if(cli, boost::is_any_of("!"));
const std::string &cli = this->cli;
//FIXME What was that for? Check the "readline" documentation.
// Neither '=' nor '!' is used in any of the cli parameters currently defined by PrusaSlicer.
// std::string cli = this->cli.substr(0, this->cli.find("="));
// boost::trim_right_if(cli, boost::is_any_of("!"));
if (cli.empty()) {
// Add the key
// Convert an option key to CLI argument by replacing underscores with dashes.
std::string opt = key;
boost::replace_all(opt, "_", "-");
args.emplace_back(std::move(opt));
@ -245,7 +248,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coPercents: return new ConfigOptionPercentsNullable();
case coFloatsOrPercents: return new ConfigOptionFloatsOrPercentsNullable();
case coBools: return new ConfigOptionBoolsNullable();
default: throw Slic3r::RuntimeError(std::string("Unknown option type for nullable option ") + this->label);
default: throw ConfigurationError(std::string("Unknown option type for nullable option ") + this->label);
}
} else {
switch (this->type) {
@ -266,7 +269,7 @@ ConfigOption* ConfigOptionDef::create_empty_option() const
case coBool: return new ConfigOptionBool();
case coBools: return new ConfigOptionBools();
case coEnum: return new ConfigOptionEnumGeneric(this->enum_keys_map);
default: throw Slic3r::RuntimeError(std::string("Unknown option type for option ") + this->label);
default: throw ConfigurationError(std::string("Unknown option type for option ") + this->label);
}
}
}
@ -494,7 +497,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions_ctxt, bool append)
{
if (! this->set_deserialize_nothrow(opt_key_src, value_src, substitutions_ctxt, append))
throw BadOptionTypeException(format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"", opt_key_src, value_src));
throw BadOptionValueException(format("Invalid value provided for parameter %1%: %2%", opt_key_src, value_src));
}
void ConfigBase::set_deserialize(std::initializer_list<SetDeserializeItem> items, ConfigSubstitutionContext& substitutions_ctxt)
@ -539,27 +542,51 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
ConfigOption *opt = this->option(opt_key, true);
assert(opt != nullptr);
bool success = opt->deserialize(value, append);
bool success = false;
bool substituted = false;
if (optdef->type == coBools && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable) {
//FIXME Special handling of vectors of bools, quick and not so dirty solution before PrusaSlicer 2.3.2 release.
bool nullable = opt->nullable();
ConfigHelpers::DeserializationSubstitution default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToFalse;
if (optdef->default_value) {
// Default value for vectors of booleans used in a "per extruder" context, thus the default contains just a single value.
assert(dynamic_cast<const ConfigOptionVector<unsigned char>*>(optdef->default_value.get()));
auto &values = static_cast<const ConfigOptionVector<unsigned char>*>(optdef->default_value.get())->values;
if (values.size() == 1 && values.front() == 1)
default_value = ConfigHelpers::DeserializationSubstitution::DefaultsToTrue;
}
auto result = nullable ?
static_cast<ConfigOptionBoolsNullable*>(opt)->deserialize_with_substitutions(value, append, default_value) :
static_cast<ConfigOptionBools*>(opt)->deserialize_with_substitutions(value, append, default_value);
success = result != ConfigHelpers::DeserializationResult::Failed;
substituted = result == ConfigHelpers::DeserializationResult::Substituted;
} else {
success = opt->deserialize(value, append);
if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable &&
// Only allow substitutions of an enum value by another enum value or a boolean value with an enum value.
// That means, we expect enum values being added in the future and possibly booleans being converted to enums.
(optdef->type == coEnum || optdef->type == coBool))
{
(optdef->type == coEnum || optdef->type == coBool) && ConfigHelpers::looks_like_enum_value(value)) {
// Deserialize failed, try to substitute with a default value.
assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent);
if (optdef->type == coBool)
static_cast<ConfigOptionBool*>(opt)->value = ConfigHelpers::enum_looks_like_true_value(value);
else
// Just use the default of the option.
opt->set(optdef->default_value.get());
success = true;
substituted = true;
}
}
if (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable) {
if (substituted && (substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable ||
substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)) {
// Log the substitution.
ConfigSubstitution config_substitution;
config_substitution.opt_def = optdef;
config_substitution.old_value = value;//std::unique_ptr<ConfigOption>(opt);
config_substitution.new_value = ConfigOptionUniquePtr(this->option(opt_key, true)->clone());
config_substitution.old_value = value;
config_substitution.new_value = ConfigOptionUniquePtr(opt->clone());
substitutions_ctxt.substitutions.emplace_back(std::move(config_substitution));
}
return true;
}
return success;
}
@ -585,7 +612,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
return opt_def->ratio_over.empty() ? 0. :
static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(this->get_abs_value(opt_def->ratio_over));
}
throw Slic3r::RuntimeError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
throw ConfigurationError("ConfigBase::get_abs_value(): Not a valid option type for get_abs_value()");
}
// Return an absolute value of a possibly relative config variable.
@ -596,7 +623,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key, double rati
const ConfigOption *raw_opt = this->option(opt_key);
assert(raw_opt != nullptr);
if (raw_opt->type() != coFloatOrPercent)
throw Slic3r::RuntimeError("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
throw ConfigurationError("ConfigBase::get_abs_value(): opt_key is not of coFloatOrPercent");
// Compute absolute value.
return static_cast<const ConfigOptionFloatOrPercent*>(raw_opt)->get_abs_value(ratio_over);
}
@ -622,16 +649,69 @@ void ConfigBase::setenv_() const
ConfigSubstitutions ConfigBase::load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
return is_gcode_file(file) ?
this->load_from_gcode_file(file, true /* check header */, compatibility_rule) :
this->load_from_gcode_file(file, compatibility_rule) :
this->load_from_ini(file, compatibility_rule);
}
ConfigSubstitutions ConfigBase::load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
try {
boost::property_tree::ptree tree;
boost::nowide::ifstream ifs(file);
boost::property_tree::read_ini(ifs, tree);
return this->load(tree, compatibility_rule);
} catch (const ConfigurationError &e) {
throw ConfigurationError(format("Failed loading configuration file \"%1%\": %2%", file, e.what()));
}
}
ConfigSubstitutions ConfigBase::load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
boost::property_tree::ptree tree;
std::istringstream iss(data);
boost::property_tree::read_ini(iss, tree);
return this->load(tree, compatibility_rule);
}
// Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF.
// Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment).
ConfigSubstitutions ConfigBase::load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// Convert the "data" string into INI format by removing the semi-colons at the start of a line.
// Also the "; generated by PrusaSlicer ..." comment line will be removed.
size_t j = 0;
for (size_t i = 0; i < data.size();)
if (i == 0 || data[i] == '\n') {
// Start of a line.
if (i != 0) {
// Consume LF.
assert(data[i] == '\n');
// Don't keep empty lines.
if (j > 0 && data[j - 1] != '\n')
data[j ++] = data[i];
++ i;
}
// Skip all leading spaces;
for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++ i) ;
// Skip the semicolon (comment indicator).
if (i < data.size() && data[i] == ';')
++ i;
// Skip all leading spaces after semicolon.
for (; i < data.size() && (data[i] == ' ' || data[i] == '\t'); ++ i) ;
if (strncmp(data.data() + i, "generated by ", 13) == 0) {
// Skip the "; generated by ..." line.
for (; i < data.size() && data[i] != '\n'; ++ i);
}
} else if (data[i] == '\r' && i + 1 < data.size() && data[i + 1] == '\n') {
// Skip CR.
++ i;
} else {
// Consume the rest of the data.
data[j ++] = data[i ++];
}
data.erase(data.begin() + j, data.end());
return this->load_from_ini_string(data, compatibility_rule);
}
ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule)
@ -648,37 +728,8 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo
return std::move(substitutions_ctxt.substitutions);
}
// Load the config keys from the tail of a G-code file.
ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, bool check_header, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// Read a 64k block from the end of the G-code.
boost::nowide::ifstream ifs(file);
if (check_header) {
const char slic3r_gcode_header[] = "; generated by Slic3r ";
const char prusaslicer_gcode_header[] = "; generated by PrusaSlicer ";
std::string firstline;
std::getline(ifs, firstline);
if (strncmp(slic3r_gcode_header, firstline.c_str(), strlen(slic3r_gcode_header)) != 0 &&
strncmp(prusaslicer_gcode_header, firstline.c_str(), strlen(prusaslicer_gcode_header)) != 0)
throw Slic3r::RuntimeError("Not a PrusaSlicer / Slic3r PE generated g-code.");
}
ifs.seekg(0, ifs.end);
auto file_length = ifs.tellg();
auto data_length = std::min<std::fstream::pos_type>(65535, file_length);
ifs.seekg(file_length - data_length, ifs.beg);
std::vector<char> data(size_t(data_length) + 1, 0);
ifs.read(data.data(), data_length);
ifs.close();
ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
size_t key_value_pairs = load_from_gcode_string(data.data(), substitutions_ctxt);
if (key_value_pairs < 80)
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
return std::move(substitutions_ctxt.substitutions);
}
// Load the config keys from the given string.
size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionContext& substitutions)
static inline size_t load_from_gcode_string_legacy(ConfigBase &config, const char *str, ConfigSubstitutionContext &substitutions)
{
if (str == nullptr)
return 0;
@ -701,7 +752,7 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ')
break;
const char *key = start + 2;
if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
if (!((*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z')))
// A key must start with a letter.
break;
const char *sep = key;
@ -723,7 +774,7 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
if (key == nullptr)
break;
try {
this->set_deserialize(std::string(key, key_end), std::string(value, end), substitutions);
config.set_deserialize(std::string(key, key_end), std::string(value, end), substitutions);
++num_key_value_pairs;
}
catch (UnknownOptionException & /* e */) {
@ -735,6 +786,174 @@ size_t ConfigBase::load_from_gcode_string(const char* str, ConfigSubstitutionCon
return num_key_value_pairs;
}
// Reading a config from G-code back to front for performance reasons: We don't want to scan
// hundreds of MB file for a short config block, which we expect to find at the end of the G-code.
class ReverseLineReader
{
public:
using pos_type = boost::nowide::ifstream::pos_type;
// Stop at file_start
ReverseLineReader(boost::nowide::ifstream &ifs, pos_type file_start) : m_ifs(ifs), m_file_start(file_start)
{
m_ifs.seekg(0, m_ifs.end);
m_file_pos = m_ifs.tellg();
m_block.assign(m_block_size, 0);
}
bool getline(std::string &out) {
out.clear();
for (;;) {
if (m_block_len == 0) {
// Read the next block.
m_block_len = size_t(std::min<std::fstream::pos_type>(m_block_size, m_file_pos - m_file_start));
if (m_block_len == 0)
return false;
m_file_pos -= m_block_len;
m_ifs.seekg(m_file_pos, m_ifs.beg);
if (! m_ifs.read(m_block.data(), m_block_len))
return false;
}
assert(m_block_len > 0);
// Non-empty buffer. Find another LF.
int i = int(m_block_len) - 1;
for (; i >= 0; -- i)
if (m_block[i] == '\n')
break;
// i is position of LF or -1 if not found.
if (i == -1) {
// LF not found. Just make a backup of the buffer and continue.
out.insert(out.begin(), m_block.begin(), m_block.begin() + m_block_len);
m_block_len = 0;
} else {
assert(i >= 0);
// Copy new line to the output. It may be empty.
out.insert(out.begin(), m_block.begin() + i + 1, m_block.begin() + m_block_len);
// Block length without the newline.
m_block_len = i;
// Remove CRLF from the end of the block.
if (m_block_len > 0 && m_block[m_block_len - 1] == '\r')
-- m_block_len;
return true;
}
}
assert(false);
return false;
}
private:
boost::nowide::ifstream &m_ifs;
std::vector<char> m_block;
size_t m_block_size = 65536;
size_t m_block_len = 0;
pos_type m_file_start;
pos_type m_file_pos = 0;
};
// Load the config keys from the tail of a G-code file.
ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// Read a 64k block from the end of the G-code.
boost::nowide::ifstream ifs(file);
// Look for Slic3r or PrusaSlicer header.
// Look for the header across the whole file as the G-code may have been extended at the start by a post-processing script or the user.
bool has_delimiters = false;
{
static constexpr const char slic3r_gcode_header[] = "; generated by Slic3r ";
static constexpr const char prusaslicer_gcode_header[] = "; generated by PrusaSlicer ";
std::string header;
bool header_found = false;
while (std::getline(ifs, header)) {
if (strncmp(slic3r_gcode_header, header.c_str(), strlen(slic3r_gcode_header)) == 0) {
header_found = true;
break;
} else if (strncmp(prusaslicer_gcode_header, header.c_str(), strlen(prusaslicer_gcode_header)) == 0) {
// Parse PrusaSlicer version.
size_t i = strlen(prusaslicer_gcode_header);
for (; i < header.size() && header[i] == ' '; ++ i) ;
size_t j = i;
for (; j < header.size() && header[j] != ' '; ++ j) ;
try {
Semver semver(header.substr(i, j - i));
has_delimiters = semver >= Semver(2, 4, 0, nullptr, "alpha0");
} catch (const RuntimeError &) {
}
header_found = true;
break;
}
}
if (! header_found)
throw Slic3r::RuntimeError("Not a PrusaSlicer / Slic3r PE generated g-code.");
}
auto header_end_pos = ifs.tellg();
ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
size_t key_value_pairs = 0;
if (has_delimiters)
{
// PrusaSlicer starting with 2.4.0-alpha0 delimits the config section stored into G-code with
// ; prusaslicer_config = begin
// ...
// ; prusaslicer_config = end
// The begin / end tags look like any other key / value pairs on purpose to be compatible with older G-code viewer.
// Read the file in reverse line by line.
ReverseLineReader reader(ifs, header_end_pos);
// Read the G-code file by 64k blocks back to front.
bool begin_found = false;
bool end_found = false;
std::string line;
while (reader.getline(line))
if (line == "; prusaslicer_config = end") {
end_found = true;
break;
}
if (! end_found)
throw Slic3r::RuntimeError(format("Configuration block closing tag \"; prusaslicer_config = end\" not found when reading %1%", file));
std::string key, value;
while (reader.getline(line)) {
if (line == "; prusaslicer_config = begin") {
begin_found = true;
break;
}
// line should be a valid key = value pair.
auto pos = line.find('=');
if (pos != std::string::npos && pos > 1 && line.front() == ';') {
key = line.substr(1, pos - 1);
value = line.substr(pos + 1);
boost::trim(key);
boost::trim(value);
try {
this->set_deserialize(key, value, substitutions_ctxt);
++ key_value_pairs;
} catch (UnknownOptionException & /* e */) {
// ignore
}
}
}
if (! begin_found)
throw Slic3r::RuntimeError(format("Configuration block opening tag \"; prusaslicer_config = begin\" not found when reading %1%", file));
}
else
{
// Slic3r or PrusaSlicer older than 2.4.0-alpha0 do not emit any delimiter.
// Try a heuristics reading the G-code from back.
ifs.seekg(0, ifs.end);
auto file_length = ifs.tellg();
auto data_length = std::min<std::fstream::pos_type>(65535, file_length - header_end_pos);
ifs.seekg(file_length - data_length, ifs.beg);
std::vector<char> data(size_t(data_length) + 1, 0);
ifs.read(data.data(), data_length);
ifs.close();
key_value_pairs = load_from_gcode_string_legacy(*this, data.data(), substitutions_ctxt);
}
if (key_value_pairs < 80)
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
return std::move(substitutions_ctxt.substitutions);
}
void ConfigBase::save(const std::string &file) const
{
boost::nowide::ofstream c;
@ -803,7 +1022,7 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
throw NoDefinitionException(opt_key);
const ConfigOptionDef *optdef = def->get(opt_key);
if (optdef == nullptr)
// throw Slic3r::RuntimeError(std::string("Invalid option name: ") + opt_key);
// throw ConfigurationError(std::string("Invalid option name: ") + opt_key);
// Let the parent decide what to do if the opt_key is not defined by this->def().
return nullptr;
ConfigOption *opt = optdef->create_default_option();
@ -817,22 +1036,12 @@ const ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key) co
return (it == options.end()) ? nullptr : it->second.get();
}
void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys)
{
std::vector<const char*> args;
// push a bogus executable name (argv[0])
args.emplace_back("");
for (size_t i = 0; i < tokens.size(); ++ i)
args.emplace_back(tokens[i].c_str());
this->read_cli(int(args.size()), args.data(), extra, keys);
}
bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys)
{
// cache the CLI option => opt_key mapping
std::map<std::string,std::string> opts;
for (const auto &oit : this->def()->options)
for (auto t : oit.second.cli_args(oit.first))
for (const std::string &t : oit.second.cli_args(oit.first))
opts[t] = oit.first;
bool parse_options = true;
@ -854,14 +1063,8 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
parse_options = false;
continue;
}
// Remove leading dashes
boost::trim_left_if(token, boost::is_any_of("-"));
// Remove the "no-" prefix used to negate boolean options.
bool no = false;
if (boost::starts_with(token, "no-")) {
no = true;
boost::replace_first(token, "no-", "");
}
// Remove leading dashes (one or two).
token.erase(token.begin(), token.begin() + (boost::starts_with(token, "--") ? 2 : 1));
// Read value when supplied in the --key=value form.
std::string value;
{
@ -871,54 +1074,45 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
token.erase(equals_pos);
}
}
// Look for the cli -> option mapping.
const auto it = opts.find(token);
auto it = opts.find(token);
bool no = false;
if (it == opts.end()) {
// Remove the "no-" prefix used to negate boolean options.
std::string yes_token;
if (boost::starts_with(token, "no-")) {
yes_token = token.substr(3);
it = opts.find(yes_token);
no = true;
}
if (it == opts.end()) {
boost::nowide::cerr << "Unknown option --" << token.c_str() << std::endl;
return false;
}
const t_config_option_key opt_key = it->second;
if (no)
token = yes_token;
}
const t_config_option_key &opt_key = it->second;
const ConfigOptionDef &optdef = this->def()->options.at(opt_key);
// If the option type expects a value and it was not already provided,
// look for it in the next token.
if (value.empty()) {
if (optdef.type != coBool && optdef.type != coBools) {
if (i == (argc-1)) {
if (value.empty() && optdef.type != coBool && optdef.type != coBools) {
if (i == argc-1) {
boost::nowide::cerr << "No value supplied for --" << token.c_str() << std::endl;
return false;
}
value = argv[++ i];
} else {
// This is a bool or bools. The value is optional, but may still be there.
// Check if the next token can be deserialized into ConfigOptionBool.
// If it is in fact bools, it will be rejected later anyway.
if (i != argc-1) { // There is still a token to read.
ConfigOptionBool cobool;
if (cobool.deserialize(argv[i+1]))
value = argv[++i];
}
}
}
if (no) {
if (optdef.type != coBool && optdef.type != coBools) {
boost::nowide::cerr << "Only boolean config options can be negated with --no- prefix." << std::endl;
return false;
}
else if (! value.empty()) {
assert(optdef.type == coBool || optdef.type == coBools);
if (! value.empty()) {
boost::nowide::cerr << "Boolean options negated by the --no- prefix cannot have a value." << std::endl;
return false;
}
}
if (optdef.type == coBools && ! value.empty()) {
boost::nowide::cerr << "Vector boolean options cannot have a value. Fill them in by "
"repeating them and negate by --no- prefix." << std::endl;
return false;
}
// Store the option value.
const bool existing = this->has(opt_key);
@ -934,7 +1128,7 @@ bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option
opt_vector->clear();
// Vector values will be chained. Repeated use of a parameter will append the parameter or parameters
// to the end of the value.
if (opt_base->type() == coBools)
if (opt_base->type() == coBools && value.empty())
static_cast<ConfigOptionBools*>(opt_base)->values.push_back(!no);
else
// Deserialize any other vector value (ConfigOptionInts, Floats, Percents, Points) the same way

View File

@ -80,32 +80,77 @@ extern bool unescape_strings_cstyle(const std::string &str, std::vector<
extern std::string escape_ampersand(const std::string& str);
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
class UnknownOptionException : public Slic3r::RuntimeError {
public:
UnknownOptionException() :
Slic3r::RuntimeError("Unknown option exception") {}
UnknownOptionException(const std::string &opt_key) :
Slic3r::RuntimeError(std::string("Unknown option exception: ") + opt_key) {}
namespace ConfigHelpers {
inline bool looks_like_enum_value(std::string value)
{
boost::trim(value);
if (value.empty() || value.size() > 64 || ! isalpha(value.front()))
return false;
for (const char c : value)
if (! (isalnum(c) || c == '_' || c == '-'))
return false;
return true;
}
inline bool enum_looks_like_true_value(std::string value) {
boost::trim(value);
return boost::iequals(value, "enabled") || boost::iequals(value, "on");
}
enum class DeserializationSubstitution {
Disabled,
DefaultsToFalse,
DefaultsToTrue
};
/// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
class NoDefinitionException : public Slic3r::RuntimeError
enum class DeserializationResult {
Loaded,
Substituted,
Failed,
};
};
// Base for all exceptions thrown by the configuration layer.
class ConfigurationError : public Slic3r::RuntimeError {
public:
using RuntimeError::RuntimeError;
};
// Specialization of std::exception to indicate that an unknown config option has been encountered.
class UnknownOptionException : public ConfigurationError {
public:
UnknownOptionException() :
ConfigurationError("Unknown option exception") {}
UnknownOptionException(const std::string &opt_key) :
ConfigurationError(std::string("Unknown option exception: ") + opt_key) {}
};
// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
class NoDefinitionException : public ConfigurationError
{
public:
NoDefinitionException() :
Slic3r::RuntimeError("No definition exception") {}
ConfigurationError("No definition exception") {}
NoDefinitionException(const std::string &opt_key) :
Slic3r::RuntimeError(std::string("No definition exception: ") + opt_key) {}
ConfigurationError(std::string("No definition exception: ") + opt_key) {}
};
/// Indicate that an unsupported accessor was called on a config option.
class BadOptionTypeException : public Slic3r::RuntimeError
// Indicate that an unsupported accessor was called on a config option.
class BadOptionTypeException : public ConfigurationError
{
public:
BadOptionTypeException() : Slic3r::RuntimeError("Bad option type exception") {}
BadOptionTypeException(const std::string &message) : Slic3r::RuntimeError(message) {}
BadOptionTypeException(const char* message) : Slic3r::RuntimeError(message) {}
BadOptionTypeException() : ConfigurationError("Bad option type exception") {}
BadOptionTypeException(const std::string &message) : ConfigurationError(message) {}
BadOptionTypeException(const char* message) : ConfigurationError(message) {}
};
// Indicate that an option has been deserialized from an invalid value.
class BadOptionValueException : public ConfigurationError
{
public:
BadOptionValueException() : ConfigurationError("Bad option value exception") {}
BadOptionValueException(const std::string &message) : ConfigurationError(message) {}
BadOptionValueException(const char* message) : ConfigurationError(message) {}
};
// Type of a configuration value.
@ -166,9 +211,16 @@ enum PrinterTechnology : unsigned char
enum ForwardCompatibilitySubstitutionRule
{
// Disable susbtitution, throw exception if an option value is not recognized.
Disable,
// Enable substitution of an unknown option value with default. Log the substitution.
Enable,
// Enable substitution of an unknown option value with default. Don't log the substitution.
EnableSilent,
// Enable substitution of an unknown option value with default. Log substitutions in user profiles, don't log substitutions in system profiles.
EnableSystemSilent,
// Enable silent substitution of an unknown option value with default when loading user profiles. Throw on an unknown option value in a system profile.
EnableSilentDisableSystem,
};
class ConfigOption;
@ -252,7 +304,7 @@ public:
void set(const ConfigOption *rhs) override
{
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionSingle: Assigning an incompatible type");
throw ConfigurationError("ConfigOptionSingle: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionSingle<T>*>(rhs));
this->value = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
}
@ -260,7 +312,7 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionSingle: Comparing incompatible types");
throw ConfigurationError("ConfigOptionSingle: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionSingle<T>*>(&rhs));
return this->value == static_cast<const ConfigOptionSingle<T>*>(&rhs)->value;
}
@ -327,7 +379,7 @@ public:
void set(const ConfigOption *rhs) override
{
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionVector: Assigning an incompatible type");
throw ConfigurationError("ConfigOptionVector: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionVector<T>*>(rhs));
this->values = static_cast<const ConfigOptionVector<T>*>(rhs)->values;
}
@ -344,12 +396,12 @@ public:
if (opt->type() == this->type()) {
auto other = static_cast<const ConfigOptionVector<T>*>(opt);
if (other->values.empty())
throw Slic3r::RuntimeError("ConfigOptionVector::set(): Assigning from an empty vector");
throw ConfigurationError("ConfigOptionVector::set(): Assigning from an empty vector");
this->values.emplace_back(other->values.front());
} else if (opt->type() == this->scalar_type())
this->values.emplace_back(static_cast<const ConfigOptionSingle<T>*>(opt)->value);
else
throw Slic3r::RuntimeError("ConfigOptionVector::set():: Assigning an incompatible type");
throw ConfigurationError("ConfigOptionVector::set():: Assigning an incompatible type");
}
}
@ -368,12 +420,12 @@ public:
// Assign the first value of the rhs vector.
auto other = static_cast<const ConfigOptionVector<T>*>(rhs);
if (other->values.empty())
throw Slic3r::RuntimeError("ConfigOptionVector::set_at(): Assigning from an empty vector");
throw ConfigurationError("ConfigOptionVector::set_at(): Assigning from an empty vector");
this->values[i] = other->get_at(j);
} else if (rhs->type() == this->scalar_type())
this->values[i] = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
else
throw Slic3r::RuntimeError("ConfigOptionVector::set_at(): Assigning an incompatible type");
throw ConfigurationError("ConfigOptionVector::set_at(): Assigning an incompatible type");
}
const T& get_at(size_t i) const
@ -398,9 +450,9 @@ public:
else if (n > this->values.size()) {
if (this->values.empty()) {
if (opt_default == nullptr)
throw Slic3r::RuntimeError("ConfigOptionVector::resize(): No default value provided.");
throw ConfigurationError("ConfigOptionVector::resize(): No default value provided.");
if (opt_default->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionVector::resize(): Extending with an incompatible type.");
throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type.");
this->values.resize(n, static_cast<const ConfigOptionVector<T>*>(opt_default)->values.front());
} else {
// Resize by duplicating the last value.
@ -417,7 +469,7 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionVector: Comparing incompatible types");
throw ConfigurationError("ConfigOptionVector: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionVector<T>*>(&rhs));
return this->values == static_cast<const ConfigOptionVector<T>*>(&rhs)->values;
}
@ -437,9 +489,9 @@ public:
// 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 Slic3r::RuntimeError("Cannot override a nullable ConfigOption.");
throw ConfigurationError("Cannot override a nullable ConfigOption.");
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionVector.overriden_by() applied to different types.");
throw ConfigurationError("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.
@ -457,9 +509,9 @@ public:
// Apply an override option, possibly a nullable one.
bool apply_override(const ConfigOption *rhs) override {
if (this->nullable())
throw Slic3r::RuntimeError("Cannot override a nullable ConfigOption.");
throw ConfigurationError("Cannot override a nullable ConfigOption.");
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionVector.apply_override() applied to different types.");
throw ConfigurationError("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.
@ -550,7 +602,7 @@ public:
bool operator< (const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_lower(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatsTempl: Comparing incompatible types");
throw ConfigurationError("ConfigOptionFloatsTempl: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionVector<double>*>(&rhs));
return vectors_equal(this->values, static_cast<const ConfigOptionVector<double>*>(&rhs)->values);
}
@ -597,7 +649,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
throw ConfigurationError("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
double value;
@ -622,9 +674,9 @@ protected:
if (NULLABLE)
ss << "nil";
else
throw Slic3r::RuntimeError("Serializing NaN");
throw ConfigurationError("Serializing NaN");
} else
throw Slic3r::RuntimeError("Serializing invalid number");
throw ConfigurationError("Serializing invalid number");
}
static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
if (NULLABLE) {
@ -756,7 +808,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
throw ConfigurationError("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
int value;
@ -773,7 +825,7 @@ private:
if (NULLABLE)
ss << "nil";
else
throw Slic3r::RuntimeError("Serializing NaN");
throw ConfigurationError("Serializing NaN");
} else
ss << v;
}
@ -963,7 +1015,7 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatOrPercent: Comparing incompatible types");
throw ConfigurationError("ConfigOptionFloatOrPercent: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionFloatOrPercent*>(&rhs));
return *this == *static_cast<const ConfigOptionFloatOrPercent*>(&rhs);
}
@ -979,7 +1031,7 @@ public:
void set(const ConfigOption *rhs) override {
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatOrPercent: Assigning an incompatible type");
throw ConfigurationError("ConfigOptionFloatOrPercent: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionFloatOrPercent*>(rhs));
*this = *static_cast<const ConfigOptionFloatOrPercent*>(rhs);
}
@ -1023,7 +1075,7 @@ public:
bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
throw ConfigurationError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
assert(dynamic_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs));
return vectors_equal(this->values, static_cast<const ConfigOptionVector<FloatOrPercent>*>(&rhs)->values);
}
@ -1072,7 +1124,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
throw ConfigurationError("Deserializing nil into a non-nullable object");
} else {
bool percent = item_str.find_first_of("%") != std::string::npos;
std::istringstream iss(item_str);
@ -1100,9 +1152,9 @@ protected:
if (NULLABLE)
ss << "nil";
else
throw Slic3r::RuntimeError("Serializing NaN");
throw ConfigurationError("Serializing NaN");
} else
throw Slic3r::RuntimeError("Serializing invalid number");
throw ConfigurationError("Serializing invalid number");
}
static bool vectors_equal(const std::vector<FloatOrPercent> &v1, const std::vector<FloatOrPercent> &v2) {
if (NULLABLE) {
@ -1308,11 +1360,11 @@ public:
bool deserialize(const std::string &str, bool append = false) override
{
UNUSED(append);
if (str == "1" || boost::iequals(str, "enabled") || boost::iequals(str, "on")) {
if (str == "1") {
this->value = true;
return true;
}
if (str == "0" || boost::iequals(str, "disabled") || boost::iequals(str, "off")) {
if (str == "0") {
this->value = false;
return true;
}
@ -1379,23 +1431,38 @@ public:
return vv;
}
bool deserialize(const std::string &str, bool append = false) override
ConfigHelpers::DeserializationResult deserialize_with_substitutions(const std::string &str, bool append, ConfigHelpers::DeserializationSubstitution substitution)
{
if (! append)
this->values.clear();
std::istringstream is(str);
std::string item_str;
bool substituted = false;
while (std::getline(is, item_str, ',')) {
boost::trim(item_str);
unsigned char new_value = 0;
if (item_str == "nil") {
if (NULLABLE)
this->values.push_back(nil_value());
new_value = nil_value();
else
throw Slic3r::RuntimeError("Deserializing nil into a non-nullable object");
throw ConfigurationError("Deserializing nil into a non-nullable object");
} else if (item_str == "1") {
new_value = true;
} else if (item_str == "0") {
new_value = false;
} else if (substitution != ConfigHelpers::DeserializationSubstitution::Disabled && ConfigHelpers::looks_like_enum_value(item_str)) {
new_value = ConfigHelpers::enum_looks_like_true_value(item_str) || substitution == ConfigHelpers::DeserializationSubstitution::DefaultsToTrue;
substituted = true;
} else
this->values.push_back(item_str.compare("1") == 0);
return ConfigHelpers::DeserializationResult::Failed;
this->values.push_back(new_value);
}
return true;
return substituted ? ConfigHelpers::DeserializationResult::Substituted : ConfigHelpers::DeserializationResult::Loaded;
}
bool deserialize(const std::string &str, bool append = false) override
{
return this->deserialize_with_substitutions(str, append, ConfigHelpers::DeserializationSubstitution::Disabled) == ConfigHelpers::DeserializationResult::Loaded;
}
protected:
@ -1404,7 +1471,7 @@ protected:
if (NULLABLE)
ss << "nil";
else
throw Slic3r::RuntimeError("Serializing NaN");
throw ConfigurationError("Serializing NaN");
} else
ss << (v ? "1" : "0");
}
@ -1442,14 +1509,14 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionEnum<T>: Comparing incompatible types");
throw ConfigurationError("ConfigOptionEnum<T>: Comparing incompatible types");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
return this->value == (T)rhs.getInt();
}
void set(const ConfigOption *rhs) override {
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionEnum<T>: Assigning an incompatible type");
throw ConfigurationError("ConfigOptionEnum<T>: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
this->value = (T)rhs->getInt();
}
@ -1512,14 +1579,14 @@ public:
bool operator==(const ConfigOption &rhs) const override
{
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Comparing incompatible types");
throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
return this->value == rhs.getInt();
}
void set(const ConfigOption *rhs) override {
if (rhs->type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Assigning an incompatible type");
throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
this->value = rhs->getInt();
}
@ -1592,7 +1659,7 @@ public:
case coInts: { auto opt = new ConfigOptionIntsNullable(); archive(*opt); return opt; }
case coPercents: { auto opt = new ConfigOptionPercentsNullable();archive(*opt); return opt; }
case coBools: { auto opt = new ConfigOptionBoolsNullable(); archive(*opt); return opt; }
default: throw Slic3r::RuntimeError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown nullable option type for option ") + this->opt_key);
}
} else {
switch (this->type) {
@ -1611,7 +1678,7 @@ public:
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 Slic3r::RuntimeError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
default: throw ConfigurationError(std::string("ConfigOptionDef::load_option_from_archive(): Unknown option type for option ") + this->opt_key);
}
}
}
@ -1623,7 +1690,7 @@ public:
case coInts: archive(*static_cast<const ConfigOptionIntsNullable*>(opt)); break;
case coPercents: archive(*static_cast<const ConfigOptionPercentsNullable*>(opt));break;
case coBools: archive(*static_cast<const ConfigOptionBoolsNullable*>(opt)); break;
default: throw Slic3r::RuntimeError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown nullable option type for option ") + this->opt_key);
}
} else {
switch (this->type) {
@ -1642,7 +1709,7 @@ public:
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 Slic3r::RuntimeError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
default: throw ConfigurationError(std::string("ConfigOptionDef::save_option_to_archive(): Unknown option type for option ") + this->opt_key);
}
}
// Make the compiler happy, shut up the warnings.
@ -1765,7 +1832,7 @@ public:
return out;
}
/// Iterate through all of the CLI options and write them to a stream.
// Iterate through all of the CLI options and write them to a stream.
std::ostream& print_cli_help(
std::ostream& out, bool show_defaults,
std::function<bool(const ConfigOptionDef &)> filter = [](const ConfigOptionDef &){ return true; }) const;
@ -1934,9 +2001,11 @@ public:
void setenv_() const;
ConfigSubstitutions load(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
ConfigSubstitutions load_from_ini(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
ConfigSubstitutions load_from_gcode_file(const std::string &file, bool check_header /* = true */, ForwardCompatibilitySubstitutionRule compatibility_rule);
// Returns number of key/value pairs extracted.
size_t load_from_gcode_string(const char* str, ConfigSubstitutionContext& substitutions);
ConfigSubstitutions load_from_ini_string(const std::string &data, ForwardCompatibilitySubstitutionRule compatibility_rule);
// Loading a "will be one day a legacy format" of configuration stored into 3MF or AMF.
// Accepts the same data as load_from_ini_string(), only with each configuration line possibly prefixed with a semicolon (G-code comment).
ConfigSubstitutions load_from_ini_string_commented(std::string &&data, ForwardCompatibilitySubstitutionRule compatibility_rule);
ConfigSubstitutions load_from_gcode_file(const std::string &file, ForwardCompatibilitySubstitutionRule compatibility_rule);
ConfigSubstitutions load(const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
void save(const std::string &file) const;
@ -2099,7 +2168,6 @@ public:
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }
// Command line processing
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cbegin() const { return options.cbegin(); }
@ -2113,9 +2181,9 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(options); }
};
/// Configuration store with a static definition of configuration values.
/// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
/// because the configuration values could be accessed directly.
// Configuration store with a static definition of configuration values.
// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
// because the configuration values could be accessed directly.
class StaticConfig : public virtual ConfigBase
{
public:

View File

@ -875,7 +875,9 @@ namespace Slic3r {
add_error("Error while reading config data to buffer");
return;
}
config.load_from_gcode_string(buffer.data(), config_substitutions);
//FIXME Loading a "will be one day a legacy format" of configuration in a form of a G-code comment.
// Each config line is prefixed with a semicolon (G-code comment), that is ugly.
config_substitutions.substitutions = config.load_from_ini_string_commented(std::move(buffer), config_substitutions.rule);
}
}

View File

@ -706,7 +706,9 @@ void AMFParserContext::endElement(const char * /* name */)
case NODE_TYPE_METADATA:
if ((m_config != nullptr) && strncmp(m_value[0].c_str(), SLIC3R_CONFIG_TYPE, strlen(SLIC3R_CONFIG_TYPE)) == 0) {
m_config->load_from_gcode_string(m_value[1].c_str(), *m_config_substitutions);
//FIXME Loading a "will be one day a legacy format" of configuration in a form of a G-code comment.
// Each config line is prefixed with a semicolon (G-code comment), that is ugly.
m_config_substitutions->substitutions = m_config->load_from_ini_string_commented(std::move(m_value[1].c_str()), m_config_substitutions->rule);
}
else if (strncmp(m_value[0].c_str(), "slic3r.", 7) == 0) {
const char *opt_key = m_value[0].c_str() + 7;

View File

@ -203,7 +203,7 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg)
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
!opt_mirror_x || !opt_mirror_y || !opt_orient)
throw Slic3r::FileIOError("Invalid SL1 file");
throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
RasterParams rstp;
@ -229,7 +229,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg)
auto *opt_init_layerh = cfg.option<ConfigOptionFloat>("initial_layer_height");
if (!opt_layerh || !opt_init_layerh)
throw Slic3r::FileIOError("Invalid SL1 file");
throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
}

View File

@ -1464,13 +1464,15 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
// Append full config.
_write(file, "\n");
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
{
_write(file, "\n; prusaslicer_config = begin\n");
std::string full_config;
append_full_config(print, full_config);
if (!full_config.empty())
_write(file, full_config);
_write(file, "; prusaslicer_config = end\n");
}
print.throw_if_canceled();
}
@ -2714,7 +2716,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
// calculate extrusion length per distance unit
double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
if (m_writer.extrusion_axis().empty())
// gcfNoExtrusion
e_per_mm = 0;
// set speed
if (speed == -1) {

View File

@ -1172,7 +1172,7 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
// Silently substitute unknown values by new ones for loading configurations from PrusaSlicer's own G-code.
// Showing substitution log or errors may make sense, but we are not really reading many values from the G-code config,
// thus a probability of incorrect substitution is low and the G-code viewer is a consumer-only anyways.
config.load_from_gcode_file(filename, false, ForwardCompatibilitySubstitutionRule::EnableSilent);
config.load_from_gcode_file(filename, ForwardCompatibilitySubstitutionRule::EnableSilent);
apply_config(config);
}
else if (m_producer == EProducer::Simplify3D)

View File

@ -337,9 +337,9 @@ namespace Slic3r {
std::string printer;
void reset() {
print = "";
filament = std::vector<std::string>();
printer = "";
print.clear();
filament.clear();
printer.clear();
}
};
std::string filename;

View File

@ -1,10 +1,15 @@
#include "PostProcessor.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/format.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/fstream.hpp>
#ifdef WIN32
@ -179,21 +184,82 @@ static int run_script(const std::string &script, const std::string &gcode, std::
namespace Slic3r {
void run_post_process_scripts(const std::string &path, const DynamicPrintConfig &config)
// Run post processing script / scripts if defined.
// Returns true if a post-processing script was executed.
// Returns false if no post-processing script was defined.
// Throws an exception on error.
// host is one of "File", "PrusaLink", "Repetier", "SL1Host", "OctoPrint", "FlashAir", "Duet", "AstroBox" ...
// For a "File" target, a temp file will be created for src_path by adding a ".pp" suffix and src_path will be updated.
// In that case the caller is responsible to delete the temp file created.
// output_name is the final name of the G-code on SD card or when uploaded to PrusaLink or OctoPrint.
// If uploading to PrusaLink or OctoPrint, then the file will be renamed to output_name first on the target host.
// The post-processing script may change the output_name.
bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::string &host, std::string &output_name, const DynamicPrintConfig &config)
{
const auto *post_process = config.opt<ConfigOptionStrings>("post_process");
if (// likely running in SLA mode
post_process == nullptr ||
// no post-processing script
post_process->values.empty())
return;
return false;
std::string path;
if (make_copy) {
// Don't run the post-processing script on the input file, it will be memory mapped by the G-code viewer.
// Make a copy.
path = src_path + ".pp";
// First delete an old file if it exists.
try {
if (boost::filesystem::exists(path))
boost::filesystem::remove(path);
} catch (const std::exception &err) {
BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed deleting an old temporary file %1% before running a post-processing script: %2%", path, err.what());
}
// Second make a copy.
std::string error_message;
if (copy_file(src_path, path, error_message, false) != SUCCESS)
throw Slic3r::RuntimeError(Slic3r::format("Failed making a temporary copy of G-code file %1% before running a post-processing script: %2%", src_path, error_message));
} else {
// Don't make a copy of the G-code before running the post-processing script.
path = src_path;
}
auto delete_copy = [&path, &src_path, make_copy]() {
if (make_copy)
try {
if (boost::filesystem::exists(path))
boost::filesystem::remove(path);
} catch (const std::exception &err) {
BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed deleting a temporary copy %1% of a G-code file %2% : %3%", path, src_path, err.what());
}
};
// Store print configuration into environment variables.
config.setenv_();
auto gcode_file = boost::filesystem::path(path);
if (! boost::filesystem::exists(gcode_file))
throw Slic3r::RuntimeError(std::string("Post-processor can't find exported gcode file"));
// Store print configuration into environment variables.
config.setenv_();
// Let the post-processing script know the target host ("File", "PrusaLink", "Repetier", "SL1Host", "OctoPrint", "FlashAir", "Duet", "AstroBox" ...)
boost::nowide::setenv("SLIC3R_PP_HOST", host.c_str(), 1);
// Let the post-processing script know the final file name. For "File" host, it is a full path of the target file name and its location, for example pointing to an SD card.
// For "PrusaLink" or "OctoPrint", it is a file name optionally with a directory on the target host.
boost::nowide::setenv("SLIC3R_PP_OUTPUT_NAME", output_name.c_str(), 1);
// Path to an optional file that the post-processing script may create and populate it with a single line containing the output_name replacement.
std::string path_output_name = path + ".output_name";
auto remove_output_name_file = [&path_output_name, &src_path]() {
try {
if (boost::filesystem::exists(path_output_name))
boost::filesystem::remove(path_output_name);
} catch (const std::exception &err) {
BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed deleting a file %1% carrying the final name / path of a G-code file %2%: %3%", path_output_name, src_path, err.what());
}
};
// Remove possible stalled path_output_name of the previous run.
remove_output_name_file();
try {
for (const std::string &scripts : post_process->values) {
std::vector<std::string> lines;
boost::split(lines, scripts, boost::is_any_of("\r\n"));
@ -203,17 +269,61 @@ void run_post_process_scripts(const std::string &path, const DynamicPrintConfig
if (script.empty())
continue;
BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path;
std::string std_err;
const int result = run_script(script, gcode_file.string(), std_err);
if (result != 0) {
const std::string msg = std_err.empty() ? (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%") % script % path % result).str()
: (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%\nOutput:\n%4%") % script % path % result % std_err).str();
BOOST_LOG_TRIVIAL(error) << msg;
delete_copy();
throw Slic3r::RuntimeError(msg);
}
}
}
if (boost::filesystem::exists(path_output_name)) {
try {
// Read a single line from path_output_name, which should contain the new output name of the post-processed G-code.
boost::nowide::fstream f;
f.open(path_output_name, std::ios::in);
std::string new_output_name;
std::getline(f, new_output_name);
f.close();
if (host == "File") {
namespace fs = boost::filesystem;
fs::path op(new_output_name);
if (op.is_relative() && op.has_filename() && op.parent_path().empty()) {
// Is this just a filename? Make it an absolute path.
auto outpath = fs::path(output_name).parent_path();
outpath /= op.string();
new_output_name = outpath.string();
}
else {
if (! op.is_absolute() || ! op.has_filename())
throw Slic3r::RuntimeError("Unable to parse desired new path from output name file");
}
if (! fs::exists(fs::path(new_output_name).parent_path()))
throw Slic3r::RuntimeError(Slic3r::format("Output directory does not exist: %1%",
fs::path(new_output_name).parent_path().string()));
}
BOOST_LOG_TRIVIAL(trace) << "Post-processing script changed the file name from " << output_name << " to " << new_output_name;
output_name = new_output_name;
} catch (const std::exception &err) {
throw Slic3r::RuntimeError(Slic3r::format("run_post_process_scripts: Failed reading a file %1% "
"carrying the final name / path of a G-code file: %2%",
path_output_name, err.what()));
}
remove_output_name_file();
}
} catch (...) {
remove_output_name_file();
delete_copy();
throw;
}
src_path = std::move(path);
return true;
}
} // namespace Slic3r

View File

@ -8,7 +8,23 @@
namespace Slic3r {
extern void run_post_process_scripts(const std::string &path, const DynamicPrintConfig &config);
// Run post processing script / scripts if defined.
// Returns true if a post-processing script was executed.
// Returns false if no post-processing script was defined.
// Throws an exception on error.
// host is one of "File", "PrusaLink", "Repetier", "SL1Host", "OctoPrint", "FlashAir", "Duet", "AstroBox" ...
// If make_copy, then a temp file will be created for src_path by adding a ".pp" suffix and src_path will be updated.
// In that case the caller is responsible to delete the temp file created.
// output_name is the final name of the G-code on SD card or when uploaded to PrusaLink or OctoPrint.
// If uploading to PrusaLink or OctoPrint, then the file will be renamed to output_name first on the target host.
// The post-processing script may change the output_name.
extern bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::string &host, std::string &output_name, const DynamicPrintConfig &config);
inline bool run_post_process_scripts(std::string &src_path, const DynamicPrintConfig &config)
{
std::string src_path_name = src_path;
return run_post_process_scripts(src_path, false, "File", src_path_name, config);
}
} // namespace Slic3r

View File

@ -12,16 +12,24 @@
namespace Slic3r {
static inline char get_extrusion_axis_char(const GCodeConfig &config)
{
std::string axis = get_extrusion_axis(config);
assert(axis.size() <= 1);
// Return 0 for gcfNoExtrusion
return axis.empty() ? 0 : axis[0];
}
void GCodeReader::apply_config(const GCodeConfig &config)
{
m_config = config;
m_extrusion_axis = get_extrusion_axis(m_config)[0];
m_extrusion_axis = get_extrusion_axis_char(m_config);
}
void GCodeReader::apply_config(const DynamicPrintConfig &config)
{
m_config.apply(config, true);
m_extrusion_axis = get_extrusion_axis(m_config)[0];
m_extrusion_axis = get_extrusion_axis_char(m_config);
}
const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline, std::pair<const char*, const char*> &command)
@ -52,9 +60,10 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
case 'Z': axis = Z; break;
case 'F': axis = F; break;
default:
if (*c == m_extrusion_axis)
if (*c == m_extrusion_axis) {
if (m_extrusion_axis != 0)
axis = E;
else if (*c >= 'A' && *c <= 'Z')
} else if (*c >= 'A' && *c <= 'Z')
// Unknown axis, but we still want to remember that such a axis was seen.
axis = UNKNOWN_AXIS;
break;
@ -190,6 +199,8 @@ void GCodeReader::GCodeLine::set(const GCodeReader &reader, const Axis axis, con
match[1] = 'F';
else {
assert(axis == E);
// Extruder axis is set.
assert(reader.extrusion_axis() != 0);
match[1] = reader.extrusion_axis();
}

View File

@ -122,8 +122,9 @@ public:
float& f() { return m_position[F]; }
float f() const { return m_position[F]; }
// Returns 0 for gcfNoExtrusion.
char extrusion_axis() const { return m_extrusion_axis; }
void set_extrusion_axis(char axis) { m_extrusion_axis = axis; }
// void set_extrusion_axis(char axis) { m_extrusion_axis = axis; }
private:
const char* parse_line_internal(const char *ptr, GCodeLine &gline, std::pair<const char*, const char*> &command);

View File

@ -405,8 +405,10 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
std::ostringstream gcode;
gcode << "G1 X" << XYZF_NUM(point(0))
<< " Y" << XYZF_NUM(point(1))
<< " " << m_extrusion_axis << E_NUM(m_extruder->E());
<< " Y" << XYZF_NUM(point(1));
if (! m_extrusion_axis.empty())
// not gcfNoExtrusion
gcode << " " << m_extrusion_axis << E_NUM(m_extruder->E());
COMMENT(comment);
gcode << "\n";
return gcode.str();
@ -421,8 +423,10 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
std::ostringstream gcode;
gcode << "G1 X" << XYZF_NUM(point(0))
<< " Y" << XYZF_NUM(point(1))
<< " Z" << XYZF_NUM(point(2))
<< " " << m_extrusion_axis << E_NUM(m_extruder->E());
<< " Z" << XYZF_NUM(point(2));
if (! m_extrusion_axis.empty())
// not gcfNoExtrusion
gcode << " " << m_extrusion_axis << E_NUM(m_extruder->E());
COMMENT(comment);
gcode << "\n";
return gcode.str();
@ -474,7 +478,7 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std
gcode << "G22 ; retract\n";
else
gcode << "G10 ; retract\n";
} else {
} else if (! m_extrusion_axis.empty()) {
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
<< " F" << XYZF_NUM(m_extruder->retract_speed() * 60.);
COMMENT(comment);
@ -503,7 +507,7 @@ std::string GCodeWriter::unretract()
else
gcode << "G11 ; unretract\n";
gcode << this->reset_e();
} else {
} else if (! m_extrusion_axis.empty()) {
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
<< " F" << XYZF_NUM(m_extruder->deretract_speed() * 60.);

View File

@ -25,6 +25,7 @@ public:
Extruder* extruder() { return m_extruder; }
const Extruder* extruder() const { return m_extruder; }
// Returns empty string for gcfNoExtrusion.
std::string extrusion_axis() const { return m_extrusion_axis; }
void apply_print_config(const PrintConfig &print_config);
// Extruders are expected to be sorted in an increasing order.

View File

@ -157,6 +157,7 @@ template<class Its> bool its_is_splittable(const Its &m)
const auto& neighbor_index = ItsWithNeighborsIndex_<Its>::get_index(m);
std::vector<char> visited(its.indices.size(), false);
its_find_unvisited_neighbors(its, neighbor_index, visited);
auto faces = its_find_unvisited_neighbors(its, neighbor_index, visited);
return !faces.empty();

View File

@ -1240,221 +1240,6 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
const size_t num_layers = input_expolygons.size();
const ConstLayerPtrsAdaptor layers = print_object.layers();
#if 0
auto get_extrusion_width = [&layers = std::as_const(layers)](const size_t layer_idx) -> float {
auto extrusion_width_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
[](const LayerRegion *l1, const LayerRegion *l2) {
return l1->region().config().perimeter_extrusion_width <
l2->region().config().perimeter_extrusion_width;
});
assert(extrusion_width_it != layers[layer_idx]->regions().end());
return float((*extrusion_width_it)->region().config().perimeter_extrusion_width);
};
auto get_top_solid_layers = [&layers = std::as_const(layers)](const size_t layer_idx) -> int {
auto top_solid_layer_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
[](const LayerRegion *l1, const LayerRegion *l2) {
return l1->region().config().top_solid_layers < l2->region().config().top_solid_layers;
});
assert(top_solid_layer_it != layers[layer_idx]->regions().end());
return (*top_solid_layer_it)->region().config().top_solid_layers;
};
auto get_bottom_solid_layers = [&layers = std::as_const(layers)](const size_t layer_idx) -> int {
auto top_bottom_layer_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
[](const LayerRegion *l1, const LayerRegion *l2) {
return l1->region().config().bottom_solid_layers < l2->region().config().bottom_solid_layers;
});
assert(top_bottom_layer_it != layers[layer_idx]->regions().end());
return (*top_bottom_layer_it)->region().config().bottom_solid_layers;
};
std::vector<ExPolygons> top_layers(num_layers);
top_layers.back() = input_expolygons.back();
tbb::parallel_for(tbb::blocked_range<size_t>(1, num_layers), [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback();
float extrusion_width = 0.1f * float(scale_(get_extrusion_width(layer_idx)));
top_layers[layer_idx - 1] = diff_ex(input_expolygons[layer_idx - 1], offset_ex(input_expolygons[layer_idx], extrusion_width));
}
}); // end of parallel_for
std::vector<ExPolygons> bottom_layers(num_layers);
bottom_layers.front() = input_expolygons.front();
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers - 1), [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback();
float extrusion_width = 0.1f * float(scale_(get_extrusion_width(layer_idx)));
bottom_layers[layer_idx + 1] = diff_ex(input_expolygons[layer_idx + 1], offset_ex(input_expolygons[layer_idx], extrusion_width));
}
}); // end of parallel_for
std::vector<std::vector<ClipperLib::Paths>> triangles_by_color_raw(num_extruders, std::vector<ClipperLib::Paths>(layers.size()));
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - begin";
{
auto delta = float(10 * SCALED_EPSILON);
std::vector<float> deltas { delta, delta, delta };
Points projected_facet;
for (const ModelVolume *mv : print_object.model_object()->volumes)
if (mv->is_model_part()) {
const Transform3f tr = print_object.trafo().cast<float>() * mv->get_matrix().cast<float>();
for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) {
const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx));
if (custom_facets.indices.empty())
continue;
throw_on_cancel_callback();
for (size_t facet_idx = 0; facet_idx < custom_facets.indices.size(); ++facet_idx) {
float min_z = std::numeric_limits<float>::max();
float max_z = std::numeric_limits<float>::lowest();
std::array<Vec3f, 3> facet;
for (int p_idx = 0; p_idx < 3; ++p_idx) {
facet[p_idx] = tr * custom_facets.vertices[custom_facets.indices[facet_idx](p_idx)];
max_z = std::max(max_z, facet[p_idx].z());
min_z = std::min(min_z, facet[p_idx].z());
}
// Sort the vertices by z-axis for simplification of projected_facet on slices
std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); });
projected_facet.clear();
projected_facet.reserve(3);
for (int p_idx = 0; p_idx < 3; ++p_idx)
projected_facet.emplace_back(Point(scale_(facet[p_idx].x()), scale_(facet[p_idx].y())) - print_object.center_offset());
if (cross2((projected_facet[1] - projected_facet[0]).cast<int64_t>(), (projected_facet[2] - projected_facet[1]).cast<int64_t>()) < 0)
// Make CCW.
std::swap(projected_facet[1], projected_facet[2]);
ClipperLib::Path offsetted = mittered_offset_path_scaled(projected_facet, deltas, 3.);
// Find lowest slice not below the triangle.
auto first_layer = std::upper_bound(layers.begin(), layers.end(), float(min_z - EPSILON),
[](float z, const Layer *l1) { return z < l1->slice_z + l1->height * 0.5; });
auto last_layer = std::upper_bound(layers.begin(), layers.end(), float(max_z - EPSILON),
[](float z, const Layer *l1) { return z < l1->slice_z + l1->height * 0.5; });
if (last_layer == layers.end())
--last_layer;
if (first_layer == layers.end() || (first_layer != layers.begin() && facet[0].z() < (*first_layer)->print_z - EPSILON))
--first_layer;
for (auto layer_it = first_layer; (layer_it != (last_layer + 1) && layer_it != layers.end()); ++layer_it)
if (size_t layer_idx = layer_it - layers.begin(); ! top_layers[layer_idx].empty() || ! bottom_layers[layer_idx].empty())
triangles_by_color_raw[extruder_idx][layer_idx].emplace_back(offsetted);
}
}
}
}
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - end";
std::vector<std::vector<ExPolygons>> triangles_by_color(num_extruders, std::vector<ExPolygons>(layers.size()));
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback();
float offset_factor = 0.1f * float(scale_(get_extrusion_width(layer_idx)));
for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id)
if (ClipperLib::Paths &src_paths = triangles_by_color_raw[extruder_id][layer_idx]; !src_paths.empty())
triangles_by_color[extruder_id][layer_idx] = offset_ex(offset_ex(ClipperPaths_to_Slic3rExPolygons(src_paths), -offset_factor), offset_factor);
}
}); // end of parallel_for
triangles_by_color_raw.clear();
std::vector<std::vector<ExPolygons>> triangles_by_color_bottom(num_extruders);
std::vector<std::vector<ExPolygons>> triangles_by_color_top(num_extruders);
triangles_by_color_bottom.assign(num_extruders, std::vector<ExPolygons>(num_layers));
triangles_by_color_top.assign(num_extruders, std::vector<ExPolygons>(num_layers));
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - begin";
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
float extrusion_width = scale_(get_extrusion_width(layer_idx));
int top_solid_layers = get_top_solid_layers(layer_idx);
ExPolygons top_expolygon = top_layers[layer_idx];
if (top_expolygon.empty())
continue;
for (size_t color_idx = 0; color_idx < triangles_by_color.size(); ++color_idx) {
throw_on_cancel_callback();
if (triangles_by_color[color_idx][layer_idx].empty())
continue;
ExPolygons intersection_poly = intersection_ex(triangles_by_color[color_idx][layer_idx], top_expolygon);
if (!intersection_poly.empty()) {
triangles_by_color_top[color_idx][layer_idx].insert(triangles_by_color_top[color_idx][layer_idx].end(), intersection_poly.begin(),
intersection_poly.end());
for (int last_idx = int(layer_idx) - 1; last_idx >= std::max(int(layer_idx - top_solid_layers), int(0)); --last_idx) {
float offset_value = float(layer_idx - last_idx) * (-1.0f) * extrusion_width;
if (offset_ex(top_expolygon, offset_value).empty())
continue;
ExPolygons layer_slices_trimmed = input_expolygons[last_idx];
for (int last_idx_1 = last_idx; last_idx_1 < int(layer_idx); ++last_idx_1) {
layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx_1 + 1]);
}
ExPolygons offset_e = offset_ex(layer_slices_trimmed, offset_value);
ExPolygons intersection_poly_2 = intersection_ex(triangles_by_color_top[color_idx][layer_idx], offset_e);
triangles_by_color_top[color_idx][last_idx].insert(triangles_by_color_top[color_idx][last_idx].end(), intersection_poly_2.begin(),
intersection_poly_2.end());
}
}
}
}
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - end";
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - begin";
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
float extrusion_width = scale_(get_extrusion_width(layer_idx));
int bottom_solid_layers = get_bottom_solid_layers(layer_idx);
const ExPolygons &bottom_expolygon = bottom_layers[layer_idx];
if (bottom_expolygon.empty())
continue;
for (size_t color_idx = 0; color_idx < triangles_by_color.size(); ++color_idx) {
throw_on_cancel_callback();
if (triangles_by_color[color_idx][layer_idx].empty())
continue;
ExPolygons intersection_poly = intersection_ex(triangles_by_color[color_idx][layer_idx], bottom_expolygon);
if (!intersection_poly.empty()) {
triangles_by_color_bottom[color_idx][layer_idx].insert(triangles_by_color_bottom[color_idx][layer_idx].end(), intersection_poly.begin(),
intersection_poly.end());
for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + bottom_solid_layers, num_layers); ++last_idx) {
float offset_value = float(last_idx - layer_idx) * (-1.0f) * extrusion_width;
if (offset_ex(bottom_expolygon, offset_value).empty())
continue;
ExPolygons layer_slices_trimmed = input_expolygons[last_idx];
for (int last_idx_1 = int(last_idx); last_idx_1 > int(layer_idx); --last_idx_1) {
layer_slices_trimmed = intersection_ex(layer_slices_trimmed, offset_ex(input_expolygons[last_idx_1 - 1], offset_value));
}
ExPolygons offset_e = offset_ex(layer_slices_trimmed, offset_value);
ExPolygons intersection_poly_2 = intersection_ex(triangles_by_color_bottom[color_idx][layer_idx], offset_e);
append(triangles_by_color_bottom[color_idx][last_idx], std::move(intersection_poly_2));
}
}
}
}
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - end";
std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_extruders);
triangles_by_color_merged.assign(num_extruders, std::vector<ExPolygons>(num_layers));
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
throw_on_cancel_callback();
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
auto &self = triangles_by_color_merged[color_idx][layer_idx];
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx]));
append(self, std::move(triangles_by_color_top[color_idx][layer_idx]));
self = union_ex(self);
}
// Cut all colors for cases when two colors are overlapping
for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) {
triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx],
triangles_by_color_merged[color_idx - 1][layer_idx]);
}
}
#else
// Maximum number of top / bottom layers accounts for maximum overlap of one thread group into a neighbor thread group.
int max_top_layers = 0;
int max_bottom_layers = 0;
@ -1470,8 +1255,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
// project downards pointing painted triangles over bottom surfaces.
std::vector<std::vector<Polygons>> top_raw(num_extruders), bottom_raw(num_extruders);
std::vector<float> zs = zs_from_layers(print_object.layers());
Transform3d object_trafo = print_object.trafo();
object_trafo.pretranslate(Vec3d(- unscale<double>(print_object.center_offset().x()), - unscale<double>(print_object.center_offset().y()), 0));
Transform3d object_trafo = print_object.trafo_centered();
#ifdef MMU_SEGMENTATION_DEBUG_TOP_BOTTOM
static int iRun = 0;
@ -1650,7 +1434,6 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
triangles_by_color_merged[color_idx - 1][layer_idx]);
}
});
#endif
return triangles_by_color_merged;
}

View File

@ -191,7 +191,9 @@ void PresetBundle::setup_directories()
PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule, const std::string &preferred_model_id)
{
// First load the vendor specific system presets.
std::string errors_cummulative = this->load_system_presets();
PresetsConfigSubstitutions substitutions;
std::string errors_cummulative;
std::tie(substitutions, errors_cummulative) = this->load_system_presets(substitution_rule);
const std::string dir_user_presets = data_dir()
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
@ -202,7 +204,6 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
#endif
;
PresetsConfigSubstitutions substitutions;
try {
this->prints.load_presets(dir_user_presets, "print", substitutions, substitution_rule);
} catch (const std::runtime_error &err) {
@ -245,10 +246,18 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
// Load system presets into this PresetBundle.
// For each vendor, there will be a single PresetBundle loaded.
std::string PresetBundle::load_system_presets()
std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule)
{
if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSystemSilent)
// Loading system presets, don't log substitutions.
compatibility_rule = ForwardCompatibilitySubstitutionRule::EnableSilent;
else if (compatibility_rule == ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem)
// Loading system presets, throw on unknown option value.
compatibility_rule = ForwardCompatibilitySubstitutionRule::Disable;
// Here the vendor specific read only Config Bundles are stored.
boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / "vendor").make_preferred();
PresetsConfigSubstitutions substitutions;
std::string errors_cummulative;
bool first = true;
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
@ -260,13 +269,13 @@ std::string PresetBundle::load_system_presets()
// Load the config bundle, flatten it.
if (first) {
// Reset this PresetBundle and load the first vendor config.
this->load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem);
append(substitutions, this->load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem, compatibility_rule).first);
first = false;
} else {
// Load the other vendor configs, merge them with this PresetBundle.
// Report duplicate profiles.
PresetBundle other;
other.load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem);
append(substitutions, other.load_configbundle(dir_entry.path().string(), PresetBundle::LoadSystem, compatibility_rule).first);
std::vector<std::string> duplicates = this->merge_presets(std::move(other));
if (! duplicates.empty()) {
errors_cummulative += "Vendor configuration file " + name + " contains the following presets with names used by other vendors: ";
@ -288,7 +297,7 @@ std::string PresetBundle::load_system_presets()
}
this->update_system_maps();
return errors_cummulative;
return std::make_pair(std::move(substitutions), errors_cummulative);
}
// Merge one vendor's presets with the other vendor's presets, report duplicates.
@ -700,7 +709,7 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
if (is_gcode_file(path)) {
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, true /* check_header */, compatibility_rule);
ConfigSubstitutions config_substitutions = config.load_from_gcode_file(path, compatibility_rule);
Preset::normalize(config);
load_config_file_config(path, true, std::move(config));
return config_substitutions;
@ -714,8 +723,8 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
} catch (const std::ifstream::failure &err) {
throw Slic3r::RuntimeError(std::string("The Config Bundle cannot be loaded: ") + path + "\n\tReason: " + err.what());
} catch (const boost::property_tree::file_parser_error &err) {
throw Slic3r::RuntimeError((boost::format("Failed loading the Config Bundle \"%1%\": %2% at line %3%")
% err.filename() % err.message() % err.line()).str());
throw Slic3r::RuntimeError(format("Failed loading the Config Bundle \"%1%\": %2% at line %3%",
err.filename(), err.message(), err.line()));
} catch (const std::runtime_error &err) {
throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + path + "\n\tReason: " + err.what());
}
@ -723,6 +732,7 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
// 2) Continue based on the type of the configuration file.
ConfigFileType config_file_type = guess_config_file_type(tree);
ConfigSubstitutions config_substitutions;
try {
switch (config_file_type) {
case CONFIG_FILE_TYPE_UNKNOWN:
throw Slic3r::RuntimeError(std::string("Unknown configuration file type: ") + path);
@ -739,7 +749,10 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw
return config_substitutions;
}
case CONFIG_FILE_TYPE_CONFIG_BUNDLE:
return load_config_file_config_bundle(path, tree);
return load_config_file_config_bundle(path, tree, compatibility_rule);
}
} catch (const ConfigurationError &e) {
throw Slic3r::RuntimeError(format("Invalid configuration file %1%: %2%", path, e.what()));
}
// This shall never happen. Suppres compiler warnings.
@ -916,13 +929,14 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
}
// Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file.
ConfigSubstitutions PresetBundle::load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree)
ConfigSubstitutions PresetBundle::load_config_file_config_bundle(
const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// 1) Load the config bundle into a temp data.
PresetBundle tmp_bundle;
// Load the config bundle, but don't save the loaded presets to user profile directory, as only the presets marked as active in the loaded preset bundle
// will be loaded into the master PresetBundle and activated.
auto [presets_substitutions, presets_imported] = tmp_bundle.load_configbundle(path, {});
auto [presets_substitutions, presets_imported] = tmp_bundle.load_configbundle(path, {}, compatibility_rule);
UNUSED(presets_imported);
std::string bundle_name = std::string(" - ") + boost::filesystem::path(path).filename().string();
@ -1135,15 +1149,11 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree, co
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(const std::string &path, LoadConfigBundleAttributes flags)
std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(
const std::string &path, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
// Enable substitutions for user config bundle, throw an exception when loading a system profile.
ConfigSubstitutionContext substitution_context {
flags.has(LoadConfigBundleAttribute::LoadSystem) ?
ForwardCompatibilitySubstitutionRule::Disable :
ForwardCompatibilitySubstitutionRule::Enable
};
ConfigSubstitutionContext substitution_context { compatibility_rule };
PresetsConfigSubstitutions substitutions;
if (flags.has(LoadConfigBundleAttribute::ResetUserProfile) || flags.has(LoadConfigBundleAttribute::LoadSystem))
@ -1275,6 +1285,7 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(co
DynamicPrintConfig config;
std::string alias_name;
std::vector<std::string> renamed_from;
try {
auto parse_config_section = [&section, &alias_name, &renamed_from, &substitution_context, &path](DynamicPrintConfig &config) {
substitution_context.substitutions.clear();
for (auto &kvp : section.second) {
@ -1302,6 +1313,9 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(co
config = *default_config;
parse_config_section(config);
}
} catch (const ConfigurationError &e) {
throw ConfigurationError(format("Invalid configuration bundle \"%1%\", section [%2%]: ", path, section.first) + e.what());
}
Preset::normalize(config);
// Report configuration fields, which are misplaced into a wrong group.
std::string incorrect_keys = Preset::remove_invalid_keys(config, *default_config);
@ -1408,8 +1422,12 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(co
DynamicPrintConfig config = default_config;
substitution_context.substitutions.clear();
try {
for (auto& kvp : section.second)
config.set_deserialize(kvp.first, kvp.second.data(), substitution_context);
} catch (const ConfigurationError &e) {
throw ConfigurationError(format("Invalid configuration bundle \"%1%\", section [%2%]: ", path, section.first) + e.what());
}
// Report configuration fields, which are misplaced into a wrong group.
std::string incorrect_keys = Preset::remove_invalid_keys(config, default_config);

View File

@ -102,7 +102,8 @@ public:
using LoadConfigBundleAttributes = enum_bitmask<LoadConfigBundleAttribute>;
// Load the config bundle based on the flags.
// Don't do any config substitutions when loading a system profile, perform and report substitutions otherwise.
std::pair<PresetsConfigSubstitutions, size_t> load_configbundle(const std::string &path, LoadConfigBundleAttributes flags);
std::pair<PresetsConfigSubstitutions, size_t> load_configbundle(
const std::string &path, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule);
// Export a config bundle file containing all the presets and the names of the active presets.
void export_configbundle(const std::string &path, bool export_system_settings = false, bool export_physical_printers = false);
@ -139,7 +140,7 @@ public:
static const char *PRUSA_BUNDLE;
private:
std::string load_system_presets();
std::pair<PresetsConfigSubstitutions, std::string> load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule);
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> merge_presets(PresetBundle &&other);
// Update renamed_from and alias maps of system profiles.
@ -158,7 +159,8 @@ private:
// and the external config is just referenced, not stored into user profile directory.
// If it is not an external config, then the config will be stored into the user profile directory.
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
ConfigSubstitutions load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
ConfigSubstitutions load_config_file_config_bundle(
const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);
DynamicPrintConfig full_fff_config() const;
DynamicPrintConfig full_sla_config() const;

View File

@ -253,6 +253,9 @@ public:
ConstLayerPtrsAdaptor layers() const { return ConstLayerPtrsAdaptor(&m_layers); }
ConstSupportLayerPtrsAdaptor support_layers() const { return ConstSupportLayerPtrsAdaptor(&m_support_layers); }
const Transform3d& trafo() const { return m_trafo; }
// Trafo with the center_offset() applied after the transformation, to center the object in XY before slicing.
Transform3d trafo_centered() const
{ Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale<double>(m_center_offset.x()), - unscale<double>(m_center_offset.y()), 0)); return t; }
const PrintInstances& instances() const { return m_instances; }
// Whoever will get a non-const pointer to PrintObject will be able to modify its layers.

View File

@ -234,7 +234,7 @@ void PrintConfigDef::init_common_params()
def = this->add("thumbnails", coPoints);
def->label = L("G-code thumbnails");
def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 files, in the following format: \"XxY, XxY, ...\"");
def->tooltip = L("Picture sizes to be stored into a .gcode and .sl1 / .sl1s files, in the following format: \"XxY, XxY, ...\"");
def->mode = comExpert;
def->gui_type = ConfigOptionDef::GUIType::one_string;
def->set_default_value(new ConfigOptionPoints());
@ -493,7 +493,7 @@ void PrintConfigDef::init_fff_params()
def->category = L("Skirt and brim");
def->tooltip = L("The offset of the brim from the printed object.");
def->sidetext = L("mm");
def->mode = comSimple;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("clip_multipart_objects", coBool);

View File

@ -428,10 +428,8 @@ std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> PrintObject::prepare
indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set();
// Rotate mesh and build octree on it with axis-aligned (standart base) cubes.
Transform3d m = m_trafo;
m.pretranslate(Vec3d(- unscale<float>(m_center_offset.x()), - unscale<float>(m_center_offset.y()), 0));
auto to_octree = transform_to_octree().toRotationMatrix();
its_transform(mesh, to_octree * m, true);
its_transform(mesh, to_octree * this->trafo_centered(), true);
// Triangulate internal bridging surfaces.
std::vector<std::vector<Vec3d>> overhangs(this->layers().size());
@ -2298,7 +2296,7 @@ void PrintObject::project_and_append_custom_facets(
: mv->supported_facets.get_facets_strict(*mv, type);
if (! custom_facets.indices.empty())
project_triangles_to_slabs(this->layers(), custom_facets,
(Eigen::Translation3d(to_3d(unscaled<double>(this->center_offset()), 0.)) * this->trafo() * mv->get_matrix()).cast<float>(),
(this->trafo_centered() * mv->get_matrix()).cast<float>(),
seam, out);
}
}

View File

@ -695,11 +695,9 @@ void PrintObject::slice_volumes()
}
std::vector<float> slice_zs = zs_from_layers(m_layers);
Transform3d trafo = this->trafo();
trafo.pretranslate(Vec3d(- unscale<double>(m_center_offset.x()), - unscale<double>(m_center_offset.y()), 0));
std::vector<std::vector<ExPolygons>> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs,
slice_volumes_inner(
print->config(), this->config(), trafo,
print->config(), this->config(), this->trafo_centered(),
this->model_object()->volumes, m_shared_regions->layer_ranges, slice_zs, throw_on_cancel_callback),
m_config.clip_multipart_objects,
throw_on_cancel_callback);
@ -832,8 +830,7 @@ std::vector<Polygons> PrintObject::slice_support_volumes(const ModelVolumeType m
const Print *print = this->print();
auto throw_on_cancel_callback = std::function<void()>([print](){ print->throw_if_canceled(); });
MeshSlicingParamsEx params;
params.trafo = this->trafo();
params.trafo.pretranslate(Vec3d(-unscale<float>(m_center_offset.x()), -unscale<float>(m_center_offset.y()), 0));
params.trafo = this->trafo_centered();
for (; it_volume != it_volume_end; ++ it_volume)
if ((*it_volume)->type() == model_volume_type) {
std::vector<ExPolygons> slices2 = slice_volume(*(*it_volume), zs, params, throw_on_cancel_callback);

View File

@ -1,5 +1,6 @@
#include "QuadricEdgeCollapse.hpp"
#include <tuple>
#include <optional>
#include "MutablePriorityQueue.hpp"
#include "SimplifyMeshImpl.hpp"
#include <tbb/parallel_for.h>

View File

@ -25,8 +25,17 @@ public:
Semver() : ver(semver_zero()) {}
Semver(int major, int minor, int patch,
boost::optional<const std::string&> metadata = boost::none,
boost::optional<const std::string&> prerelease = boost::none)
boost::optional<const std::string&> metadata, boost::optional<const std::string&> prerelease)
: ver(semver_zero())
{
ver.major = major;
ver.minor = minor;
ver.patch = patch;
set_metadata(metadata);
set_prerelease(prerelease);
}
Semver(int major, int minor, int patch, const char *metadata = nullptr, const char *prerelease = nullptr)
: ver(semver_zero())
{
ver.major = major;
@ -102,7 +111,9 @@ public:
void set_min(int min) { ver.minor = min; }
void set_patch(int patch) { ver.patch = patch; }
void set_metadata(boost::optional<const std::string&> meta) { ver.metadata = meta ? strdup(*meta) : nullptr; }
void set_metadata(const char *meta) { ver.metadata = meta ? strdup(meta) : nullptr; }
void set_prerelease(boost::optional<const std::string&> pre) { ver.prerelease = pre ? strdup(*pre) : nullptr; }
void set_prerelease(const char *pre) { ver.prerelease = pre ? strdup(pre) : nullptr; }
// Comparison
bool operator<(const Semver &b) const { return ::semver_compare(ver, b.ver) == -1; }

View File

@ -178,12 +178,12 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
}
}
void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, float seed_fill_angle)
void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, float seed_fill_angle, bool force_reselection)
{
assert(facet_start < m_orig_size_indices);
// Recompute seed fill only if the cursor is pointing on facet unselected by seed fill.
if (int start_facet_idx = select_unsplit_triangle(hit, facet_start); start_facet_idx >= 0 && m_triangles[start_facet_idx].is_selected_by_seed_fill())
if (int start_facet_idx = select_unsplit_triangle(hit, facet_start); start_facet_idx >= 0 && m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection)
return;
this->seed_fill_unselect_all_triangles();
@ -278,7 +278,7 @@ void TriangleSelector::append_touching_subtriangles(int itriangle, int vertexi,
return;
auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_subtriangles_out](const int subtriangle_idx, Partition partition) -> void {
assert(subtriangle_idx == -1);
assert(subtriangle_idx != -1);
if (!m_triangles[subtriangle_idx].is_split())
touching_subtriangles_out.emplace_back(subtriangle_idx);
else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1)
@ -295,11 +295,48 @@ void TriangleSelector::append_touching_subtriangles(int itriangle, int vertexi,
process_subtriangle(touching.second, Partition::Second);
}
void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate)
// It appends all edges that are touching the edge (vertexi, vertexj) of the triangle and are not selected by seed fill
// It doesn't append the edges that are touching the triangle only by part of the edge that means the triangles are from lower depth.
void TriangleSelector::append_touching_edges(int itriangle, int vertexi, int vertexj, std::vector<Vec2i> &touching_edges_out) const
{
if (itriangle == -1)
return;
auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_edges_out](const int subtriangle_idx, Partition partition) -> void {
assert(subtriangle_idx != -1);
if (!m_triangles[subtriangle_idx].is_split()) {
if (!m_triangles[subtriangle_idx].is_selected_by_seed_fill()) {
int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj);
if (partition == Partition::First && midpoint != -1) {
touching_edges_out.emplace_back(vertexi, midpoint);
} else if (partition == Partition::First && midpoint == -1) {
touching_edges_out.emplace_back(vertexi, vertexj);
} else {
assert(midpoint != -1 && partition == Partition::Second);
touching_edges_out.emplace_back(midpoint, vertexj);
}
}
} else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1)
append_touching_edges(subtriangle_idx, partition == Partition::First ? vertexi : midpoint, partition == Partition::First ? midpoint : vertexj,
touching_edges_out);
else
append_touching_edges(subtriangle_idx, vertexi, vertexj, touching_edges_out);
};
std::pair<int, int> touching = this->triangle_subtriangles(itriangle, vertexi, vertexj);
if (touching.first != -1)
process_subtriangle(touching.first, Partition::First);
if (touching.second != -1)
process_subtriangle(touching.second, Partition::Second);
}
void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate, bool force_reselection)
{
int start_facet_idx = select_unsplit_triangle(hit, facet_start);
assert(start_facet_idx != -1);
// Recompute bucket fill only if the cursor is pointing on facet unselected by bucket fill.
if (start_facet_idx == -1 || m_triangles[start_facet_idx].is_selected_by_seed_fill())
if (start_facet_idx == -1 || (m_triangles[start_facet_idx].is_selected_by_seed_fill() && !force_reselection))
return;
assert(!m_triangles[start_facet_idx].is_split());
@ -312,7 +349,7 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_
}
auto get_all_touching_triangles = [this](int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated) -> std::vector<int> {
assert(facet_idx != -1 && facet_idx < m_triangles.size());
assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
std::vector<int> touching_triangles;
Vec3i vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]};
@ -1358,6 +1395,48 @@ void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const
}
}
std::vector<Vec2i> TriangleSelector::get_seed_fill_contour() const {
std::vector<Vec2i> edges_out;
for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) {
const Vec3i neighbors = root_neighbors(*m_mesh, facet_idx);
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
this->get_seed_fill_contour_recursive(facet_idx, neighbors, neighbors, edges_out);
}
return edges_out;
}
void TriangleSelector::get_seed_fill_contour_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec2i> &edges_out) const {
assert(facet_idx != -1 && facet_idx < int(m_triangles.size()));
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
const Triangle *tr = &m_triangles[facet_idx];
if (!tr->valid())
return;
if (tr->is_split()) {
int num_of_children = tr->number_of_split_sides() + 1;
if (num_of_children != 1) {
for (int i = 0; i < num_of_children; ++i) {
assert(i < int(tr->children.size()));
assert(tr->children[i] < int(m_triangles.size()));
// Recursion, deep first search over the children of this triangle.
// All children of this triangle were created by splitting a single source triangle of the original mesh.
this->get_seed_fill_contour_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), this->child_neighbors_propagated(*tr, neighbors_propagated, i), edges_out);
}
}
} else if (tr->is_selected_by_seed_fill()) {
Vec3i vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]};
append_touching_edges(neighbors(0), vertices(1), vertices(0), edges_out);
append_touching_edges(neighbors(1), vertices(2), vertices(1), edges_out);
append_touching_edges(neighbors(2), vertices(0), vertices(2), edges_out);
// It appends the edges that are touching the triangle only by part of the edge that means the triangles are from lower depth.
for (int idx = 0; idx < 3; ++idx)
if (int neighbor_tr_idx = neighbors_propagated(idx); neighbor_tr_idx != -1 && !m_triangles[neighbor_tr_idx].is_split() && !m_triangles[neighbor_tr_idx].is_selected_by_seed_fill())
edges_out.emplace_back(vertices(idx), vertices(next_idx_modulo(idx, 3)));
}
}
std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> TriangleSelector::serialize() const
{
// Each original triangle of the mesh is assigned a number encoding its state

View File

@ -49,11 +49,13 @@ public:
void seed_fill_select_triangles(const Vec3f &hit, // point where to start
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
float seed_fill_angle); // the maximal angle between two facets to be painted by the same color
float seed_fill_angle, // the maximal angle between two facets to be painted by the same color
bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle
void bucket_fill_select_triangles(const Vec3f &hit, // point where to start
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
bool propagate); // if bucket fill is propagated to neighbor faces or if it fills the only facet of the modified mesh that the hit point belongs to.
bool propagate, // if bucket fill is propagated to neighbor faces or if it fills the only facet of the modified mesh that the hit point belongs to.
bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle
bool has_facets(EnforcerBlockerType state) const;
static bool has_facets(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data, EnforcerBlockerType test_state);
@ -62,6 +64,8 @@ public:
indexed_triangle_set get_facets(EnforcerBlockerType state) const;
// Get facets at a given state. Triangulate T-joints.
indexed_triangle_set get_facets_strict(EnforcerBlockerType state) const;
// Get edges around the selected area by seed fill.
std::vector<Vec2i> get_seed_fill_contour() const;
// Set facet of the mesh to a given state. Only works for original triangles.
void set_facet(int facet_idx, EnforcerBlockerType state);
@ -221,6 +225,7 @@ private:
std::pair<int, int> triangle_subtriangles(int itriangle, int vertexi, int vertexj) const;
void append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector<int> &touching_subtriangles_out) const;
void append_touching_edges(int itriangle, int vertexi, int vertexj, std::vector<Vec2i> &touching_edges_out) const;
#ifndef NDEBUG
bool verify_triangle_neighbors(const Triangle& tr, const Vec3i& neighbors) const;
@ -234,6 +239,8 @@ private:
std::vector<stl_triangle_vertex_indices> &out_triangles) const;
void get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, std::vector<stl_triangle_vertex_indices> &out_triangles) const;
void get_seed_fill_contour_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector<Vec2i> &edges_out) const;
int m_free_triangles_head { -1 };
int m_free_vertices_head { -1 };
};

View File

@ -238,7 +238,7 @@ inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER
return container[next_idx_modulo(idx, container.size())];
}
extern std::string xml_escape(std::string text);
extern std::string xml_escape(std::string text, bool is_marked = false);
#if defined __GNUC__ && __GNUC__ < 5 && !defined __clang__

View File

@ -888,7 +888,7 @@ unsigned get_current_pid()
#endif
}
std::string xml_escape(std::string text)
std::string xml_escape(std::string text, bool is_marked/* = false*/)
{
std::string::size_type pos = 0;
for (;;)
@ -903,8 +903,8 @@ std::string xml_escape(std::string text)
case '\"': replacement = "&quot;"; break;
case '\'': replacement = "&apos;"; break;
case '&': replacement = "&amp;"; break;
case '<': replacement = "&lt;"; break;
case '>': replacement = "&gt;"; break;
case '<': replacement = is_marked ? "<" :"&lt;"; break;
case '>': replacement = is_marked ? ">" :"&gt;"; break;
default: break;
}

View File

@ -8,14 +8,23 @@
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/log/trivial.hpp>
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/format.hpp"
#include "libslic3r/libslic3r.h"
#include "libslic3r/Time.hpp"
#include "libslic3r/Config.hpp"
#include "libslic3r/FileParserError.hpp"
#include "libslic3r/Utils.hpp"
#include "../GUI/GUI.hpp"
#include "../GUI/GUI_App.hpp"
#include "../GUI/I18N.hpp"
#include "../GUI/MainFrame.hpp"
#include <wx/richmsgdlg.h>
#define SLIC3R_SNAPSHOTS_DIR "snapshots"
#define SLIC3R_SNAPSHOT_FILE "snapshot.ini"
@ -358,11 +367,12 @@ static void copy_config_dir_single_level(const boost::filesystem::path &path_src
{
if (! boost::filesystem::is_directory(path_dst) &&
! boost::filesystem::create_directory(path_dst))
throw Slic3r::RuntimeError(std::string("Slic3r was unable to create a directory at ") + path_dst.string());
throw Slic3r::RuntimeError(std::string("PrusaSlicer was unable to create a directory at ") + path_dst.string());
for (auto &dir_entry : boost::filesystem::directory_iterator(path_src))
if (Slic3r::is_ini_file(dir_entry))
boost::filesystem::copy_file(dir_entry.path(), path_dst / dir_entry.path().filename(), boost::filesystem::copy_option::overwrite_if_exists);
if (std::string error_message; copy_file(dir_entry.path().string(), (path_dst / dir_entry.path().filename()).string(), error_message, false) != SUCCESS)
throw Slic3r::RuntimeError(format("Failed copying \"%1%\" to \"%2%\": %3%", path_src.string(), path_dst.string(), error_message));
}
static void delete_existing_ini_files(const boost::filesystem::path &path)
@ -413,7 +423,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot:
++ it;
// Read the active config bundle, parse the config version.
PresetBundle bundle;
bundle.load_configbundle((data_dir / "vendor" / (cfg.name + ".ini")).string(), PresetBundle::LoadConfigBundleAttribute::LoadVendorOnly);
bundle.load_configbundle((data_dir / "vendor" / (cfg.name + ".ini")).string(), PresetBundle::LoadConfigBundleAttribute::LoadVendorOnly, ForwardCompatibilitySubstitutionRule::EnableSilent);
for (const auto &vp : bundle.vendors)
if (vp.second.id == cfg.name)
cfg.version.config_version = vp.second.config_version;
@ -433,6 +443,8 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot:
}
boost::filesystem::path snapshot_dir = snapshot_db_dir / snapshot.id;
try {
boost::filesystem::create_directory(snapshot_dir);
// Backup the presets.
@ -441,6 +453,17 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot:
snapshot.save_ini((snapshot_dir / "snapshot.ini").string());
assert(m_snapshots.empty() || m_snapshots.back().time_captured <= snapshot.time_captured);
m_snapshots.emplace_back(std::move(snapshot));
} catch (...) {
if (boost::filesystem::is_directory(snapshot_dir)) {
try {
// Clean up partially copied snapshot.
boost::filesystem::remove_all(snapshot_dir);
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "Failed taking snapshot and failed removing the snapshot directory " << snapshot_dir;
}
}
throw;
}
return m_snapshots.back();
}
@ -551,6 +574,32 @@ SnapshotDB& SnapshotDB::singleton()
return instance;
}
const Snapshot* take_config_snapshot_report_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment)
{
try {
return &SnapshotDB::singleton().take_snapshot(app_config, reason, comment);
} catch (std::exception &err) {
show_error(static_cast<wxWindow*>(wxGetApp().mainframe),
_L("Taking a configuration snapshot failed.") + "\n\n" + from_u8(err.what()));
return nullptr;
}
}
bool take_config_snapshot_cancel_on_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment, const std::string &message)
{
try {
SnapshotDB::singleton().take_snapshot(app_config, reason, comment);
return true;
} catch (std::exception &err) {
wxRichMessageDialog dlg(static_cast<wxWindow*>(wxGetApp().mainframe),
_L("PrusaSlicer has encountered an error while taking a configuration snapshot.") + "\n\n" + from_u8(err.what()) + "\n\n" + from_u8(message),
_L("PrusaSlicer error"),
wxYES_NO);
dlg.SetYesNoLabels(_L("Continue"), _L("Abort"));
return dlg.ShowModal() == wxID_YES;
}
}
} // namespace Config
} // namespace GUI
} // namespace Slic3r

View File

@ -127,6 +127,13 @@ private:
std::vector<Snapshot> m_snapshots;
};
// Take snapshot on SnapshotDB::singleton(). If taking snapshot fails, report an error and return nullptr.
const Snapshot* take_config_snapshot_report_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment);
// Take snapshot on SnapshotDB::singleton(). If taking snapshot fails, report "message", and present a "Continue" or "Abort" buttons to respond.
// Return true on success and on "Continue" to continue with the process (for example installation of presets).
bool take_config_snapshot_cancel_on_error(const AppConfig &app_config, Snapshot::Reason reason, const std::string &comment, const std::string &message);
} // namespace Config
} // namespace GUI
} // namespace Slic3r

View File

@ -843,6 +843,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
volume.first->set_render_color();
// render sinking contours of non-hovered volumes
if (m_show_sinking_contours)
if (volume.first->is_sinking() && !volume.first->is_below_printbed() &&
volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) {
shader->stop_using();
@ -887,6 +888,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
}
if (m_show_sinking_contours)
for (GLVolumeWithIdAndZ& volume : to_render) {
// render sinking contours of hovered/displaced volumes
if (volume.first->is_sinking() && !volume.first->is_below_printbed() &&

View File

@ -539,6 +539,7 @@ private:
};
Slope m_slope;
bool m_show_sinking_contours = false;
public:
GLVolumePtrs volumes;
@ -608,6 +609,7 @@ public:
float get_slope_normal_z() const { return m_slope.normal_z; }
void set_slope_normal_z(float normal_z) { m_slope.normal_z = normal_z; }
void set_default_slope_normal_z() { m_slope.normal_z = -::cos(Geometry::deg2rad(90.0f - 45.0f)); }
void set_show_sinking_contours(bool show) { m_show_sinking_contours = show; }
// returns true if all the volumes are completely contained in the print volume
// returns the containment state in the given out_state, if non-null

View File

@ -154,54 +154,7 @@ void BackgroundSlicingProcess::process_fff()
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
// let the gcode window to unmap the temporary .gcode file (m_temp_output_path)
// because the scripts may want to modify it
GUI::wxGetApp().plater()->stop_mapping_gcode_window();
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
run_post_process_scripts(m_temp_output_path, m_fff_print->full_print_config());
// let the gcode window to reload and remap the temporary .gcode file (m_temp_output_path)
GUI::wxGetApp().plater()->start_mapping_gcode_window();
//FIXME localize the messages
// Perform the final post-processing of the export path by applying the print statistics over the file name.
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
std::string error_message;
int copy_ret_val = CopyFileResult::SUCCESS;
try
{
copy_ret_val = copy_file(m_temp_output_path, export_path, error_message, m_export_path_on_removable_media);
}
catch (...)
{
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
}
switch (copy_ret_val) {
case CopyFileResult::SUCCESS: break; // no error
case CopyFileResult::FAIL_COPY_FILE:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
break;
case CopyFileResult::FAIL_FILES_DIFFERENT:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
break;
case CopyFileResult::FAIL_RENAMING:
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
break;
case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
break;
case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
break;
default:
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
break;
}
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
finalize_gcode();
} else if (! m_upload_job.empty()) {
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
prepare_upload();
@ -621,9 +574,12 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
// Some FFF status was invalidated, and the G-code was not exported yet.
// Let the G-code preview UI know that the final G-code preview is not valid.
// In addition, this early memory deallocation reduces memory footprint.
if (m_gcode_result != nullptr)
if (m_gcode_result != nullptr) {
//FIXME calling platter from here is not a staple of a good architecture.
GUI::wxGetApp().plater()->stop_mapping_gcode_window();
m_gcode_result->reset();
}
}
return invalidated;
}
@ -698,12 +654,73 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
return m_step_state.invalidate_all([this](){ this->stop_internal(); });
}
// G-code is generated in m_temp_output_path.
// Optionally run a post-processing script on a copy of m_temp_output_path.
// Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error).
void BackgroundSlicingProcess::finalize_gcode()
{
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
// Perform the final post-processing of the export path by applying the print statistics over the file name.
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
std::string output_path = m_temp_output_path;
// Both output_path and export_path ar in-out parameters.
// If post processed, output_path will differ from m_temp_output_path as run_post_process_scripts() will make a copy of the G-code to not
// collide with the G-code viewer memory mapping of the unprocessed G-code. G-code viewer maps unprocessed G-code, because m_gcode_result
// is calculated for the unprocessed G-code and it references lines in the memory mapped G-code file by line numbers.
// export_path may be changed by the post-processing script as well if the post processing script decides so, see GH #6042.
bool post_processed = run_post_process_scripts(output_path, true, "File", export_path, m_fff_print->full_print_config());
auto remove_post_processed_temp_file = [post_processed, &output_path]() {
if (post_processed)
try {
boost::filesystem::remove(output_path);
} catch (const std::exception &ex) {
BOOST_LOG_TRIVIAL(error) << "Failed to remove temp file " << output_path << ": " << ex.what();
}
};
//FIXME localize the messages
std::string error_message;
int copy_ret_val = CopyFileResult::SUCCESS;
try
{
copy_ret_val = copy_file(output_path, export_path, error_message, m_export_path_on_removable_media);
remove_post_processed_temp_file();
}
catch (...)
{
remove_post_processed_temp_file();
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
}
switch (copy_ret_val) {
case CopyFileResult::SUCCESS: break; // no error
case CopyFileResult::FAIL_COPY_FILE:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
break;
case CopyFileResult::FAIL_FILES_DIFFERENT:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
break;
case CopyFileResult::FAIL_RENAMING:
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
break;
case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % output_path % export_path).str());
break;
case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED:
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
break;
default:
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
break;
}
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
}
// A print host upload job has been scheduled, enqueue it to the printhost job queue
void BackgroundSlicingProcess::prepare_upload()
{
// A print host upload job has been scheduled, enqueue it to the printhost job queue
// XXX: is fs::path::string() right?
// Generate a unique temp path to which the gcode/zip file is copied/exported
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path("." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%");
@ -711,11 +728,15 @@ void BackgroundSlicingProcess::prepare_upload()
if (m_print == m_fff_print) {
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
std::string error_message;
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS) {
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS)
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
}
run_post_process_scripts(source_path.string(), m_fff_print->full_print_config());
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
// Make a copy of the source path, as run_post_process_scripts() is allowed to change it when making a copy of the source file
// (not here, but when the final target is a file).
std::string source_path_str = source_path.string();
std::string output_name_str = m_upload_job.upload_data.upload_path.string();
if (run_post_process_scripts(source_path_str, false, m_upload_job.printhost->get_name(), output_name_str, m_fff_print->full_print_config()))
m_upload_job.upload_data.upload_path = output_name_str;
} else {
m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());

View File

@ -262,6 +262,7 @@ private:
bool invalidate_all_steps();
// If the background processing stop was requested, throw CanceledException.
void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); }
void finalize_gcode();
void prepare_upload();
// To be executed at the background thread.
ThumbnailsList render_thumbnails(const ThumbnailsParams &params);

View File

@ -65,7 +65,9 @@ bool Bundle::load(fs::path source_path, bool ais_in_resources, bool ais_prusa_bu
this->is_prusa_bundle = ais_prusa_bundle;
std::string path_string = source_path.string();
auto [config_substitutions, presets_loaded] = preset_bundle->load_configbundle(path_string, PresetBundle::LoadConfigBundleAttribute::LoadSystem);
// Throw when parsing invalid configuration. Only valid configuration is supposed to be provided over the air.
auto [config_substitutions, presets_loaded] = preset_bundle->load_configbundle(
path_string, PresetBundle::LoadConfigBundleAttribute::LoadSystem, ForwardCompatibilitySubstitutionRule::Disable);
UNUSED(config_substitutions);
// No substitutions shall be reported when loading a system config bundle, no substitutions are allowed.
assert(config_substitutions.empty());
@ -2451,7 +2453,7 @@ bool ConfigWizard::priv::check_and_install_missing_materials(Technology technolo
return true;
}
void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater)
bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater)
{
const auto enabled_vendors = appconfig_new.vendors();
@ -2506,14 +2508,14 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
break;
}
if (snapshot) {
SnapshotDB::singleton().take_snapshot(*app_config, snapshot_reason);
}
if (snapshot && ! take_config_snapshot_cancel_on_error(*app_config, snapshot_reason, "", _u8L("Continue with applying configuration changes?")))
return false;
if (install_bundles.size() > 0) {
// Install bundles from resources.
// Don't create snapshot - we've already done that above if applicable.
updater->install_bundles_rsrc(std::move(install_bundles), false);
if (! updater->install_bundles_rsrc(std::move(install_bundles), false))
return false;
} else {
BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resources";
}
@ -2590,7 +2592,8 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
// Reloading the configs after some modifications were done to PrusaSlicer.ini.
// Just perform the substitutions silently, as the substitutions were already presented to the user on application start-up
// and the Wizard shall not create any new values that would require substitution.
PresetsConfigSubstitutions substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilent, preferred_model);
// Throw on substitutions in system profiles, as the system profiles provided over the air should be compatible with this PrusaSlicer version.
preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, preferred_model);
if (page_custom->custom_wanted()) {
page_firmware->apply_custom_config(*custom_config);
@ -2604,6 +2607,8 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
// Update the selections from the compatibilty.
preset_bundle->export_selections(*app_config);
return true;
}
void ConfigWizard::priv::update_presets_in_config(const std::string& section, const std::string& alias_key, bool add)
{
@ -2814,7 +2819,8 @@ bool ConfigWizard::run(RunReason reason, StartPage start_page)
p->set_start_page(start_page);
if (ShowModal() == wxID_OK) {
p->apply_config(app.app_config, app.preset_bundle, app.preset_updater);
if (! p->apply_config(app.app_config, app.preset_bundle, app.preset_updater))
return false;
app.app_config->set_legacy_datadir(false);
app.update_mode();
app.obj_manipul()->update_ui_from_settings();

View File

@ -611,7 +611,7 @@ struct ConfigWizard::priv
bool on_bnt_finish();
bool check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id = std::string());
void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater);
bool apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater);
// #ys_FIXME_alise
void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add);
#ifdef __linux__

View File

@ -11,6 +11,7 @@
#include "GUI_Utils.hpp"
#include "MsgDialog.hpp"
#include "Tab.hpp"
#include "GUI_ObjectList.hpp"
#include <wx/button.h>
#include <wx/dialog.h>
@ -383,7 +384,11 @@ void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
// Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one
post_ticks_changed_event();
if (custom_gcode_per_print_z.mode)
// init extruder sequence in respect to the extruders count
if (m_ticks.empty())
m_extruders_sequence.init(m_extruder_colors.size());
if (custom_gcode_per_print_z.mode && !custom_gcode_per_print_z.gcodes.empty())
m_ticks.mode = custom_gcode_per_print_z.mode;
Refresh();
@ -438,7 +443,7 @@ void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, c
m_mode = !is_one_extruder_printed_model ? MultiExtruder :
only_extruder < 0 ? SingleExtruder :
MultiAsSingle;
if (!m_ticks.mode)
if (!m_ticks.mode || (m_ticks.empty() && m_ticks.mode != m_mode))
m_ticks.mode = m_mode;
m_only_extruder = only_extruder;
@ -545,7 +550,8 @@ bool Control::is_wipe_tower_layer(int tick) const
return false;
if (tick == 0 || (tick == (int)m_values.size() - 1 && m_values[tick] > m_values[tick - 1]))
return false;
if (m_values[tick - 1] == m_values[tick + 1] && m_values[tick] < m_values[tick + 1])
if ((m_values[tick - 1] == m_values[tick + 1] && m_values[tick] < m_values[tick + 1]) ||
(tick > 0 && m_values[tick] < m_values[tick - 1]) ) // if there is just one wiping on the layer
return true;
return false;
@ -1077,7 +1083,9 @@ void Control::draw_ruler(wxDC& dc)
{
if (m_values.empty())
return;
m_ruler.update(this->GetParent(), m_values, get_scroll_step());
// When "No sparce layer" is enabled, use m_layers_values for ruler update.
// Because of m_values has duplicate values in this case.
m_ruler.update(this->GetParent(), m_layers_values.empty() ? m_values : m_layers_values, get_scroll_step());
int height, width;
get_size(&width, &height);
@ -1588,7 +1596,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
append_submenu(menu, change_extruder_menu, wxID_ANY, change_extruder_menu_name, _L("Use another extruder"),
active_extruders[1] > 0 ? "edit_uni" : "change_extruder",
[this]() {return m_mode == MultiAsSingle; }, GUI::wxGetApp().plater());
[this]() {return m_mode == MultiAsSingle && !GUI::wxGetApp().obj_list()->has_paint_on_segmentation(); }, GUI::wxGetApp().plater());
}
}

View File

@ -180,6 +180,13 @@ struct ExtrudersSequence
return;// last item can't be deleted
extruders.erase(extruders.begin() + pos);
}
void init(size_t extruders_count)
{
extruders.clear();
for (size_t extruder = 0; extruder < extruders_count; extruder++)
extruders.push_back(extruder);
}
};
class Control : public wxControl

View File

@ -2,6 +2,7 @@
#include "wxExtensions.hpp"
#include "GUI.hpp"
#include "I18N.hpp"
#include "BitmapComboBox.hpp"
#include <wx/dc.h>
#ifdef wxHAS_GENERIC_DATAVIEWCTRL
@ -296,7 +297,11 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR
DataViewBitmapText data;
data << value;
#ifdef _WIN32
Slic3r::GUI::BitmapComboBox* c_editor = new Slic3r::GUI::BitmapComboBox(parent, wxID_ANY, wxEmptyString,
#else
auto c_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString,
#endif
labelRect.GetTopLeft(), wxSize(labelRect.GetWidth(), -1),
0, nullptr , wxCB_READONLY);
@ -310,9 +315,11 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR
// to avoid event propagation to other sidebar items
c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
evt.StopPropagation();
#ifdef __linux__
// FinishEditing grabs new selection and triggers config update. We better call
// it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
this->FinishEditing();
#endif
});
return c_editor;

View File

@ -73,8 +73,6 @@ Field::~Field()
{
if (m_on_kill_focus)
m_on_kill_focus = nullptr;
if (m_on_set_focus)
m_on_set_focus = nullptr;
if (m_on_change)
m_on_change = nullptr;
if (m_back_to_initial_value)
@ -156,15 +154,6 @@ void Field::on_kill_focus()
m_on_kill_focus(m_opt_id);
}
void Field::on_set_focus(wxEvent& event)
{
// to allow the default behavior
event.Skip();
// call the registered function if it is available
if (m_on_set_focus!=nullptr)
m_on_set_focus(m_opt_id);
}
void Field::on_change_field()
{
// std::cerr << "calling Field::_on_change \n";
@ -500,20 +489,18 @@ void TextCtrl::BUILD() {
temp->SetToolTip(get_tooltip_text(text_value));
if (style == wxTE_PROCESS_ENTER) {
if (style & wxTE_PROCESS_ENTER) {
temp->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent& e)
{
#if !defined(__WXGTK__)
e.Skip();
temp->GetToolTip()->Enable(true);
#endif // __WXGTK__
bEnterPressed = true;
EnterPressed enter(this);
propagate_value();
}), temp->GetId());
}
temp->Bind(wxEVT_SET_FOCUS, ([this](wxEvent& e) { on_set_focus(e); }), temp->GetId());
temp->Bind(wxEVT_LEFT_DOWN, ([temp](wxEvent& event)
{
//! to allow the default handling
@ -530,26 +517,11 @@ void TextCtrl::BUILD() {
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
{
e.Skip();
#ifdef __WXOSX__
// OSX issue: For some unknown reason wxEVT_KILL_FOCUS is emitted twice in a row in some cases
// (like when information dialog is shown during an update of the option value)
// Thus, suppress its second call
if (bKilledFocus)
return;
bKilledFocus = true;
#endif // __WXOSX__
#if !defined(__WXGTK__)
temp->GetToolTip()->Enable(true);
#endif // __WXGTK__
if (bEnterPressed)
bEnterPressed = false;
else
if (!bEnterPressed)
propagate_value();
#ifdef __WXOSX__
// After processing of KILL_FOCUS event we should to invalidate a bKilledFocus flag
bKilledFocus = false;
#endif // __WXOSX__
}), temp->GetId());
/*
// select all text using Ctrl+A
@ -851,7 +823,7 @@ void SpinCtrl::BUILD() {
bEnterPressed = true;
}), temp->GetId());
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
temp->Bind(wxEVT_TEXT, ([this, temp](wxCommandEvent e)
{
// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
// # when it was changed from the text control, so the on_change callback
@ -861,20 +833,28 @@ void SpinCtrl::BUILD() {
long value;
const bool parsed = e.GetString().ToLong(&value);
tmp_value = parsed && value >= INT_MIN && value <= INT_MAX ? (int)value : UNDEF_VALUE;
if (!parsed || value < INT_MIN || value > INT_MAX)
tmp_value = UNDEF_VALUE;
else {
tmp_value = std::min(std::max((int)value, m_opt.min), m_opt.max);
#ifdef __WXOSX__
// Forcibly set the input value for SpinControl, since the value
// inserted from the keyboard or clipboard is not updated under OSX
if (tmp_value != UNDEF_VALUE) {
wxSpinCtrl* spin = static_cast<wxSpinCtrl*>(window);
spin->SetValue(tmp_value);
temp->SetValue(tmp_value);
// But in SetValue() is executed m_text_ctrl->SelectAll(), so
// discard this selection and set insertion point to the end of string
spin->GetText()->SetInsertionPointEnd();
temp->GetText()->SetInsertionPointEnd();
#else
// update value for the control only if it was changed in respect to the Min/max values
if (tmp_value != (int)value) {
temp->SetValue(tmp_value);
// But after SetValue() cursor ison the first position
// so put it to the end of string
int pos = std::to_string(tmp_value).length();
temp->SetSelection(pos, pos);
}
#endif
}
}), temp->GetId());
temp->SetToolTip(get_tooltip_text(text_value));
@ -935,7 +915,7 @@ void Choice::BUILD() {
choice_ctrl* temp;
if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_open) {
m_is_editable = true;
temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size);
temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxTE_PROCESS_ENTER);
}
else {
#ifdef __WXOSX__
@ -988,8 +968,23 @@ void Choice::BUILD() {
temp->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_change_field(); }, temp->GetId());
if (m_is_editable) {
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) {
temp->Bind(wxEVT_KILL_FOCUS, [this](wxEvent& e) {
e.Skip();
if (!bEnterPressed)
propagate_value();
} );
temp->Bind(wxEVT_TEXT_ENTER, [this, temp](wxEvent& e) {
EnterPressed enter(this);
propagate_value();
} );
}
temp->SetToolTip(get_tooltip_text(temp->GetValue()));
}
void Choice::propagate_value()
{
if (m_opt.type == coStrings) {
on_change_field();
return;
@ -1022,10 +1017,6 @@ void Choice::BUILD() {
}
else
on_kill_focus();
}), temp->GetId());
}
temp->SetToolTip(get_tooltip_text(temp->GetValue()));
}
void Choice::suppress_scroll()
@ -1137,6 +1128,15 @@ void Choice::set_value(const boost::any& value, bool change_event)
}
else
field->SetSelection(idx);
if (!m_value.empty() && m_opt.opt_key == "fill_density") {
// If m_value was changed before, then update m_value here too to avoid case
// when control's value is already changed from the ConfigManipulation::update_print_fff_config(),
// but m_value doesn't respect it.
if (double val; text_value.ToDouble(&val))
m_value = val;
}
break;
}
case coEnum: {

View File

@ -52,10 +52,17 @@ protected:
//! in another case we can't unfocused control at all
void on_kill_focus();
/// Call the attached on_change method.
void on_set_focus(wxEvent& event);
/// Call the attached on_change method.
void on_change_field();
class EnterPressed {
public:
EnterPressed(Field* field) :
m_parent(field){ m_parent->set_enter_pressed(true); }
~EnterPressed() { m_parent->set_enter_pressed(false); }
private:
Field* m_parent;
};
public:
/// Call the attached m_back_to_initial_value method.
void on_back_to_initial_value();
@ -69,9 +76,6 @@ public:
/// Function object to store callback passed in from owning object.
t_kill_focus m_on_kill_focus {nullptr};
/// Function object to store callback passed in from owning object.
t_kill_focus m_on_set_focus {nullptr};
/// Function object to store callback passed in from owning object.
t_change m_on_change {nullptr};
@ -236,10 +240,6 @@ class TextCtrl : public Field {
void change_field_value(wxEvent& event);
#endif //__WXGTK__
#ifdef __WXOSX__
bool bKilledFocus = false;
#endif // __WXOSX__
public:
TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
@ -342,6 +342,7 @@ public:
class Choice : public Field {
using Field::Field;
public:
Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
@ -349,6 +350,8 @@ public:
wxWindow* window{ nullptr };
void BUILD() override;
// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER
void propagate_value();
/* Under OSX: wxBitmapComboBox->GetWindowStyle() returns some weard value,
* so let use a flag, which has TRUE value for a control without wxCB_READONLY style

View File

@ -65,6 +65,8 @@ enum {
USB_PID_MMU_APP = 4,
USB_PID_CW1_BOOT = 7,
USB_PID_CW1_APP = 8,
USB_PID_CW1S_BOOT = 14,
USB_PID_CW1S_APP = 15,
};
// This enum discriminates the kind of information in EVT_AVRDUDE,
@ -308,7 +310,7 @@ void FirmwareDialog::priv::update_flash_enabled()
void FirmwareDialog::priv::load_hex_file(const wxString &path)
{
hex_file = HexFile(path.wx_str());
const bool autodetect = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1;
const bool autodetect = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1 || hex_file.device == HexFile::DEV_CW1S;
set_autodetect(autodetect);
}
@ -636,6 +638,10 @@ void FirmwareDialog::priv::perform_upload()
this->prepare_avr109(Avr109Pid(USB_PID_CW1_BOOT, USB_PID_CW1_APP));
break;
case HexFile::DEV_CW1S:
this->prepare_avr109(Avr109Pid(USB_PID_CW1S_BOOT, USB_PID_CW1S_APP));
break;
default:
this->prepare_mk2();
break;
@ -767,11 +773,10 @@ const char* FirmwareDialog::priv::avr109_dev_name(Avr109Pid usb_pid) {
switch (usb_pid.boot) {
case USB_PID_MMU_BOOT:
return "Original Prusa MMU 2.0 Control";
break;
case USB_PID_CW1_BOOT:
return "Original Prusa CW1";
break;
case USB_PID_CW1S_BOOT:
return "Original Prusa CW1S";
default: throw Slic3r::RuntimeError((boost::format("Invalid avr109 device USB PID: %1%") % usb_pid.boot).str());
}
}

View File

@ -3455,12 +3455,17 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// stores current min_z of instances
std::map<std::pair<int, int>, double> min_zs;
if (!snapshot_type.empty()) {
for (int i = 0; i < static_cast<int>(m_model->objects.size()); ++i) {
const ModelObject* obj = m_model->objects[i];
for (int j = 0; j < static_cast<int>(obj->instances.size()); ++j) {
if (snapshot_type.empty() && m_selection.get_object_idx() == i) {
// This means we are flattening this object. In that case pretend
// that it is not sinking (even if it is), so it is placed on bed
// later on (whatever is sinking will be left sinking).
min_zs[{ i, j }] = SINKING_Z_THRESHOLD;
} else
min_zs[{ i, j }] = obj->instance_bounding_box(j).min.z();
}
}
}
@ -3502,7 +3507,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
ModelObject* m = m_model->objects[i.first];
const double shift_z = m->get_instance_min_z(i.second);
// leave sinking instances as sinking
if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) {
if (min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) {
const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
@ -5107,6 +5112,7 @@ void GLCanvas3D::_render_objects()
m_volumes.set_z_range(-FLT_MAX, FLT_MAX);
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
m_volumes.set_show_sinking_contours(! m_gizmos.is_hiding_instances());
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
if (shader != nullptr) {

View File

@ -61,6 +61,8 @@ std::pair<bool, std::string> GLShadersManager::init()
);
// used to render variable layers heights in 3d editor
valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" });
// used to render highlight contour around selected triangles inside the multi-material gizmo
valid &= append_shader("mm_contour", { "mm_contour.vs", "mm_contour.fs" });
return { valid, error };
}

View File

@ -8,6 +8,7 @@
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/any.hpp>
#if __APPLE__
@ -21,6 +22,7 @@
#include "AboutDialog.hpp"
#include "MsgDialog.hpp"
#include "format.hpp"
#include "libslic3r/Print.hpp"
@ -244,6 +246,127 @@ void warning_catcher(wxWindow* parent, const wxString& message)
msg.ShowModal();
}
static wxString bold(const wxString& str)
{
return wxString::Format("<b>%s</b>", str);
};
static wxString bold_string(const wxString& str)
{
return wxString::Format("<b>\"%s\"</b>", str);
};
static void add_config_substitutions(const ConfigSubstitutions& conf_substitutions, wxString& changes)
{
changes += "<table>";
for (const ConfigSubstitution& conf_substitution : conf_substitutions) {
wxString new_val;
const ConfigOptionDef* def = conf_substitution.opt_def;
if (!def)
continue;
switch (def->type) {
case coEnum:
{
const std::vector<std::string>& labels = def->enum_labels;
const std::vector<std::string>& values = def->enum_values;
int val = conf_substitution.new_value->getInt();
bool is_infill = def->opt_key == "top_fill_pattern" ||
def->opt_key == "bottom_fill_pattern" ||
def->opt_key == "fill_pattern";
// Each infill doesn't use all list of infill declared in PrintConfig.hpp.
// So we should "convert" val to the correct one
if (is_infill) {
for (const auto& key_val : *def->enum_keys_map)
if ((int)key_val.second == val) {
auto it = std::find(values.begin(), values.end(), key_val.first);
if (it == values.end())
break;
auto idx = it - values.begin();
new_val = wxString("\"") + values[idx] + "\"" + " (" + from_u8(_utf8(labels[idx])) + ")";
break;
}
if (new_val.IsEmpty()) {
assert(false);
new_val = _L("Undefined");
}
}
else
new_val = wxString("\"") + values[val] + "\"" + " (" + from_u8(_utf8(labels[val])) + ")";
break;
}
case coBool:
new_val = conf_substitution.new_value->getBool() ? "true" : "false";
break;
case coBools:
if (conf_substitution.new_value->nullable())
for (const char v : static_cast<const ConfigOptionBoolsNullable*>(conf_substitution.new_value.get())->values)
new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", ";
else
for (const char v : static_cast<const ConfigOptionBools*>(conf_substitution.new_value.get())->values)
new_val += std::string(v ? "true" : "false") + ", ";
if (! new_val.empty())
new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end());
break;
default:
assert(false);
}
changes += format_wxstr("<tr><td><b>\"%1%\" (%2%)</b></td><td>: ", def->opt_key, _(def->label)) +
format_wxstr(_L("%1% was substituted with %2%"), bold_string(conf_substitution.old_value), bold(new_val)) +
"</td></tr>";
}
changes += "</table>";
}
static wxString substitution_message(const wxString& changes)
{
return
_L("Most likely the configuration was produced by a newer version of PrusaSlicer or by some PrusaSlicer fork.") + " " +
_L("The following values were substituted:") + "\n" + changes + "\n\n" +
_L("Review the substitutions and adjust them if needed.");
}
void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions)
{
wxString changes;
auto preset_type_name = [](Preset::Type type) {
switch (type) {
case Preset::TYPE_PRINT: return _L("Print settings");
case Preset::TYPE_SLA_PRINT: return _L("SLA print settings");
case Preset::TYPE_FILAMENT: return _L("Filament");
case Preset::TYPE_SLA_MATERIAL: return _L("SLA material");
case Preset::TYPE_PRINTER: return _L("Printer");
case Preset::TYPE_PHYSICAL_PRINTER: return _L("Physical Printer");
default: assert(false); return wxString();
}
};
for (const PresetConfigSubstitutions& substitution : presets_config_substitutions) {
changes += "\n\n" + format_wxstr("%1% : %2%", preset_type_name(substitution.preset_type), bold_string(substitution.preset_name));
if (!substitution.preset_file.empty())
changes += format_wxstr(" (%1%)", substitution.preset_file);
add_config_substitutions(substitution.substitutions, changes);
}
InfoDialog msg(nullptr, _L("Configuration bundle was loaded, however some configuration values were not recognized."), substitution_message(changes));
msg.ShowModal();
}
void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename)
{
wxString changes = "\n";
add_config_substitutions(config_substitutions, changes);
InfoDialog msg(nullptr,
format_wxstr(_L("Configuration file \"%1%\" was loaded, however some configuration values were not recognized."), from_u8(filename)),
substitution_message(changes));
msg.ShowModal();
}
void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items)
{
if (comboCtrl == nullptr)

View File

@ -7,6 +7,7 @@ namespace boost::filesystem { class path; }
#include <wx/string.h>
#include "libslic3r/Config.hpp"
#include "libslic3r/Preset.hpp"
class wxWindow;
class wxMenuBar;
@ -48,6 +49,8 @@ void show_info(wxWindow* parent, const wxString& message, const wxString& title
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); }
void warning_catcher(wxWindow* parent, const wxString& message);
void show_substitutions_info(const PresetsConfigSubstitutions& presets_config_substitutions);
void show_substitutions_info(const ConfigSubstitutions& config_substitutions, const std::string& filename);
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.
// Items data must be separated by '|', and contain the item name to be shown followed by its initial value (0 for false, 1 for true).

View File

@ -435,7 +435,9 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
/* FT_TEX */ "Texture (*.png, *.svg)|*.png;*.PNG;*.svg;*.SVG",
/* FT_PNGZIP */ "Masked SLA files (*.sl1)|*.sl1;*.SL1",
/* FT_SL1 */ "Masked SLA files (*.sl1, *.sl1s)|*.sl1;*.SL1;*.sl1s;*.SL1S",
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
/* FT_SL1S */ "Masked SLA files (*.sl1s, *.sl1)|*.sl1s;*.SL1S;*.sl1;*.SL1",
};
std::string out = defaults[file_type];
@ -626,12 +628,8 @@ void GUI_App::post_init()
this->plater()->load_gcode(wxString::FromUTF8(this->init_params->input_files[0].c_str()));
}
else {
if (! this->init_params->preset_substitutions.empty()) {
// TODO: Add list of changes from all_substitutions
show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities."
" To recover these files, incompatible values were changed to default values."
" But data in files won't be changed until you save them in PrusaSlicer.")));
}
if (! this->init_params->preset_substitutions.empty())
show_substitutions_info(this->init_params->preset_substitutions);
#if 0
// Load the cummulative config over the currently active profiles.
@ -664,7 +662,7 @@ void GUI_App::post_init()
// show "Did you know" notification
if (app_config->get("show_hints") == "1" && ! is_gcode_viewer())
plater_->get_notification_manager()->push_hint_notification();
plater_->get_notification_manager()->push_hint_notification(true);
// The extra CallAfter() is needed because of Mac, where this is the only way
// to popup a modal dialog on start without screwing combo boxes.
@ -916,7 +914,10 @@ bool GUI_App::on_init_inner()
// Suppress the '- default -' presets.
preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1");
try {
init_params->preset_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::Enable);
// Enable all substitutions (in both user and system profiles), but log the substitutions in user profiles only.
// If there are substitutions in system profiles, then a "reconfigure" event shall be triggered, which will force
// installation of a compatible system preset, thus nullifying the system preset substitutions.
init_params->preset_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
} catch (const std::exception &ex) {
show_error(nullptr, ex.what());
}
@ -1861,9 +1862,10 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
child->SetFont(normal_font());
if (dlg.ShowModal() == wxID_OK)
app_config->set("on_snapshot",
Slic3r::GUI::Config::SnapshotDB::singleton().take_snapshot(
*app_config, Slic3r::GUI::Config::Snapshot::SNAPSHOT_USER, dlg.GetValue().ToUTF8().data()).id);
if (const Config::Snapshot *snapshot = Config::take_config_snapshot_report_error(
*app_config, Config::Snapshot::SNAPSHOT_USER, dlg.GetValue().ToUTF8().data());
snapshot != nullptr)
app_config->set("on_snapshot", snapshot->id);
}
break;
case ConfigMenuSnapshots:
@ -1874,19 +1876,24 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
ConfigSnapshotDialog dlg(Slic3r::GUI::Config::SnapshotDB::singleton(), on_snapshot);
dlg.ShowModal();
if (!dlg.snapshot_to_activate().empty()) {
if (! Config::SnapshotDB::singleton().is_on_snapshot(*app_config))
Config::SnapshotDB::singleton().take_snapshot(*app_config, Config::Snapshot::SNAPSHOT_BEFORE_ROLLBACK);
if (! Config::SnapshotDB::singleton().is_on_snapshot(*app_config) &&
! Config::take_config_snapshot_cancel_on_error(*app_config, Config::Snapshot::SNAPSHOT_BEFORE_ROLLBACK, "",
GUI::format(_L("Continue to activate a configuration snapshot %1%?"), dlg.snapshot_to_activate())))
break;
try {
app_config->set("on_snapshot", Config::SnapshotDB::singleton().restore_snapshot(dlg.snapshot_to_activate(), *app_config).id);
// Enable substitutions, log both user and system substitutions. There should not be any substitutions performed when loading system
// presets because compatibility of profiles shall be verified using the min_slic3r_version keys in config index, but users
// are known to be creative and mess with the config files in various ways.
if (PresetsConfigSubstitutions all_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::Enable);
! all_substitutions.empty()) {
// TODO:
show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities."
" To recover these files, incompatible values were changed to default values."
" But data in files won't be changed until you save them in PrusaSlicer.")));
}
! all_substitutions.empty())
show_substitutions_info(all_substitutions);
// Load the currently selected preset into the GUI, update the preset selection box.
load_current_presets();
// update config wizard in respect to the new config
update_wizard_from_config();
} catch (std::exception &ex) {
GUI::show_error(nullptr, _L("Failed to activate configuration snapshot.") + "\n" + into_u8(ex.what()));
}
@ -2059,7 +2066,7 @@ std::vector<std::pair<unsigned int, std::string>> GUI_App::get_selected_presets(
// to notify the user whether he is aware that some preset changes will be lost.
bool GUI_App::check_and_save_current_preset_changes(const wxString& header)
{
if (this->plater()->model().objects.empty() && has_current_preset_changes()) {
if (/*this->plater()->model().objects.empty() && */has_current_preset_changes()) {
UnsavedChangesDialog dlg(header);
if (wxGetApp().app_config->get("default_action_on_close_application") == "none" && dlg.ShowModal() == wxID_CANCEL)
return false;
@ -2138,6 +2145,17 @@ void GUI_App::load_current_presets(bool check_printer_presets_ /*= true*/)
}
}
void GUI_App::update_wizard_from_config()
{
if (!m_wizard)
return;
// If ConfigWizard was created before changing of the configuration,
// we have to destroy it to have possibility to create it again in respect to the new config's parameters
m_wizard->Reparent(nullptr);
m_wizard->Destroy();
m_wizard = nullptr;
}
bool GUI_App::OnExceptionInMainLoop()
{
generic_exception_handle();
@ -2298,7 +2316,13 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
{
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
if (reason == ConfigWizard::RR_USER)
if (PresetUpdater::UpdateResult result = preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD);
result == PresetUpdater::R_ALL_CANCELED)
return false;
if (! m_wizard) {
wxBusyCursor wait;
m_wizard = new ConfigWizard(mainframe);
}
@ -2466,7 +2490,7 @@ void GUI_App::check_updates(const bool verbose)
{
PresetUpdater::UpdateResult updater_result;
try {
updater_result = preset_updater->config_update(app_config->orig_version(), verbose);
updater_result = preset_updater->config_update(app_config->orig_version(), verbose ? PresetUpdater::UpdateParams::SHOW_TEXT_BOX : PresetUpdater::UpdateParams::SHOW_NOTIFICATION);
if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) {
mainframe->Close();
}

View File

@ -66,7 +66,9 @@ enum FileType
FT_TEX,
FT_PNGZIP,
FT_SL1,
// Workaround for OSX file picker, for some reason it always saves with the 1st extension.
FT_SL1S,
FT_SIZE,
};
@ -247,6 +249,7 @@ public:
bool check_print_host_queue();
bool checked_tab(Tab* tab);
void load_current_presets(bool check_printer_presets = true);
void update_wizard_from_config();
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".

View File

@ -145,7 +145,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus
auto temp = new wxStaticText(m_parent, wxID_ANY, _L("mm"));
temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
temp->SetFont(wxGetApp().normal_font());
sizer->Add(temp, 0, wxLEFT, wxGetApp().em_unit());
sizer->Add(temp, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, wxGetApp().em_unit());
m_grid_sizer->Add(sizer);

View File

@ -2517,7 +2517,7 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D
}
void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selections/* = nullptr*/)
void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selections/* = nullptr*/, bool added_object/* = false*/)
{
const ModelObject* model_object = (*m_objects)[obj_idx];
wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx);
@ -2561,8 +2561,8 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio
if (! shows && should_show) {
m_objects_model->AddInfoChild(item_obj, type);
Expand(item_obj);
if (added_object)
wxGetApp().notification_manager()->push_updated_item_info_notification(type);
}
else if (shows && ! should_show) {
if (!selections)
@ -2594,7 +2594,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
model_object->config.has("extruder") ? model_object->config.extruder() : 0,
get_mesh_errors_count(obj_idx) > 0);
update_info_items(obj_idx);
update_info_items(obj_idx, nullptr, true);
// add volumes to the object
if (model_object->volumes.size() > 1) {
@ -3857,6 +3857,7 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
// update printable state for new volumes on canvas3D
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object(new_obj_indx);
update_info_items(new_obj_indx);
}
void ObjectList::instances_to_separated_objects(const int obj_idx)
@ -3889,6 +3890,8 @@ void ObjectList::instances_to_separated_objects(const int obj_idx)
// update printable state for new volumes on canvas3D
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(object_idxs);
for (size_t object : object_idxs)
update_info_items(object);
}
void ObjectList::split_instances()
@ -3953,6 +3956,7 @@ void ObjectList::fix_through_netfabb()
wxGetApp().plater()->fix_through_netfabb(obj_idx, vol_idx);
update_item_error_icon(obj_idx, vol_idx);
update_info_items(obj_idx);
}
void ObjectList::simplify()
@ -4248,5 +4252,10 @@ ModelObject* ObjectList::object(const int obj_idx) const
return (*m_objects)[obj_idx];
}
bool ObjectList::has_paint_on_segmentation()
{
return m_objects_model->HasInfoItem(InfoItemType::MmuSegmentation);
}
} //namespace GUI
} //namespace Slic3r

View File

@ -350,7 +350,7 @@ public:
void update_and_show_object_settings_item();
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
void update_object_list_by_printer_technology();
void update_info_items(size_t obj_idx, wxDataViewItemArray* selections = nullptr);
void update_info_items(size_t obj_idx, wxDataViewItemArray* selections = nullptr, bool added_object = false);
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
void instances_to_separated_objects(const int obj_idx);
@ -379,6 +379,7 @@ public:
void set_extruder_for_selected_items(const int extruder) const ;
wxDataViewItemArray reorder_volumes_and_get_selection(int obj_idx, std::function<bool(const ModelVolume*)> add_to_selection = nullptr);
void apply_volumes_order();
bool has_paint_on_segmentation();
private:
#ifdef __WXOSX__

View File

@ -709,9 +709,9 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
const ExPolygons& bottom = object->get_layer(0)->lslices;
double bottom_area = area(bottom);
// at least 30% of object's height have to be a solid
int i;
for (i = 1; i < int(0.3 * num_layers); ++ i) {
// at least 25% of object's height have to be a solid
int i, min_solid_height = int(0.25 * num_layers);
for (i = 1; i <= min_solid_height; ++ i) {
double cur_area = area(object->get_layer(i)->lslices);
if (cur_area != bottom_area && fabs(cur_area - bottom_area) > scale_(scale_(1))) {
// but due to the elephant foot compensation, the first layer may be slightly smaller than the others
@ -723,7 +723,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
break;
}
}
if (i < int(0.3 * num_layers))
if (i < min_solid_height)
continue;
// bottom layer have to be a biggest, so control relation between bottom layer and object size
@ -788,10 +788,10 @@ void Preview::update_layers_slider_mode()
object->config.option("extruder")->getInt() != extruder)
return false;
if (object->volumes.size() > 1)
for (ModelVolume* volume : object->volumes)
if (volume->config.has("extruder") &&
volume->config.option("extruder")->getInt() != extruder)
volume->config.option("extruder")->getInt() != extruder ||
!volume->mmu_segmentation_facets.empty())
return false;
for (const auto& range : object->layer_config_ranges)

View File

@ -67,8 +67,8 @@ void GLGizmoFdmSupports::render_painter_gizmo() const
glsafe(::glEnable(GL_DEPTH_TEST));
render_triangles(selection);
m_c->object_clipper()->render_cut();
m_c->instances_hider()->render_cut();
render_cursor();
glsafe(::glDisable(GL_BLEND));

View File

@ -42,6 +42,8 @@ std::string GLGizmoFlatten::on_get_name() const
bool GLGizmoFlatten::on_is_activable() const
{
// This is assumed in GLCanvas3D::do_rotate, do not change this
// without updating that function too.
return m_parent.get_selection().is_single_full_instance();
}

View File

@ -42,7 +42,7 @@ void GLGizmoMmuSegmentation::on_shutdown()
std::string GLGizmoMmuSegmentation::on_get_name() const
{
// FIXME Lukas H.: Discuss and change shortcut
return (_L("MMU painting") + " [N]").ToUTF8().data();
return (_L("Multimaterial painting") + " [N]").ToUTF8().data();
}
bool GLGizmoMmuSegmentation::on_is_selectable() const
@ -147,6 +147,7 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() const
render_triangles(selection, false);
m_c->object_clipper()->render_cut();
m_c->instances_hider()->render_cut();
render_cursor();
glsafe(::glDisable(GL_BLEND));
@ -327,8 +328,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::AlignTextToFramePadding();
ImGui::SameLine(tool_type_offset + m_imgui->scaled(0.f));
ImGui::PushItemWidth(tool_type_radio_brush);
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BRUSH))
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BRUSH)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::BRUSH;
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
@ -339,24 +345,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
}
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + m_imgui->scaled(0.f));
ImGui::PushItemWidth(tool_type_radio_bucket_fill);
if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL;
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Paints neighboring facets that have the same color.").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_bucket_fill + m_imgui->scaled(0.f));
ImGui::PushItemWidth(tool_type_radio_seed_fill);
if (m_imgui->radio_button(m_desc["tool_seed_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::SEED_FILL)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::SEED_FILL;
@ -374,6 +362,24 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::EndTooltip();
}
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_seed_fill + m_imgui->scaled(0.f));
ImGui::PushItemWidth(tool_type_radio_bucket_fill);
if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) {
m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL;
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted(_L("Paints neighboring facets that have the same color.").ToUTF8().data());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::Separator();
if(m_tool_type == ToolType::BRUSH) {
@ -459,7 +465,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
"placed after the number with no whitespace in between.");
ImGui::SameLine(sliders_width);
ImGui::PushItemWidth(window_width - sliders_width);
m_imgui->slider_float("##seed_fill_angle", &m_seed_fill_angle, SeedFillAngleMin, SeedFillAngleMax, format_str.data());
if(m_imgui->slider_float("##seed_fill_angle", &m_seed_fill_angle, SeedFillAngleMin, SeedFillAngleMax, format_str.data()))
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(max_tooltip_width);
@ -586,10 +597,13 @@ std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_colo
return {color[0], color[1], color[2], 0.25f};
}
static std::array<float, 4> get_seed_fill_color(const std::array<float, 4> &base_color)
{
return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f};
}
void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
{
static constexpr std::array<float, 4> seed_fill_color{0.f, 1.f, 0.44f, 1.f};
if (m_update_render_data)
update_render_data();
@ -602,12 +616,24 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx)
if (m_gizmo_scene.has_VBOs(color_idx)) {
shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color :
color_idx == (m_gizmo_scene.triangle_indices.size() - 1) ? seed_fill_color :
m_colors[color_idx - 1]);
if (color_idx > m_colors.size()) // Seed fill VBO
shader->set_uniform("uniform_color", get_seed_fill_color(color_idx == (m_colors.size() + 1) ? m_default_volume_color : m_colors[color_idx - (m_colors.size() + 1) - 1]));
else // Normal VBO
shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color : m_colors[color_idx - 1]);
m_gizmo_scene.render(color_idx);
}
if (m_gizmo_scene.has_contour_VBO()) {
ScopeGuard guard_gouraud([shader]() { shader->start_using(); });
shader->stop_using();
auto *contour_shader = wxGetApp().get_shader("mm_contour");
contour_shader->start_using();
m_gizmo_scene.render_contour();
contour_shader->stop_using();
}
m_update_render_data = false;
}
@ -624,10 +650,10 @@ void TriangleSelectorMmGui::update_render_data()
for (const Triangle &tr : m_triangles)
if (tr.valid() && !tr.is_split()) {
int color = int(tr.get_state());
std::vector<int> &iva = tr.is_selected_by_seed_fill() ? m_gizmo_scene.triangle_indices.back() :
color < int(m_gizmo_scene.triangle_indices.size() - 1) ? m_gizmo_scene.triangle_indices[color] :
m_gizmo_scene.triangle_indices.front();
int color = int(tr.get_state()) <= int(m_colors.size()) ? int(tr.get_state()) : 0;
assert(m_colors.size() + 1 + color < m_gizmo_scene.triangle_indices.size());
std::vector<int> &iva = m_gizmo_scene.triangle_indices[color + tr.is_selected_by_seed_fill() * (m_colors.size() + 1)];
if (iva.size() + 3 > iva.capacity())
iva.reserve(next_highest_power_of_2(iva.size() + 3));
@ -640,6 +666,24 @@ void TriangleSelectorMmGui::update_render_data()
m_gizmo_scene.triangle_indices_sizes[color_idx] = m_gizmo_scene.triangle_indices[color_idx].size();
m_gizmo_scene.finalize_triangle_indices();
std::vector<Vec2i> contour_edges = this->get_seed_fill_contour();
m_gizmo_scene.contour_vertices.reserve(contour_edges.size() * 6);
for (const Vec2i &edge : contour_edges) {
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.x());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.y());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.z());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.x());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.y());
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.z());
}
m_gizmo_scene.contour_indices.assign(m_gizmo_scene.contour_vertices.size() / 3, 0);
std::iota(m_gizmo_scene.contour_indices.begin(), m_gizmo_scene.contour_indices.end(), 0);
m_gizmo_scene.contour_indices_size = m_gizmo_scene.contour_indices.size();
m_gizmo_scene.finalize_contour();
}
wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
@ -663,6 +707,14 @@ void GLMmSegmentationGizmo3DScene::release_geometry() {
glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id));
triangle_indices_VBO_id = 0;
}
if (this->contour_vertices_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->contour_vertices_VBO_id));
this->contour_vertices_VBO_id = 0;
}
if (this->contour_indices_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->contour_indices_VBO_id));
this->contour_indices_VBO_id = 0;
}
this->clear();
}
@ -673,6 +725,10 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
assert(this->vertices_VBO_id != 0);
assert(this->triangle_indices_VBO_ids[triangle_indices_idx] != 0);
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); });
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
glsafe(::glPolygonOffset(5.0, 5.0));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float))));
@ -690,13 +746,36 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLMmSegmentationGizmo3DScene::render_contour() const
{
assert(this->contour_vertices_VBO_id != 0);
assert(this->contour_indices_VBO_id != 0);
glsafe(::glLineWidth(4.0f));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
if (this->contour_indices_size > 0) {
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices_VBO_id));
glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLMmSegmentationGizmo3DScene::finalize_vertices()
{
assert(this->vertices_VBO_id == 0);
if (!this->vertices.empty()) {
glsafe(::glGenBuffers(1, &this->vertices_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * 4, this->vertices.data(), GL_STATIC_DRAW));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), this->vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->vertices.clear();
}
@ -711,19 +790,32 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices()
if (!this->triangle_indices[buffer_idx].empty()) {
glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_ids[buffer_idx]));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[buffer_idx]));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices[buffer_idx].size() * 4, this->triangle_indices[buffer_idx].data(),
GL_STATIC_DRAW));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices[buffer_idx].size() * sizeof(int), this->triangle_indices[buffer_idx].data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
this->triangle_indices[buffer_idx].clear();
}
}
void GLMmSegmentationGizmo3DScene::finalize_geometry()
void GLMmSegmentationGizmo3DScene::finalize_contour()
{
assert(this->vertices_VBO_id == 0);
assert(this->triangle_indices.size() == this->triangle_indices_VBO_ids.size());
finalize_vertices();
finalize_triangle_indices();
assert(this->contour_vertices_VBO_id == 0);
assert(this->contour_indices_VBO_id == 0);
if (!this->contour_vertices.empty()) {
glsafe(::glGenBuffers(1, &this->contour_vertices_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_vertices.clear();
}
if (!this->contour_indices.empty()) {
glsafe(::glGenBuffers(1, &this->contour_indices_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_indices_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->contour_indices.clear();
}
}
} // namespace Slic3r

View File

@ -25,9 +25,8 @@ public:
return this->triangle_indices_VBO_ids[triangle_indices_idx] != 0;
}
// Finalize the initialization of the geometry and indices, upload the geometry and indices to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_geometry();
[[nodiscard]] inline bool has_contour_VBO() const { return this->contour_indices_VBO_id != 0; }
// Release the geometry data, release OpenGL VBOs.
void release_geometry();
// Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects
@ -36,6 +35,9 @@ public:
// Finalize the initialization of the indices, upload the indices to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_triangle_indices();
// Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_contour();
void clear()
{
@ -45,28 +47,41 @@ public:
for (size_t &triangle_indices_size : this->triangle_indices_sizes)
triangle_indices_size = 0;
this->contour_vertices.clear();
this->contour_indices.clear();
this->contour_indices_size = 0;
}
void render(size_t triangle_indices_idx) const;
void render_contour() const;
std::vector<float> vertices;
std::vector<std::vector<int>> triangle_indices;
std::vector<float> contour_vertices;
std::vector<int> contour_indices;
// When the triangle indices are loaded into the graphics card as Vertex Buffer Objects,
// the above mentioned std::vectors are cleared and the following variables keep their original length.
std::vector<size_t> triangle_indices_sizes;
size_t contour_indices_size{0};
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
// Zero if the VBOs are not sent to GPU yet.
unsigned int vertices_VBO_id{0};
std::vector<unsigned int> triangle_indices_VBO_ids;
unsigned int contour_vertices_VBO_id{0};
unsigned int contour_indices_VBO_id{0};
};
class TriangleSelectorMmGui : public TriangleSelectorGUI {
public:
// Plus 2 in the initialization of m_gizmo_scene is because the first position is allocated for non-painted triangles, and the last position is allocated for seed fill.
// Plus 1 in the initialization of m_gizmo_scene is because the first position is allocated for non-painted triangles, and the indices above colors.size() are allocated for seed fill.
explicit TriangleSelectorMmGui(const TriangleMesh &mesh, const std::vector<std::array<float, 4>> &colors, const std::array<float, 4> &default_volume_color)
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(colors.size() + 2) {}
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(2 * (colors.size() + 1)) {}
~TriangleSelectorMmGui() override = default;
// Render current selection. Transformation matrices are supposed

View File

@ -283,7 +283,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
return true;
}
else if (alt_down) {
if (m_tool_type == ToolType::BRUSH) {
if (m_tool_type == ToolType::BRUSH && (m_cursor_type == TriangleSelector::CursorType::SPHERE || m_cursor_type == TriangleSelector::CursorType::CIRCLE)) {
m_cursor_radius = action == SLAGizmoEventType::MouseWheelDown ? std::max(m_cursor_radius - CursorRadiusStep, CursorRadiusMin)
: std::min(m_cursor_radius + CursorRadiusStep, CursorRadiusMax);
m_parent.set_as_dirty();
@ -292,6 +292,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_seed_fill_angle = action == SLAGizmoEventType::MouseWheelDown ? std::max(m_seed_fill_angle - SeedFillAngleStep, SeedFillAngleMin)
: std::min(m_seed_fill_angle + SeedFillAngleStep, SeedFillAngleMax);
m_parent.set_as_dirty();
if (m_rr.mesh_id != -1) {
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle, true);
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
m_seed_fill_last_mesh_id = m_rr.mesh_id;
}
return true;
}
@ -382,6 +387,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
if (m_tool_type == ToolType::SEED_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) {
m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state);
if (m_tool_type == ToolType::SEED_FILL)
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle, true);
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), false, true);
else if (m_tool_type == ToolType::BUCKET_FILL)
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), true, true);
m_seed_fill_last_mesh_id = -1;
} else if (m_tool_type == ToolType::BRUSH)
m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type,

View File

@ -114,7 +114,7 @@ protected:
bool m_triangle_splitting_enabled = true;
ToolType m_tool_type = ToolType::BRUSH;
float m_seed_fill_angle = 0.f;
float m_seed_fill_angle = 30.f;
static constexpr float SeedFillAngleMin = 0.0f;
static constexpr float SeedFillAngleMax = 90.f;

View File

@ -63,6 +63,7 @@ void GLGizmoSeam::render_painter_gizmo() const
render_triangles(selection);
m_c->object_clipper()->render_cut();
m_c->instances_hider()->render_cut();
render_cursor();
glsafe(::glDisable(GL_BLEND));

View File

@ -906,10 +906,11 @@ void GLGizmoSlaSupports::on_set_state()
// on OSX with the wxMessageDialog being shown several times when clicked into.
//wxMessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
MessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
"edited support points?") + "\n",_L("Save changes?"), wxICON_QUESTION | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES)
"edited support points?") + "\n",_L("Save support points?"), wxICON_QUESTION | wxYES | wxNO | wxCANCEL );
int ret = dlg.ShowModal();
if (ret == wxID_YES)
editing_mode_apply_changes();
else
else if (ret == wxID_NO)
editing_mode_discard_changes();
});
// refuse to be turned off so the gizmo is active when the CallAfter is executed

View File

@ -150,6 +150,30 @@ void InstancesHider::on_update()
canvas->toggle_model_objects_visibility(false);
canvas->toggle_model_objects_visibility(true, mo, active_inst);
canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst);
canvas->set_use_clipping_planes(true);
// Some objects may be sinking, do not show whatever is below the bed.
canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), 0.));
canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), std::numeric_limits<double>::max()));
std::vector<const TriangleMesh*> meshes;
for (const ModelVolume* mv : mo->volumes)
meshes.push_back(&mv->mesh());
if (meshes != m_old_meshes) {
m_clippers.clear();
for (const TriangleMesh* mesh : meshes) {
m_clippers.emplace_back(new MeshClipper);
if (mo->get_instance_min_z(active_inst) < SINKING_Z_THRESHOLD)
m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), 0.));
else {
m_clippers.back()->set_plane(ClippingPlane::ClipsNothing());
m_clippers.back()->set_limiting_plane(ClippingPlane::ClipsNothing());
}
m_clippers.back()->set_mesh(*mesh);
}
m_old_meshes = meshes;
}
}
else
canvas->toggle_model_objects_visibility(true);
@ -158,6 +182,9 @@ void InstancesHider::on_update()
void InstancesHider::on_release()
{
get_pool()->get_canvas()->toggle_model_objects_visibility(true);
get_pool()->get_canvas()->set_use_clipping_planes(false);
m_old_meshes.clear();
m_clippers.clear();
}
void InstancesHider::show_supports(bool show) {
@ -167,6 +194,38 @@ void InstancesHider::show_supports(bool show) {
}
}
void InstancesHider::render_cut() const
{
const SelectionInfo* sel_info = get_pool()->selection_info();
const ModelObject* mo = sel_info->model_object();
Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
size_t clipper_id = 0;
for (const ModelVolume* mv : mo->volumes) {
Geometry::Transformation vol_trafo = mv->get_transformation();
Geometry::Transformation trafo = inst_trafo * vol_trafo;
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
auto& clipper = m_clippers[clipper_id];
clipper->set_transformation(trafo);
const ObjectClipper* obj_clipper = get_pool()->object_clipper();
if (obj_clipper->is_valid() && obj_clipper->get_clipping_plane()
&& obj_clipper->get_position() != 0.) {
ClippingPlane clp = *get_pool()->object_clipper()->get_clipping_plane();
clp.set_normal(-clp.get_normal());
clipper->set_limiting_plane(clp);
} else
clipper->set_limiting_plane(ClippingPlane::ClipsNothing());
glsafe(::glPushMatrix());
glsafe(::glColor3f(0.8f, 0.3f, 0.0f));
clipper->render_cut();
glsafe(::glPopMatrix());
++clipper_id;
}
}
void HollowedMesh::on_update()
@ -348,6 +407,7 @@ void ObjectClipper::render_cut() const
const SelectionInfo* sel_info = get_pool()->selection_info();
const ModelObject* mo = sel_info->model_object();
Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
const bool sinking = mo->bounding_box().min.z() < SINKING_Z_THRESHOLD;
size_t clipper_id = 0;
for (const ModelVolume* mv : mo->volumes) {
@ -358,7 +418,9 @@ void ObjectClipper::render_cut() const
auto& clipper = m_clippers[clipper_id];
clipper->set_plane(*m_clp);
clipper->set_transformation(trafo);
clipper->set_limiting_plane(sinking ?
ClippingPlane(Vec3d::UnitZ(), 0.)
: ClippingPlane::ClipsNothing());
glsafe(::glPushMatrix());
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
clipper->render_cut();

View File

@ -180,6 +180,7 @@ public:
void show_supports(bool show);
bool are_supports_shown() const { return m_show_supports; }
void render_cut() const;
protected:
void on_update() override;
@ -187,6 +188,8 @@ protected:
private:
bool m_show_supports = false;
std::vector<const TriangleMesh*> m_old_meshes;
std::vector<std::unique_ptr<MeshClipper>> m_clippers;
};

View File

@ -103,7 +103,7 @@ bool GLGizmosManager::init()
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6));
m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "fdm_supports.svg", 7));
m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8));
m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "fdm_supports.svg", 9));
m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9));
m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10));
m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent));
@ -1248,6 +1248,14 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const
}
bool GLGizmosManager::is_hiding_instances() const
{
return (m_common_gizmos_data
&& m_common_gizmos_data->instances_hider()
&& m_common_gizmos_data->instances_hider()->is_valid());
}
int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const
{
return m_gizmos[type]->get_shortcut_key();

View File

@ -122,7 +122,6 @@ private:
MouseCapture m_mouse_capture;
std::string m_tooltip;
bool m_serializing;
//std::unique_ptr<CommonGizmosData> m_common_gizmos_data;
std::unique_ptr<CommonGizmosDataPool> m_common_gizmos_data;
public:
@ -218,6 +217,7 @@ public:
bool wants_reslice_supports_on_undo() const;
bool is_in_editing_mode(bool error_notification = false) const;
bool is_hiding_instances() const;
void render_current_gizmo() const;
void render_current_gizmo_for_picking_pass() const;

View File

@ -30,33 +30,153 @@ inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, f
else
ImGui::PushStyleColor(idx, col);
}
// return true if NOT in disabled mode.
inline bool disabled_modes_check(const std::string& disabled_modes)
enum TagCheckResult
{
TagCheckAffirmative,
TagCheckNegative,
TagCheckNotCompatible
};
// returns if in mode defined by tag
TagCheckResult tag_check_mode(const std::string& tag)
{
std::vector<std::string> allowed_tags = {"simple", "advanced", "expert"};
if (std::find(allowed_tags.begin(), allowed_tags.end(), tag) != allowed_tags.end())
{
if (disabled_modes.empty())
return true;
// simple / advanced / expert
ConfigOptionMode config_mode = wxGetApp().get_mode();
std::string mode_name;
if (config_mode == ConfigOptionMode::comSimple) mode_name = "simple";
else if (config_mode == ConfigOptionMode::comAdvanced) mode_name = "advanced";
else if (config_mode == ConfigOptionMode::comExpert) mode_name = "expert";
if (!mode_name.empty() && disabled_modes.find(mode_name) != std::string::npos)
return false;
// fff / sla
const PrinterTechnology tech = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
if (tech == ptFFF) {
if (disabled_modes.find("FFF") != std::string::npos)
return false;
} else {
if (disabled_modes.find("SLA") != std::string::npos)
return false;
if (config_mode == ConfigOptionMode::comSimple) return (tag == "simple" ? TagCheckAffirmative : TagCheckNegative);
else if (config_mode == ConfigOptionMode::comAdvanced) return (tag == "advanced" ? TagCheckAffirmative : TagCheckNegative);
else if (config_mode == ConfigOptionMode::comExpert) return (tag == "expert" ? TagCheckAffirmative : TagCheckNegative);
}
return TagCheckNotCompatible;
}
TagCheckResult tag_check_tech(const std::string& tag)
{
std::vector<std::string> allowed_tags = { "FFF", "MMU", "SLA" };
if (std::find(allowed_tags.begin(), allowed_tags.end(), tag) != allowed_tags.end()) {
const PrinterTechnology tech = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
if (tech == ptFFF) {
// MMU / FFF
bool is_mmu = wxGetApp().extruders_edited_cnt() > 1;
if (tag == "MMU") return (is_mmu ? TagCheckAffirmative : TagCheckNegative);
return (tag == "FFF" ? TagCheckAffirmative : TagCheckNegative);
} else {
// SLA
return (tag == "SLA" ? TagCheckAffirmative : TagCheckNegative);
}
}
return TagCheckNotCompatible;
}
TagCheckResult tag_check_system(const std::string& tag)
{
std::vector<std::string> allowed_tags = { "Windows", "Linux", "OSX" };
if (std::find(allowed_tags.begin(), allowed_tags.end(), tag) != allowed_tags.end()) {
if (tag =="Windows")
#ifdef WIN32
return TagCheckAffirmative;
#else
return TagCheckNegative;
#endif // WIN32
if (tag == "Linux")
#ifdef __linux__
return TagCheckAffirmative;
#else
return TagCheckNegative;
#endif // __linux__
if (tag == "OSX")
#ifdef __APPLE__
return TagCheckAffirmative;
#else
return TagCheckNegative;
#endif // __apple__
}
return TagCheckNotCompatible;
}
// return true if NOT in disabled mode.
bool tags_check(const std::string& disabled_tags, const std::string& enabled_tags)
{
if (disabled_tags.empty() && enabled_tags.empty())
return true;
// enabled tags must ALL return affirmative or check fails
if (!enabled_tags.empty()) {
std::string tag;
for (size_t i = 0; i < enabled_tags.size(); i++) {
if (enabled_tags[i] == ' ') {
tag.erase();
continue;
}
if (enabled_tags[i] != ';') {
tag += enabled_tags[i];
}
if (enabled_tags[i] == ';' || i == enabled_tags.size() - 1) {
if (!tag.empty()) {
TagCheckResult result;
result = tag_check_mode(tag);
if (result == TagCheckResult::TagCheckNegative)
return false;
if (result == TagCheckResult::TagCheckAffirmative)
continue;
result = tag_check_tech(tag);
if (result == TagCheckResult::TagCheckNegative)
return false;
if (result == TagCheckResult::TagCheckAffirmative)
continue;
result = tag_check_system(tag);
if (result == TagCheckResult::TagCheckNegative)
return false;
if (result == TagCheckResult::TagCheckAffirmative)
continue;
BOOST_LOG_TRIVIAL(error) << "Hint Notification: Tag " << tag << " in enabled_tags not compatible.";
// non compatible in enabled means return false since all enabled must be affirmative.
return false;
}
}
}
}
// disabled tags must all NOT return affirmative or check fails
if (!disabled_tags.empty()) {
std::string tag;
for (size_t i = 0; i < disabled_tags.size(); i++) {
if (disabled_tags[i] == ' ') {
tag.erase();
continue;
}
if (disabled_tags[i] != ';') {
tag += disabled_tags[i];
}
if (disabled_tags[i] == ';' || i == disabled_tags.size() - 1) {
if (!tag.empty()) {
TagCheckResult result;
result = tag_check_mode(tag);
if (result == TagCheckResult::TagCheckNegative)
continue;
if (result == TagCheckResult::TagCheckAffirmative)
return false;
result = tag_check_tech(tag);
if (result == TagCheckResult::TagCheckNegative)
continue;
if (result == TagCheckResult::TagCheckAffirmative)
return false;
result = tag_check_system(tag);
if (result == TagCheckResult::TagCheckAffirmative)
return false;
if (result == TagCheckResult::TagCheckNegative)
continue;
BOOST_LOG_TRIVIAL(error) << "Hint Notification: Tag " << tag << " in disabled_tags not compatible.";
}
}
}
}
return true;
}
void launch_browser_if_allowed(const std::string& url)
{
if (wxGetApp().app_config->get("suppress_hyperlinks") != "1")
wxLaunchDefaultBrowser(url);
}
} //namespace
@ -90,13 +210,15 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
dict.emplace(data.first, data.second.data());
}
//unescaping a translating all texts
//unescape text1
//unescaping and translating all texts and saving all data common for all hint types
std::string fulltext;
std::string text1;
std::string hypertext_text;
std::string follow_text;
std::string disabled_modes;
std::string disabled_tags;
std::string enabled_tags;
std::string documentation_link;
//unescape text1
unescape_string_cstyle(_utf8(dict["text"]), fulltext);
// replace <b> and </b> for imgui markers
std::string marker_s(1, ImGui::ColorMarkerStart);
@ -143,8 +265,14 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
text1 = fulltext;
}
if (dict.find("disabled_modes") != dict.end()) {
disabled_modes = dict["disabled_modes"];
if (dict.find("disabled_tags") != dict.end()) {
disabled_tags = dict["disabled_tags"];
}
if (dict.find("enabled_tags") != dict.end()) {
enabled_tags = dict["enabled_tags"];
}
if (dict.find("documentation_link") != dict.end()) {
documentation_link = dict["documentation_link"];
}
// create HintData
@ -152,37 +280,37 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
//link to internet
if(dict["hypertext_type"] == "link") {
std::string hypertext_link = dict["hypertext_link"];
HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, false, [hypertext_link]() { wxLaunchDefaultBrowser(hypertext_link); } };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } };
m_loaded_hints.emplace_back(hint_data);
// highlight settings
} else if (dict["hypertext_type"] == "settings") {
std::string opt = dict["hypertext_settings_opt"];
Preset::Type type = static_cast<Preset::Type>(std::atoi(dict["hypertext_settings_type"].c_str()));
std::wstring category = boost::nowide::widen(dict["hypertext_settings_category"]);
HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, true, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } };
m_loaded_hints.emplace_back(hint_data);
// open preferences
} else if(dict["hypertext_type"] == "preferences") {
int page = static_cast<Preset::Type>(std::atoi(dict["hypertext_preferences_page"].c_str()));
HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, false, [page]() { wxGetApp().open_preferences(page); } };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page]() { wxGetApp().open_preferences(page); } };
m_loaded_hints.emplace_back(hint_data);
} else if (dict["hypertext_type"] == "plater") {
std::string item = dict["hypertext_plater_item"];
HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, true, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } };
m_loaded_hints.emplace_back(hint_data);
} else if (dict["hypertext_type"] == "gizmo") {
std::string item = dict["hypertext_gizmo_item"];
HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, true, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } };
m_loaded_hints.emplace_back(hint_data);
}
else if (dict["hypertext_type"] == "gallery") {
HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, false, []() { wxGetApp().obj_list()->load_shape_object_from_gallery(); } };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, []() { wxGetApp().obj_list()->load_shape_object_from_gallery(); } };
m_loaded_hints.emplace_back(hint_data);
}
} else {
// plain text without hypertext
HintData hint_data{ text1 };
HintData hint_data{ text1, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link };
m_loaded_hints.emplace_back(hint_data);
}
}
@ -194,8 +322,14 @@ HintData* HintDatabase::get_hint(bool up)
init();
//return false;
}
if (m_loaded_hints.empty())
{
BOOST_LOG_TRIVIAL(error) << "There were no hints loaded from hints.ini file.";
return nullptr;
}
// shift id
m_hint_id = (up ? m_hint_id + 1 : (m_hint_id == 0 ? m_loaded_hints.size() - 1 : m_hint_id - 1));
m_hint_id = (up ? m_hint_id + 1 : m_hint_id );
m_hint_id %= m_loaded_hints.size();
AppConfig* app_config = wxGetApp().app_config;
@ -220,12 +354,16 @@ void NotificationManager::HintNotification::count_spaces()
std::string text;
text = ImGui::WarningMarker;
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
m_left_indentation = picture_width + m_line_height / 2;
m_left_indentation = picture_width * 1.5f + m_line_height / 2;
// no left button picture
//m_left_indentation = m_line_height;
m_window_width_offset = m_left_indentation + m_line_height * 3.f;// 5.5f; // no right arrow
if (m_documentation_link.empty())
m_window_width_offset = m_left_indentation + m_line_height * 3.f;
else
m_window_width_offset = m_left_indentation + m_line_height * 5.5f;
m_window_width = m_line_height * 25;
}
@ -263,7 +401,7 @@ void NotificationManager::HintNotification::count_lines()
}
// when one word longer than line.
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset ||
ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 4 * 3
ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 5 * 3
) {
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
@ -333,7 +471,7 @@ void NotificationManager::HintNotification::count_lines()
}
// when one word longer than line.
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset - size_of_last_line ||
ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x + size_of_last_line < (m_window_width - m_window_width_offset) / 4 * 3
ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x + size_of_last_line < (m_window_width - m_window_width_offset) / 5 * 3
) {
float width_of_a = ImGui::CalcTextSize("a").x;
int letter_count = (int)((m_window_width - m_window_width_offset - size_of_last_line) / width_of_a);
@ -387,12 +525,12 @@ void NotificationManager::HintNotification::set_next_window_size(ImGuiWrapper& i
m_window_height += 1 * m_line_height; // top and bottom
*/
m_window_height = std::max((m_lines_count + 1.f) * m_line_height, 4.f * m_line_height);
m_window_height = std::max((m_lines_count + 1.f) * m_line_height, 5.f * m_line_height);
}
bool NotificationManager::HintNotification::on_text_click()
{
if (m_hypertext_callback != nullptr && (!m_runtime_disable || disabled_modes_check(m_disabled_modes)))
if (m_hypertext_callback != nullptr && (!m_runtime_disable || tags_check(m_disabled_tags, m_enabled_tags)))
m_hypertext_callback();
return false;
}
@ -405,7 +543,7 @@ void NotificationManager::HintNotification::render_text(ImGuiWrapper& imgui, con
float x_offset = m_left_indentation;
int last_end = 0;
float starting_y = (m_lines_count == 2 ? win_size_y / 2 - m_line_height :(m_lines_count == 1 ? win_size_y / 2 - m_line_height / 2: m_line_height / 2));
float starting_y = (m_lines_count < 4 ? m_line_height / 2 * (4 - m_lines_count + 1) : m_line_height / 2);
float shift_y = m_line_height;
std::string line;
@ -425,8 +563,8 @@ void NotificationManager::HintNotification::render_text(ImGuiWrapper& imgui, con
// regural line
line = m_text1.substr(last_end, m_endlines[i] - last_end);
}
// first line is headline
if (i == 0) {
// first line is headline (for hint notification it must be divided by \n)
if (m_text1.find('\n') >= m_endlines[i]) {
line = ImGui::ColorMarkerStart + line + ImGui::ColorMarkerEnd;
}
// Add ImGui::ColorMarkerStart if there is ImGui::ColorMarkerEnd first (start was at prev line)
@ -524,16 +662,17 @@ void NotificationManager::HintNotification::render_close_button(ImGuiWrapper& im
close();
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
render_right_arrow_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
//render_right_arrow_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_logo(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_preferences_button(imgui, win_pos_x, win_pos_y);
if (!m_documentation_link.empty() && wxGetApp().app_config->get("suppress_hyperlinks") != "1")
{
render_documentation_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
}
void NotificationManager::HintNotification::render_preferences_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y)
@ -548,12 +687,23 @@ void NotificationManager::HintNotification::render_preferences_button(ImGuiWrapp
std::string button_text;
button_text = ImGui::PreferencesButton;
//hover
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 10.f, win_pos_y + m_window_height - 2 * m_line_height + 1),
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 15.f, win_pos_y + m_window_height - 1.75f * m_line_height),
ImVec2(win_pos_x, win_pos_y + m_window_height),
true))
{
true)) {
button_text = ImGui::PreferencesHoverButton;
// tooltip
long time_now = wxGetLocalTime();
if (m_prefe_hover_time > 0 && m_prefe_hover_time < time_now) {
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
ImGui::BeginTooltip();
imgui.text(_u8L("Open Preferences."));
ImGui::EndTooltip();
ImGui::PopStyleColor();
}
if (m_prefe_hover_time == 0)
m_prefe_hover_time = time_now;
} else
m_prefe_hover_time = 0;
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
@ -568,15 +718,10 @@ void NotificationManager::HintNotification::render_preferences_button(ImGuiWrapp
wxGetApp().open_preferences(2);
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
// preferences button is in place of minimize button
m_minimize_b_visible = true;
}
void NotificationManager::HintNotification::render_right_arrow_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
// Used for debuging
@ -605,11 +750,7 @@ void NotificationManager::HintNotification::render_right_arrow_button(ImGuiWrapp
retrieve_data();
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
}
void NotificationManager::HintNotification::render_logo(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
@ -621,32 +762,95 @@ void NotificationManager::HintNotification::render_logo(ImGuiWrapper& imgui, con
push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
std::string button_text;
button_text = ImGui::ErrorMarker;//LeftArrowButton;
std::wstring button_text;
button_text = ImGui::ClippyMarker;//LeftArrowButton;
std::string placeholder_text;
placeholder_text = ImGui::EjectButton;
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
ImVec2 button_pic_size = ImGui::CalcTextSize(placeholder_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f * 2.f, button_pic_size.y * 1.25f * 2.f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y * 1.1f);
ImGui::SetCursorPosX(0);
// shouldnt it render as text?
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
{
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
}
void NotificationManager::HintNotification::render_documentation_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
std::wstring button_text;
button_text = ImGui::DocumentationButton;
std::string placeholder_text;
placeholder_text = ImGui::EjectButton;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y),
ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y - 2 * m_line_height),
true))
{
button_text = ImGui::DocumentationHoverButton;
// tooltip
long time_now = wxGetLocalTime();
if (m_docu_hover_time > 0 && m_docu_hover_time < time_now) {
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
ImGui::BeginTooltip();
imgui.text(_u8L("Open Documentation in web browser."));
ImGui::EndTooltip();
ImGui::PopStyleColor();
}
void NotificationManager::HintNotification::retrieve_data(size_t recursion_counter)
if (m_docu_hover_time == 0)
m_docu_hover_time = time_now;
}
else
m_docu_hover_time = 0;
ImVec2 button_pic_size = ImGui::CalcTextSize(placeholder_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
ImGui::SetCursorPosX(win_size.x - m_line_height * 5.0f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
{
HintData* hint_data = HintDatabase::get_instance().get_hint(true);
if (hint_data != nullptr && !disabled_modes_check(hint_data->disabled_modes))
open_documentation();
}
//invisible large button
ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f);
ImGui::SetCursorPosY(0);
if (imgui.button(" ", m_line_height * 2.f, win_size.y - 2 * m_line_height))
{
open_documentation();
}
ImGui::PopStyleColor(5);
}
void NotificationManager::HintNotification::open_documentation()
{
if (!m_documentation_link.empty())
{
launch_browser_if_allowed(m_documentation_link);
}
}
void NotificationManager::HintNotification::retrieve_data(int recursion_counter)
{
HintData* hint_data = HintDatabase::get_instance().get_hint(recursion_counter >= 0 ? true : false);
if (hint_data == nullptr)
close();
if (hint_data != nullptr && !tags_check(hint_data->disabled_tags, hint_data->enabled_tags))
{
// Content for different user - retrieve another
size_t count = HintDatabase::get_instance().get_count();
if (count < recursion_counter) {
if ((int)count < recursion_counter) {
BOOST_LOG_TRIVIAL(error) << "Hint notification failed to load data due to recursion counter.";
} else {
retrieve_data(recursion_counter + 1);
@ -661,12 +865,13 @@ void NotificationManager::HintNotification::retrieve_data(size_t recursion_count
hint_data->text,
hint_data->hypertext, nullptr,
hint_data->follow_text };
update(nd);
m_hypertext_callback = hint_data->callback;
m_disabled_modes = hint_data->disabled_modes;
m_disabled_tags = hint_data->disabled_tags;
m_enabled_tags = hint_data->enabled_tags;
m_runtime_disable = hint_data->runtime_disable;
m_documentation_link = hint_data->documentation_link;
m_has_hint_data = true;
update(nd);
}
}
} //namespace Slic3r

View File

@ -12,8 +12,10 @@ struct HintData
std::string text;
std::string hypertext;
std::string follow_text;
std::string disabled_modes;
std::string disabled_tags;
std::string enabled_tags;
bool runtime_disable; // if true - hyperlink will check before every click if not in disabled mode
std::string documentation_link;
std::function<void(void)> callback { nullptr };
};
@ -53,12 +55,13 @@ private:
class NotificationManager::HintNotification : public NotificationManager::PopNotification
{
public:
HintNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler)
HintNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool new_hint)
: PopNotification(n, id_provider, evt_handler)
{
retrieve_data();
retrieve_data(new_hint ? 0 : -1);
}
virtual void init() override;
void open_next() { retrieve_data(0); }
protected:
virtual void set_next_window_size(ImGuiWrapper& imgui) override;
virtual void count_spaces() override;
@ -77,18 +80,27 @@ protected:
void render_right_arrow_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);
void render_documentation_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);
void render_logo(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y);
void retrieve_data(size_t recursion_counter = 0);
// recursion counter -1 tells to retrieve same hint as last time
void retrieve_data(int recursion_counter = 0);
void open_documentation();
bool m_has_hint_data { false };
std::function<void(void)> m_hypertext_callback;
std::string m_disabled_modes;
std::string m_disabled_tags;
std::string m_enabled_tags;
bool m_runtime_disable;
std::string m_documentation_link;
float m_close_b_y { 0 };
float m_close_b_w { 0 };
// hover of buttons
long m_docu_hover_time { 0 };
long m_prefe_hover_time{ 0 };
};
} //namespace Slic3r

View File

@ -36,7 +36,7 @@ namespace Slic3r {
namespace GUI {
static const std::map<const char, std::string> font_icons = {
static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::PrintIconMarker , "cog" },
{ImGui::PrinterIconMarker , "printer" },
{ImGui::PrinterSlaIconMarker , "sla_printer" },
@ -49,7 +49,7 @@ static const std::map<const char, std::string> font_icons = {
{ImGui::PreferencesButton , "notification_preferences" },
{ImGui::PreferencesHoverButton , "notification_preferences_hover"},
};
static const std::map<const char, std::string> font_icons_large = {
static const std::map<const wchar_t, std::string> font_icons_large = {
{ImGui::CloseNotifButton , "notification_close" },
{ImGui::CloseNotifHoverButton , "notification_close_hover" },
{ImGui::EjectButton , "notification_eject_sd" },
@ -61,8 +61,14 @@ static const std::map<const char, std::string> font_icons_large = {
{ImGui::SinkingObjectMarker , "move" },
{ImGui::CustomSupportsMarker , "fdm_supports" },
{ImGui::CustomSeamMarker , "seam" },
{ImGui::MmuSegmentationMarker , "move" },
{ImGui::MmuSegmentationMarker , "mmu_segmentation" },
{ImGui::VarLayerHeightMarker , "layers" },
{ImGui::DocumentationButton , "notification_documentation" },
{ImGui::DocumentationHoverButton, "notification_documentation_hover"},
};
static const std::map<const wchar_t, std::string> font_icons_extra_large = {
{ImGui::ClippyMarker , "notification_clippy" },
};
@ -989,6 +995,8 @@ void ImGuiWrapper::init_font(bool compress)
io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz);
for (auto& icon : font_icons_large)
io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2);
for (auto& icon : font_icons_extra_large)
io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4);
// Build texture atlas
unsigned char* pixels;
@ -1027,6 +1035,22 @@ void ImGuiWrapper::init_font(bool compress)
rect_id++;
}
icon_sz *= 2; // default size of extra large icon is 64 px
for (auto icon : font_icons_extra_large) {
if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) {
assert(rect->Width == icon_sz);
assert(rect->Height == icon_sz);
std::vector<unsigned char> raw_data = load_svg(icon.second, icon_sz, icon_sz);
const ImU32* pIn = (ImU32*)raw_data.data();
for (int y = 0; y < icon_sz; y++) {
ImU32* pOut = (ImU32*)pixels + (rect->Y + y) * width + (rect->X);
for (int x = 0; x < icon_sz; x++)
*pOut++ = *pIn++;
}
}
rect_id++;
}
// Upload texture to graphics system
GLint last_texture;
glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));

View File

@ -33,7 +33,7 @@ public:
m_filepicker = new wxFilePickerCtrl(this, wxID_ANY,
from_u8(wxGetApp().app_config->get_last_dir()), _(L("Choose SLA archive:")),
"SL1 archive files (*.sl1, *.zip)|*.sl1;*.SL1;*.zip;*.ZIP",
"SL1 / SL1S archive files (*.sl1, *.sl1s, *.zip)|*.sl1;*.SL1;*.sl1s;*.SL1S;*.zip;*.ZIP",
wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE | wxFD_OPEN | wxFD_FILE_MUST_EXIST);
szfilepck->Add(new wxStaticText(this, wxID_ANY, _L("Import file") + ": "), 0, wxALIGN_CENTER);
@ -119,6 +119,7 @@ public:
wxString path;
Vec2i win = {2, 2};
std::string err;
ConfigSubstitutions config_substitutions;
priv(Plater *plt) : plater{plt} {}
};
@ -140,17 +141,16 @@ void SLAImportJob::process()
if (p->path.empty()) return;
std::string path = p->path.ToUTF8().data();
ConfigSubstitutions config_substitutions;
try {
switch (p->sel) {
case Sel::modelAndProfile:
config_substitutions = import_sla_archive(path, p->win, p->mesh, p->profile, progr);
p->config_substitutions = import_sla_archive(path, p->win, p->mesh, p->profile, progr);
break;
case Sel::modelOnly:
config_substitutions = import_sla_archive(path, p->win, p->mesh, progr);
p->config_substitutions = import_sla_archive(path, p->win, p->mesh, progr);
break;
case Sel::profileOnly:
config_substitutions = import_sla_archive(path, p->profile);
p->config_substitutions = import_sla_archive(path, p->profile);
break;
}
@ -158,10 +158,6 @@ void SLAImportJob::process()
p->err = ex.what();
}
if (! config_substitutions.empty()) {
//FIXME Add reporting here "Loading profiles found following incompatibilities."
}
update_status(100, was_canceled() ? _(L("Importing canceled.")) :
_(L("Importing done.")));
}
@ -187,6 +183,7 @@ void SLAImportJob::prepare()
p->path = !nm.Exists(wxFILE_EXISTS_REGULAR) ? "" : nm.GetFullPath();
p->sel = dlg.get_selection();
p->win = dlg.get_marchsq_windowsize();
p->config_substitutions.clear();
} else {
p->path = "";
}
@ -231,7 +228,10 @@ void SLAImportJob::finalize()
name, is_centered);
}
if (! p->config_substitutions.empty())
show_substitutions_info(p->config_substitutions, p->path.ToUTF8().data());
reset();
}
}}
}} // namespace Slic3r::GUI

View File

@ -151,6 +151,9 @@ void KBShortcutsDialog::fill_shortcuts()
{ "F", L("Gizmo Place face on bed") },
{ "H", L("Gizmo SLA hollow") },
{ "L", L("Gizmo SLA support points") },
{ "L", L("Gizmo FDM paint-on supports") },
{ "P", L("Gizmo FDM paint-on seam") },
{ "N", L("Gizmo Multi Material painting") },
{ "Esc", L("Unselect gizmo or clear selection") },
{ "K", L("Change camera type (perspective, orthographic)") },
{ "B", L("Zoom to Bed") },

View File

@ -45,6 +45,7 @@
#include "GUI_Factories.hpp"
#include "GUI_ObjectList.hpp"
#include "GalleryDialog.hpp"
#include "NotificationManager.hpp"
#ifdef _WIN32
#include <dbt.h>
@ -219,15 +220,19 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
return;
}
if (m_plater != nullptr && !m_plater->save_project_if_dirty()) {
if (m_plater != nullptr) {
int saved_project = m_plater->save_project_if_dirty();
if (saved_project == wxID_CANCEL) {
event.Veto();
return;
}
// check unsaved changes only if project wasn't saved
else if (saved_project == wxID_NO && event.CanVeto() && !wxGetApp().check_and_save_current_preset_changes()) {
event.Veto();
return;
}
}
if (event.CanVeto() && !wxGetApp().check_and_save_current_preset_changes()) {
event.Veto();
return;
}
if (event.CanVeto() && !wxGetApp().check_print_host_queue()) {
event.Veto();
return;
@ -1073,6 +1078,8 @@ static wxMenu* generate_help_menu()
else
append_menu_item(helpMenu, wxID_ANY, wxString::Format(_L("&About %s"), GCODEVIEWER_APP_NAME), _L("Show about dialog"),
[](wxCommandEvent&) { Slic3r::GUI::about(); });
append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the day"), _L("Opens Tip of the day notification in bottom right corner or shows another tip if already opened."),
[](wxCommandEvent&) { wxGetApp().plater()->get_notification_manager()->push_hint_notification(false); });
helpMenu->AppendSeparator();
append_menu_item(helpMenu, wxID_ANY, _L("Keyboard Shortcuts") + sep + "&?", _L("Show the list of the keyboard shortcuts"),
[](wxCommandEvent&) { wxGetApp().keyboard_shortcuts(); });
@ -1181,7 +1188,7 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(true); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 archive") + dots, _L("Load an SL1 archive"),
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 / SL1S archive") + dots, _L("Load an SL1 / Sl1S archive"),
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
[this](){return m_plater != nullptr; }, this);
@ -1742,12 +1749,8 @@ bool MainFrame::load_config_file(const std::string &path)
{
try {
ConfigSubstitutions config_substitutions = wxGetApp().preset_bundle->load_config_file(path, ForwardCompatibilitySubstitutionRule::Enable);
if (! config_substitutions.empty()) {
// TODO: Add list of changes from all_substitutions
show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities."
" To recover these files, incompatible values were changed to default values."
" But data in files won't be changed until you save them in PrusaSlicer.")));
}
if (!config_substitutions.empty())
show_substitutions_info(config_substitutions, path);
} catch (const std::exception &ex) {
show_error(this, ex.what());
return false;
@ -1806,18 +1809,16 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re
size_t presets_imported = 0;
PresetsConfigSubstitutions config_substitutions;
try {
std::tie(config_substitutions, presets_imported) = wxGetApp().preset_bundle->load_configbundle(file.ToUTF8().data(), PresetBundle::LoadConfigBundleAttribute::SaveImported);
// Report all substitutions.
std::tie(config_substitutions, presets_imported) = wxGetApp().preset_bundle->load_configbundle(
file.ToUTF8().data(), PresetBundle::LoadConfigBundleAttribute::SaveImported, ForwardCompatibilitySubstitutionRule::Enable);
} catch (const std::exception &ex) {
show_error(this, ex.what());
return;
}
if (! config_substitutions.empty()) {
// TODO: Add list of changes from all_substitutions
show_error(nullptr, GUI::format(_L("Loading profiles found following incompatibilities."
" To recover these files, incompatible values were changed to default values."
" But data in files won't be changed until you save them in PrusaSlicer.")));
}
if (! config_substitutions.empty())
show_substitutions_info(config_substitutions);
// Load the currently selected preset into the GUI, update the preset selection box.
wxGetApp().load_current_presets();

View File

@ -24,6 +24,15 @@ void MeshClipper::set_plane(const ClippingPlane& plane)
}
void MeshClipper::set_limiting_plane(const ClippingPlane& plane)
{
if (m_limiting_plane != plane) {
m_limiting_plane = plane;
m_triangles_valid = false;
}
}
void MeshClipper::set_mesh(const TriangleMesh& mesh)
{
@ -78,29 +87,82 @@ void MeshClipper::recalculate_triangles()
float height_mesh = m_plane.distance(m_trafo.get_offset()) * (up_noscale.norm()/up.norm());
// Now do the cutting
MeshSlicingParamsEx slicing_params;
MeshSlicingParams slicing_params;
slicing_params.trafo.rotate(Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(up, Vec3d::UnitZ()));
assert(m_mesh->has_shared_vertices());
std::vector<ExPolygons> list_of_expolys = slice_mesh_ex(m_mesh->its, std::vector<float>{height_mesh}, slicing_params);
ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params));
if (m_negative_mesh && !m_negative_mesh->empty()) {
assert(m_negative_mesh->has_shared_vertices());
std::vector<ExPolygons> neg_polys = slice_mesh_ex(m_negative_mesh->its, std::vector<float>{height_mesh}, slicing_params);
list_of_expolys.front() = diff_ex(list_of_expolys.front(), neg_polys.front());
ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params));
expolys = diff_ex(expolys, neg_expolys);
}
m_triangles2d = triangulate_expolygons_2f(list_of_expolys[0], m_trafo.get_matrix().matrix().determinant() < 0.);
// Rotate the cut into world coords:
// Triangulate and rotate the cut into world coords:
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), up);
Transform3d tr = Transform3d::Identity();
tr.rotate(q);
tr = m_trafo.get_matrix() * tr;
height_mesh += 0.001f; // to avoid z-fighting
// to avoid z-fighting
height_mesh += 0.001f;
if (m_limiting_plane != ClippingPlane::ClipsNothing())
{
// Now remove whatever ended up below the limiting plane (e.g. sinking objects).
// First transform the limiting plane from world to mesh coords.
// Note that inverse of tr transforms the plane from world to horizontal.
Vec3d normal_old = m_limiting_plane.get_normal().normalized();
Vec3d normal_new = (tr.matrix().block<3,3>(0,0).transpose() * normal_old).normalized();
// normal_new should now be the plane normal in mesh coords. To find the offset,
// transform a point and set offset so it belongs to the transformed plane.
Vec3d pt = Vec3d::Zero();
double plane_offset = m_limiting_plane.get_data()[3];
if (std::abs(normal_old.z()) > 0.5) // normal is normalized, at least one of the coords if larger than sqrt(3)/3 = 0.57
pt.z() = - plane_offset / normal_old.z();
else if (std::abs(normal_old.y()) > 0.5)
pt.y() = - plane_offset / normal_old.y();
else
pt.x() = - plane_offset / normal_old.x();
pt = tr.inverse() * pt;
double offset = -(normal_new.dot(pt));
if (std::abs(normal_old.dot(m_plane.get_normal().normalized())) > 0.99) {
// The cuts are parallel, show all or nothing.
if (offset < height_mesh)
expolys.clear();
} else {
// The cut is a horizontal plane defined by z=height_mesh.
// ax+by+e=0 is the line of intersection with the limiting plane.
// Normalized so a^2 + b^2 = 1.
double len = std::hypot(normal_new.x(), normal_new.y());
if (len == 0.)
return;
double a = normal_new.x() / len;
double b = normal_new.y() / len;
double e = (normal_new.z() * height_mesh + offset) / len;
if (b == 0.)
return;
// We need a half-plane to limit the cut. Get angle of the intersecting line.
double angle = std::atan(-a/b);
if (b > 0) // select correct half-plane
angle += M_PI;
// We'll take a big rectangle above x-axis and rotate and translate
// it so it lies on our line. This will be the figure to subtract
// from the cut. The coordinates must not overflow after the transform,
// make the rectangle a bit smaller.
coord_t size = (std::numeric_limits<coord_t>::max() - scale_(std::max(std::abs(e*a), std::abs(e*b)))) / 4;
Polygons ep {Polygon({Point(-size, 0), Point(size, 0), Point(size, 2*size), Point(-size, 2*size)})};
ep.front().rotate(angle);
ep.front().translate(scale_(-e * a), scale_(-e * b));
expolys = diff_ex(expolys, ep);
}
}
m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.);
m_vertex_array.release_geometry();
for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) {
@ -159,18 +221,20 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
unsigned i = 0;
// Remove points that are obscured or cut by the clipping plane
if (clipping_plane) {
for (i=0; i<hits.size(); ++i)
if (! clipping_plane->is_point_clipped(trafo * hits[i].position()))
// Remove points that are obscured or cut by the clipping plane.
// Also, remove anything below the bed (sinking objects).
for (i=0; i<hits.size(); ++i) {
Vec3d transformed_hit = trafo * hits[i].position();
if (transformed_hit.z() >= 0. &&
(! clipping_plane || ! clipping_plane->is_point_clipped(transformed_hit)))
break;
}
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
// All hits are either clipped, or there is an odd number of unclipped
// hits - meaning the nearest must be from inside the mesh.
return false;
}
}
// Now stuff the points in the provided vector and calculate normals if asked about them:
position = hits[i].position().cast<float>();

View File

@ -71,6 +71,11 @@ public:
// This is supposed to be in world coordinates.
void set_plane(const ClippingPlane& plane);
// In case the object is clipped by two planes (e.g. in case of sinking
// objects), this will be used to clip the triagnulated cut.
// Pass ClippingPlane::ClipsNothing to turn this off.
void set_limiting_plane(const ClippingPlane& plane);
// Which mesh to cut. MeshClipper remembers const * to it, caller
// must make sure that it stays valid.
void set_mesh(const TriangleMesh& mesh);
@ -92,6 +97,7 @@ private:
const TriangleMesh* m_mesh = nullptr;
const TriangleMesh* m_negative_mesh = nullptr;
ClippingPlane m_plane;
ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing();
std::vector<Vec2f> m_triangles2d;
GLIndexedVertexArray m_vertex_array;
bool m_triangles_valid = false;

View File

@ -61,7 +61,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
topsizer->Add(logo, 0, wxALL, BORDER);
topsizer->Add(rightsizer, 1, wxALL | wxEXPAND, BORDER);
topsizer->Add(rightsizer, 1, wxTOP | wxBOTTOM | wxRIGHT | wxEXPAND, BORDER);
SetSizerAndFit(topsizer);
}
@ -98,7 +98,6 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
msg_lines++;
}
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), monospaced_font ? 30 * wxGetApp().em_unit() : 2 * msg_lines * wxGetApp().em_unit()));
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
wxFont monospace = wxGetApp().code_font();
wxColour text_clr = wxGetApp().get_label_clr_default();
@ -109,6 +108,30 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
int size[] = { font_size, font_size, font_size, font_size, font_size, font_size, font_size };
html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size);
html->SetBorders(2);
// calculate html page size from text
wxSize page_size;
int em = wxGetApp().em_unit();
// if message containes the table
if (msg.Contains("<tr>")) {
int lines = msg.Freq('\n') + 1;
int pos = 0;
while (pos < (int)msg.Len() && pos != wxNOT_FOUND) {
pos = msg.find("<tr>", pos + 1);
lines += 2;
}
int page_height = std::min(int(font.GetPixelSize().y+2) * lines, 68 * em);
page_size = wxSize(68 * em, page_height);
}
else {
wxClientDC dc(parent);
wxSize msg_sz = dc.GetMultiLineTextExtent(msg);
page_size = wxSize(std::min(msg_sz.GetX() + 2 * em, 68 * em),
std::min(msg_sz.GetY() + 2 * em, 68 * em));
}
html->SetMinSize(page_size);
std::string msg_escaped = xml_escape(msg.ToUTF8().data());
boost::replace_all(msg_escaped, "\r\n", "<br>");
boost::replace_all(msg_escaped, "\n", "<br>");
@ -116,7 +139,7 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin
// Code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
msg_escaped = std::string("<pre><code>") + msg_escaped + "</code></pre>";
html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>");
content_sizer->Add(html, 1, wxEXPAND | wxBOTTOM, 30);
content_sizer->Add(html, 1, wxEXPAND);
}
// ErrorDialog
@ -131,7 +154,7 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_
add_btn(wxID_OK, true);
// Use a small bitmap with monospaced font, as the error text will not be wrapped.
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, monospaced_font ? 48 : /*1*/92));
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, monospaced_font ? 48 : /*1*/84));
wxGetApp().UpdateDlgDarkUI(this);
@ -155,7 +178,7 @@ WarningDialog::WarningDialog(wxWindow *parent,
if (style & wxYES) add_btn(wxID_YES);
if (style & wxNO) add_btn(wxID_NO);
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 90));
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 84));
wxGetApp().UpdateDlgDarkUI(this);
Fit();
@ -179,8 +202,8 @@ MessageDialog::MessageDialog(wxWindow* parent,
if (style & wxCANCEL) add_btn(wxID_CANCEL);
logo->SetBitmap(create_scaled_bitmap(style & wxICON_WARNING ? "exclamation" :
style & wxICON_INFORMATION ? "info.png" :
style & wxICON_QUESTION ? "question" : "PrusaSlicer_192px_grayscale.png", this, 90));
style & wxICON_INFORMATION ? "info" :
style & wxICON_QUESTION ? "question" : "PrusaSlicer_192px_grayscale.png", this, 84));
wxGetApp().UpdateDlgDarkUI(this);
Fit();
@ -188,5 +211,57 @@ MessageDialog::MessageDialog(wxWindow* parent,
}
#endif
// InfoDialog
InfoDialog::InfoDialog(wxWindow* parent, const wxString &title, const wxString& msg)
: MsgDialog(parent, wxString::Format(_L("%s information"), SLIC3R_APP_NAME), title)
, msg(msg)
{
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
// Text shown as HTML, so that mouse selection and Ctrl-V to copy will work.
wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
{
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
wxFont monospace = wxGetApp().code_font();
wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
const int font_size = font.GetPointSize() - 1;
int size[] = { font_size, font_size, font_size, font_size, font_size, font_size, font_size };
html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size);
html->SetBorders(2);
// calculate html page size from text
int lines = msg.Freq('\n');
if (msg.Contains("<tr>")) {
int pos = 0;
while (pos < (int)msg.Len() && pos != wxNOT_FOUND) {
pos = msg.find("<tr>", pos + 1);
lines+=2;
}
}
int page_height = std::min((font.GetPixelSize().y + 1) * lines, 68 * wxGetApp().em_unit());
wxSize page_size(68 * wxGetApp().em_unit(), page_height);
html->SetMinSize(page_size);
std::string msg_escaped = xml_escape(msg.ToUTF8().data(), true);
boost::replace_all(msg_escaped, "\r\n", "<br>");
boost::replace_all(msg_escaped, "\n", "<br>");
html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>");
content_sizer->Add(html, 1, wxEXPAND);
}
// Set info bitmap
logo->SetBitmap(create_scaled_bitmap("info", this, 84));
Fit();
}
}
}

View File

@ -114,6 +114,22 @@ public:
#endif
// Generic info dialog, used for displaying exceptions
class InfoDialog : public MsgDialog
{
public:
InfoDialog(wxWindow *parent, const wxString &title, const wxString &msg);
InfoDialog(InfoDialog&&) = delete;
InfoDialog(const InfoDialog&) = delete;
InfoDialog&operator=(InfoDialog&&) = delete;
InfoDialog&operator=(const InfoDialog&) = delete;
virtual ~InfoDialog() = default;
private:
wxString msg;
};
}
}

View File

@ -24,7 +24,7 @@ ButtonsListCtrl::ButtonsListCtrl(wxWindow *parent, bool add_mode_buttons/* = fal
m_sizer = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(m_sizer);
m_buttons_sizer = new wxFlexGridSizer(4, m_btn_margin, m_btn_margin);
m_buttons_sizer = new wxFlexGridSizer(1, m_btn_margin, m_btn_margin);
m_sizer->Add(m_buttons_sizer, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxBOTTOM, m_btn_margin);
if (add_mode_buttons) {
@ -111,6 +111,7 @@ bool ButtonsListCtrl::InsertPage(size_t n, const wxString& text, bool bSelect/*
Slic3r::GUI::wxGetApp().UpdateDarkUI(btn);
m_pageButtons.insert(m_pageButtons.begin() + n, btn);
m_buttons_sizer->Insert(n, new wxSizerItem(btn));
m_buttons_sizer->SetCols(m_buttons_sizer->GetCols() + 1);
m_sizer->Layout();
return true;
}

View File

@ -218,6 +218,7 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
if (m_state == EState::FadingOut) {
push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity);
push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity);
push_style_color(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered), true, m_current_fade_opacity);
fading_pop = true;
}
@ -229,7 +230,7 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
m_id = m_id_provider.allocate_id();
std::string name = "!!Ntfctn" + std::to_string(m_id);
if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar)) {
if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
ImVec2 win_size = ImGui::GetWindowSize();
render_left_sign(imgui);
@ -245,7 +246,7 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
ImGui::PopStyleColor();
if (fading_pop)
ImGui::PopStyleColor(2);
ImGui::PopStyleColor(3);
}
bool NotificationManager::PopNotification::push_background_color()
{
@ -440,9 +441,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
close();
}
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(3);
//hover color
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
@ -501,11 +500,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
{
close();
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
}
void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui)
@ -545,11 +540,7 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper&
m_multiline = false;
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
m_minimize_b_visible = true;
}
bool NotificationManager::PopNotification::on_text_click()
@ -790,11 +781,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
close();
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
}
bool NotificationManager::ExportFinishedNotification::on_text_click()
{
@ -1054,11 +1041,7 @@ void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGu
{
wxGetApp().printhost_job_queue().cancel(m_job_id - 1);
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor(5);
}
//------UpdatedItemsInfoNotification-------
void NotificationManager::UpdatedItemsInfoNotification::count_spaces()
@ -1074,10 +1057,39 @@ void NotificationManager::UpdatedItemsInfoNotification::count_spaces()
m_window_width_offset = m_left_indentation + m_line_height * 3.f;
m_window_width = m_line_height * 25;
}
void NotificationManager::UpdatedItemsInfoNotification::add_type(InfoItemType type)
{
std::vector<std::pair<InfoItemType, size_t>>::iterator it = m_types_and_counts.begin();
for (; it != m_types_and_counts.end(); ++it) {
if ((*it).first == type) {
(*it).second++;
break;
}
}
if (it == m_types_and_counts.end())
m_types_and_counts.emplace_back(type, 1);
std::string text;
for (it = m_types_and_counts.begin(); it != m_types_and_counts.end(); ++it) {
text += std::to_string((*it).second);
text += _L_PLURAL(" Object was loaded with "," Objects were loaded with ", (*it).second).ToUTF8().data();
switch ((*it).first) {
case InfoItemType::CustomSupports: text += _utf8("custom supports.\n"); break;
case InfoItemType::CustomSeam: text += _utf8("custom seam.\n"); break;
case InfoItemType::MmuSegmentation: text += _utf8("multimaterial painting.\n"); break;
case InfoItemType::VariableLayerHeight: text += _utf8("variable layer height.\n"); break;
case InfoItemType::Sinking: text += _utf8("Partial sinking.\n"); break;
default: BOOST_LOG_TRIVIAL(error) << "Unknown InfoItemType: " << (*it).second; break;
}
}
NotificationData data { get_data().type, get_data().level , get_data().duration, text };
update(data);
}
void NotificationManager::UpdatedItemsInfoNotification::render_left_sign(ImGuiWrapper& imgui)
{
std::string text;
switch (m_info_item_type) {
InfoItemType type = (m_types_and_counts.empty() ? InfoItemType::CustomSupports : m_types_and_counts[0].first);
switch (type) {
case InfoItemType::CustomSupports: text = ImGui::CustomSupportsMarker; break;
case InfoItemType::CustomSeam: text = ImGui::CustomSeamMarker; break;
case InfoItemType::MmuSegmentation: text = ImGui::MmuSegmentationMarker; break;
@ -1347,31 +1359,43 @@ void NotificationManager::upload_job_notification_show_error(int id, const std::
}
}
}
void NotificationManager::push_hint_notification()
void NotificationManager::push_hint_notification(bool open_next)
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::DidYouKnowHint) {
(dynamic_cast<HintNotification*>(notification.get()))->open_next();
return;
}
}
NotificationData data{ NotificationType::DidYouKnowHint, NotificationLevel::RegularNotification, 300, "" };
push_notification_data(std::make_unique<NotificationManager::HintNotification>(data, m_id_provider, m_evt_handler, open_next), 0);
}
bool NotificationManager::is_hint_notification_open()
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::DidYouKnowHint)
return;
return true;
}
NotificationData data{ NotificationType::DidYouKnowHint, NotificationLevel::RegularNotification, 0, "" };
push_notification_data(std::make_unique<NotificationManager::HintNotification>(data, m_id_provider, m_evt_handler), 0);
return false;
}
void NotificationManager::push_updated_item_info_notification(InfoItemType type)
{
std::string text = _utf8("Object(s) were loaded with ");
switch (type) {
case InfoItemType::CustomSupports: text += _utf8("custom supports."); break;
case InfoItemType::CustomSeam: text += _utf8("custom seam."); break;
case InfoItemType::MmuSegmentation: text += _utf8("MMU segmentation."); break;
case InfoItemType::VariableLayerHeight: text += _utf8("variable layer height."); break;
case InfoItemType::Sinking: text = _utf8("Partially sinking object(s) were loaded."); break;
default: text.clear(); break;
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::UpdatedItemsInfo) {
(dynamic_cast<UpdatedItemsInfoNotification*>(notification.get()))->add_type(type);
return;
}
if (!text.empty()) {
NotificationData data{ NotificationType::UpdatedItemsInfo, NotificationLevel::RegularNotification, 10, text };
push_notification_data(std::make_unique<NotificationManager::UpdatedItemsInfoNotification>(data, m_id_provider, m_evt_handler, type), 0);
}
NotificationData data{ NotificationType::UpdatedItemsInfo, NotificationLevel::RegularNotification, 5, "" };
auto notification = std::make_unique<NotificationManager::UpdatedItemsInfoNotification>(data, m_id_provider, m_evt_handler, type);
if (push_notification_data(std::move(notification), 0)) {
(dynamic_cast<UpdatedItemsInfoNotification*>(m_pop_notifications.back().get()))->add_type(type);
}
}
bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp)
{

View File

@ -169,7 +169,8 @@ public:
void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host);
void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host);
// Hint (did you know) notification
void push_hint_notification();
void push_hint_notification(bool open_next);
bool is_hint_notification_open();
void push_updated_item_info_notification(InfoItemType type);
// Close old notification ExportFinished.
void new_export_began(bool on_removable);
@ -498,13 +499,14 @@ private:
public:
UpdatedItemsInfoNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, InfoItemType info_item_type)
: PopNotification(n, id_provider, evt_handler)
, m_info_item_type(info_item_type)
{
//m_types_and_counts.emplace_back(info_item_type, 1);
}
void count_spaces() override;
void add_type(InfoItemType type);
protected:
void render_left_sign(ImGuiWrapper& imgui) override;
InfoItemType m_info_item_type;
std::vector<std::pair<InfoItemType, size_t>> m_types_and_counts;
};
// in HintNotification.hpp

View File

@ -37,7 +37,21 @@ void ObjectDataViewModelNode::init_container()
static constexpr char LayerRootIcon[] = "edit_layers_all";
static constexpr char LayerIcon[] = "edit_layers_some";
static constexpr char WarningIcon[] = "exclamation";
static constexpr char InfoIcon[] = "info";
static constexpr char InfoIcon[] = "objlist_info";
struct InfoItemAtributes {
std::string name;
std::string bmp_name;
};
const std::map<InfoItemType, InfoItemAtributes> INFO_ITEMS{
// info_item Type info_item Name info_item BitmapName
{ InfoItemType::CustomSupports, {L("Paint-on supports"), "fdm_supports" }, },
{ InfoItemType::CustomSeam, {L("Paint-on seam"), "seam" }, },
{ InfoItemType::MmuSegmentation, {L("Multimaterial painting"), "mmu_segmentation"}, },
{ InfoItemType::Sinking, {L("Sinking"), "support_blocker"}, },
{ InfoItemType::VariableLayerHeight, {L("Variable layer height"), "layers"}, },
};
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
const wxString& sub_obj_name,
@ -60,14 +74,10 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* pare
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType info_type) :
m_parent(parent),
m_type(itInfo),
m_extruder(wxEmptyString)
m_info_item_type(info_type),
m_extruder(wxEmptyString),
m_name(_(INFO_ITEMS.at(info_type).name))
{
m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") :
info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") :
info_type == InfoItemType::MmuSegmentation ? _L("Paint-on segmentation") :
info_type == InfoItemType::Sinking ? _L("Sinking") :
_L("Variable layer height");
m_info_item_type = info_type;
}
@ -307,7 +317,8 @@ ObjectDataViewModel::ObjectDataViewModel()
m_volume_bmps = MenuFactory::get_volume_bitmaps();
m_warning_bmp = create_scaled_bitmap(WarningIcon);
m_info_bmp = create_scaled_bitmap(InfoIcon);
for (auto item : INFO_ITEMS)
m_info_bmps[item.first] = create_scaled_bitmap(item.second.bmp_name);
}
ObjectDataViewModel::~ObjectDataViewModel()
@ -402,7 +413,7 @@ wxDataViewItem ObjectDataViewModel::AddInfoChild(const wxDataViewItem &parent_it
}
root->Insert(node, idx+1);
node->SetBitmap(m_info_bmp);
node->SetBitmap(m_info_bmps.at(info_type));
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
@ -1494,6 +1505,16 @@ void ObjectDataViewModel::GetAllChildren(const wxDataViewItem &parent, wxDataVie
}
}
bool ObjectDataViewModel::HasInfoItem(InfoItemType type) const
{
for (ObjectDataViewModelNode* obj_node : m_objects)
for (size_t j = 0; j < obj_node->GetChildCount(); j++)
if (obj_node->GetNthChild(j)->GetInfoItemType() == type)
return true;
return false;
}
ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
{
if (!item.IsOk())

Some files were not shown because too many files have changed in this diff Show More